["/greetings"
[
["/hello" (yada "Hello World!\n")]
["/goodbye" (yada "Goodbye!\n")]
]
]
All yada resources are built on data which can be published in a variety of formats. A popular format is Swagger, which allows APIs to be quickly documented. This is particularly useful when multiple teams of developers need to share their service documentation with others during development.
Swagger involves the creation of JSON-formatted specifications which, in the absence of libraries like yada, are hand-authored. There exist a variety of code generation libraries that can take hand-authored specifications and generate code in various programming languages. However, a key disadvantage with code-generation approaches like this is they do not support round-trip engineering, that is, the steady iterative co-evolution of the specification with the code.
Since Swagger covers both URI routing as well as resources, we must involve routing information in the set of resources we wish to publish. Currently, bidi is the only supported router, but it should be possible to support other data-driven routers such as Silk in future.
The first task is to create and publish the swagger specification for a set of resources.
The easiest way of creating a Swagger spec is by following these steps:
Creating a bidi route structure containing your yada handlers (remember a yada handler is a Ring handler). Remember, bidi is infinitely recursive, so you can group your resources however you like. Just use the vector-of-vectors syntax in place of a usual handler.
["/greetings"
[
["/hello" (yada "Hello World!\n")]
["/goodbye" (yada "Goodbye!\n")]
]
]
swaggered
The swaggered
function can be used to further wrap the route
structure.
This function takes 2 arguments. The first argument is simply the bidi routing tree containing your yada resources. The second argument is a 'base template' map which contains all the static data that should appear in the spec, such as the Swagger service meta-data. The data contained in both the routing tree and the resources themselves is used to construct the specification.
For example, let’s take the bidi routing tree below:
(require '[yada.swagger :refer [swaggered]])
["/api"
(swaggered
["/greetings"
[
["/hello" (yada "Hello World!\n")]
["/goodbye" (yada "Goodbye!\n")]
]
]
{:info {:title "Hello World!"
:version "1.0"
:description "A greetings service"}
:basePath "/api"}
)]
This declares a route that (partially) matches on the URI path /api
.
The second element of the route pair is a custom record created with
swaggered
which satisfies bidi’s Matched
protocol. This acts as a
sort of 'junction' which matches on the routes given in the second
argument. Critically, however, it also adds an additional sub-route,
/swagger.json
, which exposes the Swagger specification of the given
base template, routes and resources.
Therefore, to access the JSON swagger specification in the example
above, you would navigate to /api/swagger.json
. Also, use
/api/greetings/hello
and /api/greetings/goodbye
to access the
services.
The Swagger spec is merely a map that can be created with
yada.swagger/swagger-spec-resource
. Once you have this map, publish it
with yada
(you should know how to do this already. Hint: (yada m)
).
There is a function yada.swagger/swagger-spec-resource
that creates a
yada resource for you, and can optionally take a content-type to publish
the spec in HTML and EDN too.
This approach gives you more flexibility, since you aren’t tied to publishing your swagger spec in the same route structure as your API (you might want to publish it on another server perhaps).
Once you have published the Swagger specification you should use the Swagger UI to access it.
If you use the swaggered
convenience function, a Swagger UI will
automatically be hosted under the route. Use a single /
to redirect to
the UI for the Swagger specification of your routing tree. In the
example above, navigating to /api/
will bring up the Swagger UI
allowing you to browse and play with the API.
It is also possible to host your own Swagger UI and link it to your
published Swagger specifications. Just pass the url
query parameter to
the Swagger UI to indiciate the location of the yada-produced Swagger
specification you want to browse.
Advanced users: For an example of custom Swagger UI configuration see
dev/resources/swagger/phonebook-swagger.html
for an example.
Resources accept the following Swagger options. These options will also affect the Swagger UI.
:swagger/tags
for logical grouping of operations, e.g. ["users"]
:swagger/summary
and :swagger/description
for documentation of operations
These options can be provided at the resource’s top level and can be overriden per method.
In some sense Swagger definitions compete with REST as an architecture. Where REST encourages self-describing APIs, Swagger tends towards well-documented APIs. REST APIs are particularly well suited to fluid public APIs which can support gradual evolution and a diverse and potentially unknown set of clients. In contrast, Swagger APIs and suited to fixed private APIs inside a single organisation or between multiple collaborating parties.
Although the REST approach avoids publishing full API specifications up-front, preferring discovery over documentation, there are still many situations where it is useful to derive a data representation of an API.
One example is for API deployment to Amazon Web Services, where an API on the cloud can be created programmatically.
See IBM’s Watson Developer Cloud for a sophistated Swagger example.
Can you improve this documentation? These fine people already did:
Malcolm Sparks, Mike Fikes & Michiel BorkentEdit on GitHub
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close