RSDL (RESTful Service Description Language, «мова опису RESTful сервісів») — це машино- й людино-читабельний XML опис HTTP вебзастосунків (зазвичай, вебсервісів типу REST).

Ця мова (розроблена Майклом ПастернакомПрофіль автора RSDL на Linkedin у процесі його роботи над RESTful API для oVirt) надає можливість описати модель ресурсів, які надає сервіс, взаємозв’язки між ними, та дії й параметри, які мають бути передані до виконуваних методів. Вона визначає чи треба передавати параметри, а також описує можливі варіації множин параметрів.

RSDL покликаний спростити повторне використання вебсервісів, які базуються на HTTP-архітектурі вебу. Він є платформо- та мово-незалежним і має на меті сприяння повторному використанню застосунків, окрім основного використання у веббраузерах, як людьми, так і машинами.

На відміну від WADL, він зосереджується на описі URI як автономних точок входу у застосунок, які можуть бути викликані різними способами, не потребує слідування через компоненти URI, щоб визначити структуру URI, та підтримує перевантаження параметрів URI/заголовків/тіла. Це робить його легкочитабельним для людей та простим для використання і людьми, й машинами.

Самоописуваний

RSDL представляє різні URI як автономні точки входу у застосунок. Слідуючи за URI ресурсів можна дізнатися які методи доступні для заданих ресурсів і як цими ресурси можна користуватися

Зрозумілий машинам

Кожен URI у RSDL містить усю необхідну інформацію для формування з нього HTTP запиту. Цю інформацію можна отримати із внутрішніх частин URI.

Зрозумілий людям

Кожен URI у RSDL містить атрибути "rel" та "description", які описують значення заданої операції над цим URI. Люди можуть дізнатися всі доступні операції для вказаної колекції/ресурсу, просто знайшовши різні дескриптори за тим самим URI.

Формат <?xml version="1.0" encoding="utf-8"?> <rsdl rel="rsdl" href="/api?rsdl"> <description /> <version revision="0" build="0" minor="0" major="0" /> <schema rel="schema" href="/api?schema"> <name>api.xsd</name> <description /> </schema> <general rel="*" href="/*"> <request> <headers> <header required="true|false"> <name /> <description /> <value /> </header> </headers> <url> <parameters_set> <parameter context="query|matrix" type="xs:string" required="true|false"> <name /> <value /> </parameter> </parameters_set> </url> </request> <name /> <description /> </general> <links> <link rel="get|..." href="/api/xxx"> <request> <http_method>GET|POST|PUT|DELETE|...</http_method> <headers> <header required="true|false"> <name /> <value /> </header> </headers> <url> <parameters_set> <parameter context="query|matrix" type="" required="true|false"> <name /> <value /> </parameter> </parameters_set> </url> <body> <type>...</type> <parameters_set> <parameter type="" required="true|false"> <name>FQ-name-to-parameter</name> </parameter> </parameters_set> </body> </request> <response> <type /> </response> </link> </links> </rsdl>

Компоненти

URI <links> <link rel="get|..." href="/api/xxx">

Запит <request> <http_method>GET|POST|PUT|DELETE|...</http_method> <headers> <header required="true|false"> <name></name> <value></value> </header> ... </headers> <url> <parameters_set> <parameter context="query|matrix" type="" required="true|false"> <name></name> <value></value> </parameter> ... </parameters_set> ... </url> <body> <type>...</type> <parameters_set> <parameter type="" required="true|false"> <name>FQ-name-to-parameter</name> </parameter> ... </parameters_set> ... </body> </request>

Відповідь <response> <type></type> ... </response>

Схема XML

<xs:element name="detailedLinks" type="DetailedLinks"/>

<xs:complexType name="DetailedLinks"> <xs:sequence> <xs:annotation> <xs:appinfo> <jaxb:property name="links"/> </xs:appinfo> </xs:annotation> <xs:element type="DetailedLink" name="link" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType>

<xs:element name="link" type="Link"/>

<xs:complexType name="Link"> <xs:attribute name="href" type="xs:string"/> <xs:attribute name="rel" type="xs:string"/> </xs:complexType>

<xs:element name="url" type="Url"/>

