Swagger UI
on this page
What is Swagger UI
Swagger UI is an open-source tool that allows you to visualize and interact with APIs (Application Programming Interfaces) defined using the OpenAPI Specification
(formerly known as Swagger Specification). The OpenAPI Specification is a standardized format for describing and documenting APIs, including endpoints, request/response data formats, authentication methods, and more.
OpenAPI document
In order to generate a swagger UI for our API, we first need an OpenAPI document. Luckily this is very easy to do with ts-rest.
npm install @ts-rest/open-api
Now we can use generateOpenApi
function provided by this ts-rest library to generate an OpenAPI document for our contract.
import { generateOpenApi } from '@ts-rest/open-api';
const ApiContract = contract.router({
posts : PostContract,
user : UserContract
});
const openApiDocument = generateOpenApi(Contracts.ApiContract, {
info: {
title: 'API',
version: '1.0.0',
},
});
Note that we have combined both of our contracts into a single contract. This is similar to how we can nest routers in express.
Generating the Swagger UI
For this series, since we are using express, we will use the swagger-ui-express
library to generate and serve our UI using our server.
npm i swagger-ui-express
Now pass the generated openAPI document to swagger ui.
import * as swaggerUi from 'swagger-ui-express';
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(openApiDocument));
app.listen(...../*same as before*/
Now simply open your browser, and navigate to http://localhost:<port>/api-docs
and see the UI for your api live. You can interact with it, and test it, all from the browser.
Caveat:
Thereβs a slight difference in opinion about the way the authorization header is handled in swagger ui, and the way that the ts-rest generates the OpenAPI document. For more information on the issue refer to this github issue.
To fix the issue, you can simply patch the OpenAPI document beforehand. Heres a simple function for the patch:
import { generateOpenApi } from '@ts-rest/open-api';
export function patchOpenAPIDocument(openApiDocument : ReturnType<typeof generateOpenApi>){
openApiDocument.components = openApiDocument.components || {};
openApiDocument.components.securitySchemes = openApiDocument.components.securitySchemes || {};
openApiDocument.components.securitySchemes.auth = {
type : 'apiKey',
in : 'header',
name : 'authorization'
}
openApiDocument.security = openApiDocument.security || [];
openApiDocument.security.push({
auth : []
});
Object.entries(openApiDocument.paths).map(([endpoint, methods]) => {
Object.entries(methods).map(([method, implementation] : [method : any, implementation : any]) => {
implementation.parameters = implementation.parameters.filter((obj : any) => !(obj.name === "authorization" && obj.in === "header"))
});
});
}