Have you ever wanted to have a swagger documentation for your express API based on annotations? I have. And unfortunately didn’t find any way of doing it without having to manually create a swagger.json
file. My wish was simple as this: I want to have a clean express app with multiple endpoints and I want to keep swagger documentation for every endpoint close to the endpoint implementation, not in a separate file.
Maybe I’m just lacking some google skills, but I decided that it’d be much easier for me to create such a tool. And here it is: mgr-swagger-express
Getting started
Example here will be written in TypeScript, but the same can be done in Javascript project.
So imagine a classical express app:
Here we have a resource “Book” and a some basic CRUD endpoints. The question is “How would you add a cool Swagger documentation to this API?” I really wanted to do it using annotations in order to keep every endpoint documentation close to the endpoint itself.
This is what you’ll be able to do with mgr-swagger-express:
index.ts
:
BookService.ts
:
There is a bot more code, but now we have all swagger documentation laying near the endpoint itself.
Let’s see what’s happening here:
- In index file, we create out express app, as usual. Also we have to initialise all middlewares (the bodyParser being the most important).
- After this we call the
SET_EXPRESS_APP
to set the app object globally. This way mgr-swagger-express will be able to attach handlers to endpoints - Only after this we can import the service with annotations. It does not have to be a class, it could be just functions.
- Then we create an instance of our service (or call an init function in case of not using classes)
- And we generate swagger config based on all of the annotations we have in the project and attach it to our app using swagger-ui-express package
Inside the service, there are multiple things going on, but let’s stop on a couple of them only. Everything else you can easily find in the mgr-swagger-express repo:
- In the constructor we call
addSwaggerDefinition
function. It registers a swagger model with a given name. in our case we defineBookDefinition
under a Book name in order to reference it afterwards by#/definitions/Book
- All handlers are annotated with
@GET @POST @PUT @DELETE
commands. All of them are taking in arguments an object of typeSwaggerEndpoint
:
path: string; auth?: string; description?: string; tags?: string[]; parameters?: SwaggerURLParameter[]; query?: SwaggerQueryParameter; body?: SwaggerBodyParameter; success?: SwaggerSuccessResponse;
It’s basically the classical swagger endpoint definition object, nothing special, except for the auth field, but I’ll come back to it in the future
All handlers should have the following signature:
(args: object, context: Context) => Promise<any>
The args object contains all parameters pathed to your endpoint. It can be URL parameters (like
book_id
in our example), query parameters or even body value.
The context object is used for handling authentication and security, but again, about it later.
Conclusion
Now we have a simple CRUD express API annotated with Swagger and a beautiful swagger UI, where all Swagger definitions are laying nearby the endpoint implementation. As usual — always glad to have any feedback! ?
somebody4
It would be really nice, if you could create couple VS Code extensions for the project.
First one is to do an API call directly for VSC based on an endpoint definition and display results of the call. I think, you could reuse swagger UI in popup window.
Second, generate an endpoint definition, based on a method signature. Should be quite easy.
And maybe add some kind of tree-based API navigator, as a nice helper for developers to see everything API.
Mgrin Автор
I never thought about VSCode extension for this thanks! Will think about it.
For the generation of swagger endpoint definition based on a function signature — it's not that easy. I wanted to to this in the beginning but then ended up with the existing solution. So now instead of getting SwaggerEndpointDefinition from signature (which should be edited to allow some additional information like shape of the body object, parameters in URL or query, etc etc etc) this definition is done manually in JSON and then your method signature looks almost like in GraphQL: list of arguments coming from any source (body, url, query) and a context (for auth flow) and a request (not implemented yet, will be implemented in future as I need it now for my projects)
Tree-based API navigator — cool idea as well. Will think about VSCode extension fo this, thanks :)
somebody4
Something like «document this» extension has pretty much everything you need, just add a little different formatting.