<xs:complexType name="Url"> <xs:sequence> <xs:element ref="parameters_set" maxOccurs="unbounded" minOccurs="0"> <xs:annotation> <xs:appinfo> <jaxb:property name="ParametersSets"/> </xs:appinfo> </xs:annotation> </xs:element> </xs:sequence> </xs:complexType>

<xs:element name="body" type="Body"/>

<xs:complexType name="Body"> <xs:sequence> <xs:element name="type" type="xs:string" minOccurs="1" maxOccurs="1"/> <xs:element ref="parameters_set" maxOccurs="unbounded" minOccurs="0"> <xs:annotation> <xs:appinfo> <jaxb:property name="ParametersSets"/> </xs:appinfo> </xs:annotation> </xs:element> </xs:sequence> <xs:attribute name="required" type="xs:boolean"> <xs:annotation> <xs:appinfo> <jaxb:property generateIsSetMethod="false"/> </xs:appinfo> </xs:annotation> </xs:attribute> </xs:complexType>

<xs:element name="request" type="Request"/>

<xs:complexType name="Request"> <xs:sequence> <xs:element name="http_method" type="HttpMethod" minOccurs="1" maxOccurs="1"/> <xs:element ref="headers" minOccurs="0" maxOccurs="1"/> <xs:element ref="url" minOccurs="0" maxOccurs="1"/> <xs:element ref="body" minOccurs="0" maxOccurs="1"/> </xs:sequence> </xs:complexType>

<xs:simpleType name="HttpMethod"> <xs:restriction base="xs:string"> <xs:enumeration value="GET"/> <xs:enumeration value="POST"/> <xs:enumeration value="PUT"/> <xs:enumeration value="DELETE"/> <xs:enumeration value="OPTIONS"/> </xs:restriction> </xs:simpleType>

<xs:element name="response" type="Response"/>

<xs:complexType name="Response"> <xs:sequence> <xs:element name="type" type="xs:string" minOccurs="1" maxOccurs="1"/> </xs:sequence> </xs:complexType>

<xs:element name="parameter" type="Parameter"/>

<xs:complexType name="Parameter"> <xs:complexContent> <xs:extension base="BaseResource"> <xs:sequence> <xs:element name="value" type="xs:string" minOccurs="1" maxOccurs="1"/> <xs:element ref="parameters_set" minOccurs="0" maxOccurs="1"/> </xs:sequence> <xs:attribute name="required" type="xs:boolean"> <xs:annotation> <xs:appinfo> <jaxb:property generateIsSetMethod="false"/> </xs:appinfo> </xs:annotation> </xs:attribute> <xs:attribute name="type" type="xs:string"/> <xs:attribute name="context" type="xs:string"/> </xs:extension> </xs:complexContent> </xs:complexType>

<xs:element name="header" type="Header"/>

<xs:complexType name="Header"> <xs:complexContent> <xs:extension base="BaseResource"> <xs:sequence> <xs:element name="value" type="xs:string" minOccurs="1" maxOccurs="1"/> </xs:sequence> <xs:attribute name="required" type="xs:boolean"> <xs:annotation> <xs:appinfo> <jaxb:property generateIsSetMethod="false"/> </xs:appinfo> </xs:annotation> </xs:attribute> </xs:extension> </xs:complexContent> </xs:complexType>

<xs:element name="headers" type="Headers"/>

<xs:complexType name="Headers"> <xs:sequence> <xs:element ref="header" maxOccurs="unbounded"> <xs:annotation> <xs:appinfo> <jaxb:property name="Headers"/> </xs:appinfo> </xs:annotation> </xs:element> </xs:sequence> </xs:complexType>

<xs:element name="parameters_set" type="ParametersSet"/>

<xs:complexType name="ParametersSet"> <xs:sequence> <xs:element ref="parameter" maxOccurs="unbounded" minOccurs="0"> <xs:annotation> <xs:appinfo> <jaxb:property name="Parameters"/> </xs:appinfo> </xs:annotation> </xs:element> </xs:sequence> </xs:complexType>

<xs:element name="schema" type="Schema"/>

