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! ️