In many companies, like mine, there are many projects and products. And products have web interfaces to somehow manipulate these products. In our case, these are unpretentious RESTful web services, and on top of them are even more unpretentious web pages with tins and buttons. All these web pages are so similar to each other that there was an idea to write a unified product that would ask the server about the supported services and get a full description of the parameters for these services so that you could draw those simple little forms. That is, web services should describe themselves, quite exhaustively, so that our client can build a GUI for them, and nothing would have to be done by hand. Just such a picture is googled by the request "REST":

Immediately found such a technology as
WADL - Web Application Description Language. But this is XML, I didn’t want to mess with it in javascript, python and perl. Its more lightweight JSON equivalent -
JSDL - JSON Service Description Language was chosen.
Service Requirements
')
It turned out that the JSDL (as well as the WADL) does not fit all the information needed to form full-fledged formulators, and a number of additional agreements with web services should be established:
- First you need to get a list of services, and how they are called. The concept of service (in terms of JSDL or WADL) here corresponds to the entity being manipulated (resource in REST terms). A service has a set of operations that JSDL describes. Therefore, there may be several services (and usually there are), and they can be combined into groups for convenience of display. Therefore, first of all, our client requests the
GET /service_groups
URL and gets a JSON of the form
[ { "description": "Manipulate resource1", "services": ["resource1"] }, { "description": "Manipulate resource2 and its statistics", "services": ["resource2", "resource2_stat"] } ]
- Next, you need to get JSDL for all these services. It can be done on request for each service, but for convenience, it was also implemented to get all the objects in one
GET /jsdls
. Get JSON view
[["resource1", {...object...}], ["resource2", {...object...}], ["resource2_stat", {...object...}]]
where object
is the JSDL description of the service (operations, their parameters, etc.).
- It would seem that all. But not all. Our client is just an html file that can be accessed from an arbitrary domain, or without a domain at all if we set the browser directly on it. Next, we enter the root URL of our RESTful API into the form, and requests are made there that are cross-domain. And we inevitably face security . If we could restrict ourselves to GET requests, it would be possible to use JSONP , but this would also impose additional requirements on the RESTful API itself.
Instead, the server must support the OPTIONS method, which few people know about and which is practically not used, although the browser implicitly makes such a request for cross-domain ajax calls. The RFC about this method is written in my opinion rather vague. In practice, the server should issue the Allow header for this request:
Allow: HEAD,GET,PUT,POST,DELETE,OPTIONS
In addition, for each request you need to send the type headers:
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: content-type,X-Requested-With
Access-Control-Allow-Methods: HEAD,GET,PUT,POST,DELETE,OPTIONS
Then the browser is satisfied.
Validating JSDL
Our client validates incoming JSON objects from the server in accordance with the JSDL scheme described using the
JSON Schema . We just took the
JSDL scheme , the
JSONa metascheme , and the first validator from the proposed ones,
this one . The metascheme is needed, because the parameter in JSDL is a schema and is described by a metasheme, which we have expanded a bit, as indicated below. I hope it is clear (for me personally, not always).
Extend JSDL
Unfortunately, using standard JSDL, it is still not possible to fully express our forms.
The parameter scheme lacked the following means of expression:
- The parameter needs a name. It must be set.
- The parameter is transmitted to the server in different ways:
- In the URL, after the resource:
api.com/resource1/paramvalue1/paramvalue2
- In the query string (if GET) or in the request body:
api.com/resource1?param1=value1¶m2=value2
- In the request body, in one piece, without forming a key-value pair. Specific case, but occurs
- For which parameters of the string type do you need textarea and which text input is enough?
To solve these problems, the JSDL parameter description scheme (that metascheme) had to be expanded as follows:
Now there is all the data to draw a request box and correctly send its contents to the service. The result is displayed on the page.
The project itself lies
on the githaba and can be used to implement a single web interface to the services in your company, for example.