<xs:complexType name="Schema"> <xs:complexContent> <xs:extension base="Link"> <xs:sequence> <xs:element name="name" type="xs:string" minOccurs="0" maxOccurs="1"/> <xs:element name="description" type="xs:string" minOccurs="0" maxOccurs="1"/> </xs:sequence> </xs:extension> </xs:complexContent> </xs:complexType>

<xs:element name="general_metadata" type="GeneralMetadata"/>

<xs:complexType name="GeneralMetadata"> <xs:complexContent> <xs:extension base="DetailedLink"> <xs:sequence> <xs:element name="name" type="xs:string" minOccurs="0" maxOccurs="1"/> <xs:element name="description" type="xs:string" minOccurs="0" maxOccurs="1"/> </xs:sequence> </xs:extension> </xs:complexContent> </xs:complexType>

<xs:element name="rsdl" type="RSDL"/>

<xs:complexType name="RSDL"> <xs:sequence> <xs:element name="description" type="xs:string" minOccurs="0"/> <xs:element type="Version" name="version" minOccurs="0" maxOccurs="1" /> <xs:element ref="schema" minOccurs="0" maxOccurs="1" /> <xs:element type="GeneralMetadata" name="general" minOccurs="0" maxOccurs="1"/> <xs:element type="DetailedLinks" name="links" minOccurs="0"/> </xs:sequence> <xs:attribute name="href" type="xs:string"/> <xs:attribute name="rel" type="xs:string"/> </xs:complexType>

Приклади

Перелік ресурсів <link rel="get" href="/api/clusters"> <request> <http_method>GET</http_method> <headers> <header required="false"> <name>Filter</name> <value>true|false</value> </header> </headers> <url> <parameters_set> <parameter context="query" type="xs:string" required="false"> <name>search</name> <value>search query</value> </parameter> <parameter context="matrix" type="xs:boolean" required="false"> <name>case_sensitive</name> <value>true|false</value> </parameter> <parameter context="matrix" type="xs:int" required="false"> <name>max</name> <value>max results</value> </parameter> </parameters_set> </url> <body/> </request> <response> <type>Clusters</type> </response> </link>

Одержати ресурс <link rel="get" href="/api/clusters/{cluster:id}"> <request> <http_method>GET</http_method> <headers> <header required="false"> <name>Filter</name> <value>true|false</value> </header> </headers> <body/> </request> <response> <type>Cluster</type> </response> </link>

Оновити ресурс <link rel="update" href="/api/clusters/{cluster:id}"> <request> <http_method>PUT</http_method> <headers> <header required="true"> <name>Content-Type</name> <value>application/xml|json</value> </header> <header required="false"> <name>Correlation-Id</name> <value>any string</value> </header> </headers> <body> <type>Cluster</type> <parameters_set> <parameter type="xs:string" required="false"> <name>cluster.name</name> </parameter> <parameter type="xs:string" required="false"> <name>cluster.description</name> </parameter> <parameter type="xs:string" required="false"> <name>cluster.cpu.id</name> </parameter> <parameter type="xs:int" required="false"> <name>cluster.version.major</name> </parameter> <parameter type="xs:int" required="false"> <name>cluster.version.minor</name> </parameter> <parameter type="xs:double" required="false"> <name>cluster.memory_policy.overcommit.percent</name> </parameter> <parameter type="xs:boolean" required="false"> <name>cluster.memory_policy.transparent_hugepages.enabled </name> </parameter> <parameter type="xs:string" required="false"> <name>cluster.scheduling_policy.policy</name> </parameter> <parameter type="xs:int" required="false"> <name>cluster.scheduling_policy.thresholds.low</name> </parameter> <parameter type="xs:int" required="false"> <name>cluster.scheduling_policy.thresholds.high</name> </parameter> <parameter type="xs:int" required="false"> <name>cluster.scheduling_policy.thresholds.duration</name> </parameter> <parameter type="xs:string" required="false"> <name>cluster.error_handling.on_error</name> </parameter> <parameter type="xs:boolean" required="false"> <name>cluster.virt_service</name> </parameter> <parameter type="xs:boolean" required="false"> <name>cluster.gluster_service</name> </parameter> <parameter type="xs:boolean" required="false"> <name>cluster.threads_as_cores</name> </parameter> <parameter type="xs:boolean" required="false">