In the previous articles, we went through:
- how to create a Rest API with @novice1/app
- how to validate request data with @novice1/validator-joi
Now we wish to use the API for ourself or give an access for other people to use. For that we are missing something of fundamental importance: documentation.
Let us be real, during my years as a developer, I never met anyone who liked writing documentation. That does not mean that it's not necessary to do so.
For a REST API, a schema of the API can be very useful and self explanatory. There are multiple schema specifications like OpenAPI and Postman. @novice1/api-doc-generator covers them both.
With @novice1/api-doc-generator, you can easily generate an OpenAPI and/or Postman schema from your application. That package is quite complete, covers all cases and has a reference sheet for its usage.
In this article we will see how to generate an OpenAPI schema with @novice1/api-doc-generator for a simple REST API.
Create the service
Let's install the dependencies
npm i @novice1/api-doc-generator yamljs
npm i --save-dev @types/yamljs
and create the service that will generate the documentation
src/services/openapi/generator.ts
import { OpenAPI } from '@novice1/api-doc-generator';
import { EXTERNAL_PORT, EXTERNAL_PROTOCOL, HOSTNAME } from '../../config/server';
export const openAPIGenerator = new OpenAPI()
.setTitle('API DOC')
.setHost(`${EXTERNAL_PROTOCOL}://${HOSTNAME}${EXTERNAL_PORT ? ':'+EXTERNAL_PORT : ''}`)
.setConsumes(['application/json'])
.setTags([
{
name: 'default',
externalDocs: { description: 'Find more info here', url: 'https://swagger.io/specification/' }
}
])
Access documentation
Using @novice1/app, the app provides metadata. Those are used to generate the REST API schema.
src/index.ts
import logger from '@novice1/logger';
import { app } from './app';
import { httpError, httpNotFound } from './middlewares/http';
import { PORT } from './config/server';
import { openAPIGenerator } from './services/openapi/generator';
// 404
app.use(httpNotFound);
// error
app.useError(httpError);
// start server
app.listen(PORT, () => {
logger.info('Application running on port', PORT)
/**
* Add app metadata to API documentation generator
*/
openAPIGenerator.add(app.meta)
})
Create a route that renders the schema:
src/routes/documentation.ts
import routing from '@novice1/routing';
import Joi from 'joi';
import YAML from 'yamljs';
import { openAPIGenerator } from '../services/openapi/generator';
export default routing().get({
path: '/documentation',
parameters: {
// query
query: Joi.object().keys({
json: Joi.boolean().default(false)
}),
// do not put this route in the documentation
undoc: true
}
}, (req, res) => {
// Get the JSON schema
const result = openAPIGenerator.result()
if (!req.query.json) {
// respond with a yaml schema
res.set('Content-Type', 'text/plain')
res.send(YAML.stringify(result, 10, 2))
} else {
// respond with the JSON schema
res.json(result)
}
})
And register it with the other routers:
src/routes/index.ts
import corsOptions from './cors-options';
import documentation from './documentation';
import helloWorld from './hello-world';
import items from './items';
// all routers
export default [
corsOptions,
documentation,
helloWorld,
items
]
Now, we run the application to see if we have access to the schema at http://localhost:8080/documentation.
For development:
npm run dev
For production:
npm run lint
npm run build
npm start
It should render the schema in yaml format. To get the json format, we can set the following query string in the url ?json=true
.
The schema can be copied and pasted to the Swagger Editor to get a UI to test your API.
Render swagger UI
If you want your API to not just serve the schema but also the UI, you can install the following dependencies:
npm i swagger-ui-express
npm i --save-dev @types/swagger-ui-express
and change the route that serves the documentation like so:
src/routes/documentation.ts
import routing, { RequestHandler } from '@novice1/routing';
import Joi from 'joi';
import YAML from 'yamljs';
import swaggerUi from 'swagger-ui-express';
import { openAPIGenerator } from '../services/openapi/generator';
const swaggerUIController: RequestHandler = (req, res, next) => {
const swaggerDocument = openAPIGenerator.result()
return swaggerUi.setup(swaggerDocument)(req, res, next)
}
const swaggerRouter = routing()
.get({
path: '/',
parameters: {
undoc: true
},
},
swaggerUIController)
.get({
path: '/schema',
parameters: {
query: Joi.object().keys({
json: Joi.boolean().default(false),
}).options({ allowUnknown: true, stripUnknown: false }),
undoc: true
}
}, (req, res) => {
const result = openAPIGenerator.result();
if (!req.query.json) {
res.set('Content-Type', 'text/plain');
res.send(YAML.stringify(result, 10, 2));
} else {
res.json(result);
}
});
export default routing().use('/documentation',
swaggerUi.serve,
swaggerRouter
);
That way, your API will serve the UI (html) at /documentation
and the schema (yaml/json) at /documentation/schema
.
As I said earlier, @novice1/api-doc-generator is quite complete. We can define everything there is in OpenAPI Specification 3.0.3 and Postman Collection Format v2.1.0 so it would be impossible to cover it all in one article. As of today, the best way to learn @novice1/api-doc-generator is by reading the package's documentation that you can find here. It lists and defines the classes, interfaces, enumerations and gives a few examples on how to define authorizations, responses, etc ...
I would gladly talk about more aspects of the package in future articles if it is requested in the comment section.
What is sure is that we will continue using and updating our REST API documentation in the next article that will be about Authorizations with @novice1/app.
References
You can see the result of what we have done till now right here on Github.
Top comments (0)