Last checked with Wasp 0.24, swagger-jsdoc 6, and swagger-ui-express 5.
This guide depends on external libraries or services, so it may become outdated over time. We do our best to keep it up to date, but make sure to check their documentation for any changes.Swagger UI
This guide shows you how to add Swagger UI documentation to your Wasp APIs, making it easy to explore and test your endpoints.
Setting up Swagger UIโ
1. Install dependenciesโ
Install the required packages:
npm install swagger-jsdoc swagger-ui-express
npm install --save-dev @types/swagger-jsdoc @types/swagger-ui-express
2. Configure the API namespace in main.wasp.tsโ
Add an API namespace for the Swagger UI endpoint:
import { api, apiNamespace, app } from "@wasp.sh/spec"
import { getStatus } from "./src/apis" with { type: "ref" }
import { swaggerMiddleware } from "./src/swagger-ui" with { type: "ref" }
export default app({
name: "MyApp",
wasp: { version: "^0.24.0" },
title: "my-app",
head: ["<link rel='icon' href='/favicon.ico' />"],
spec: [
apiNamespace("/api-docs", { middlewareConfigFn: swaggerMiddleware }),
api("GET", "/status", getStatus, { auth: false }),
],
})
3. Create the spec generator scriptโ
Because swagger-jsdoc scans source files at runtime and src/ is not available in the production Docker image, you need to pre-generate the spec as a TypeScript module that gets bundled with the server.
Create scripts/generate-swagger.js:
import swaggerJsdoc from "swagger-jsdoc";
import { writeFileSync } from "fs";
const spec = swaggerJsdoc({
definition: {
openapi: "3.0.0",
info: {
title: "My API",
version: "1.0.0",
description: "API documentation for my Wasp application",
contact: {
name: "API Support",
url: "https://example.com",
email: "support@example.com",
},
},
components: {
securitySchemes: {
bearerAuth: {
type: "http",
scheme: "bearer",
bearerFormat: "JWT",
description: "Enter your JWT token in the format: Bearer {token}",
},
},
},
security: [{ bearerAuth: [] }],
},
apis: ["./src/**/*.ts", "!./src/swaggerSpec.ts"],
});
writeFileSync(
"./src/swaggerSpec.ts",
`const swaggerSpec = ${JSON.stringify(spec, null, 2)} as const;\nexport default swaggerSpec;\n`,
);
console.log("swaggerSpec.ts generated");
Run this script whenever you add or change JSDoc annotations:
node scripts/generate-swagger.js
This generates src/swaggerSpec.ts, which gets bundled into the server and works in both dev and production.
You may want to add src/swaggerSpec.ts to your .gitignore since it's a generated file.
4. Create the Swagger middlewareโ
Create the Swagger UI middleware that serves the pre-generated spec:
- JavaScript
- TypeScript
import * as express from "express";
import helmet from "helmet";
import swaggerUi from "swagger-ui-express";
import { env, MiddlewareConfigFn } from "wasp/server";
import baseSwaggerDoc from "./swaggerSpec";
const swaggerDoc = {
...baseSwaggerDoc,
servers: [{ url: env.WASP_SERVER_URL, description: "API server" }],
};
export const swaggerMiddleware = (middlewareConfig) => {
middlewareConfig.delete("helmet");
middlewareConfig.set(
"helmet",
helmet({
contentSecurityPolicy: false,
hsts: false,
}),
);
swaggerUi.serve.forEach((handler, i) => {
middlewareConfig.set(`swaggerServe${i}`, handler);
});
middlewareConfig.set("swaggerSetup", (req, res, next) => {
return swaggerUi.setup(swaggerDoc, {
explorer: true,
customCss: ".swagger-ui .topbar { display: none }",
swaggerOptions: {
persistAuthorization: true,
url: "/api-docs/swagger.json",
},
})(req, res, next);
});
return middlewareConfig;
};
import * as express from "express";
import helmet from "helmet";
import swaggerUi from "swagger-ui-express";
import { env, MiddlewareConfigFn } from "wasp/server";
import baseSwaggerDoc from "./swaggerSpec";
const swaggerDoc = {
...baseSwaggerDoc,
servers: [{ url: env.WASP_SERVER_URL, description: "API server" }],
};
export const swaggerMiddleware: MiddlewareConfigFn = (middlewareConfig) => {
middlewareConfig.delete("helmet");
middlewareConfig.set(
"helmet",
helmet({
contentSecurityPolicy: false,
hsts: false,
}),
);
swaggerUi.serve.forEach((handler, i) => {
middlewareConfig.set(`swaggerServe${i}`, handler);
});
middlewareConfig.set(
"swaggerSetup",
(
req: express.Request,
res: express.Response,
next: express.NextFunction,
) => {
return swaggerUi.setup(swaggerDoc, {
explorer: true,
customCss: ".swagger-ui .topbar { display: none }",
swaggerOptions: {
persistAuthorization: true,
url: "/api-docs/swagger.json",
},
})(req, res, next);
},
);
return middlewareConfig;
};
5. Document your APIsโ
Add JSDoc comments with Swagger annotations above your API definitions:
- JavaScript
- TypeScript
import { GetStatus } from "wasp/server/api";
/**
* @swagger
* /status:
* get:
* summary: Get API status
* description: Returns the current status of the API
* tags:
* - Status
* security:
* - bearerAuth: []
* responses:
* 200:
* description: Successful response
* content:
* application/json:
* schema:
* type: object
* properties:
* message:
* type: string
* 401:
* description: Unauthorized
* 500:
* description: Server error
*/
export const getStatus = async (req, res) => {
return res.json({ message: "OK" });
};
import { GetStatus } from "wasp/server/api";
/**
* @swagger
* /status:
* get:
* summary: Get API status
* description: Returns the current status of the API
* tags:
* - Status
* security:
* - bearerAuth: []
* responses:
* 200:
* description: Successful response
* content:
* application/json:
* schema:
* type: object
* properties:
* message:
* type: string
* 401:
* description: Unauthorized
* 500:
* description: Server error
*/
export const getStatus: GetStatus = async (req, res) => {
return res.json({ message: "OK" });
};
6. Access the documentationโ
Start your Wasp application and navigate to http://localhost:3001/api-docs to see your API documentation.
Documenting Different Request Typesโ
POST Request with Bodyโ
/**
* @swagger
* /users:
* post:
* summary: Create a new user
* tags:
* - Users
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* required:
* - email
* - password
* properties:
* email:
* type: string
* format: email
* password:
* type: string
* minLength: 8
* responses:
* 201:
* description: User created successfully
* 400:
* description: Invalid input
*/
Path Parametersโ
/**
* @swagger
* /users/{id}:
* get:
* summary: Get user by ID
* tags:
* - Users
* parameters:
* - in: path
* name: id
* required: true
* schema:
* type: string
* description: User ID
* responses:
* 200:
* description: User found
* 404:
* description: User not found
*/
Query Parametersโ
/**
* @swagger
* /users:
* get:
* summary: List users
* tags:
* - Users
* parameters:
* - in: query
* name: page
* schema:
* type: integer
* default: 1
* description: Page number
* - in: query
* name: limit
* schema:
* type: integer
* default: 10
* description: Items per page
* responses:
* 200:
* description: List of users
*/
Customizationโ
Custom Stylingโ
You can customize the Swagger UI appearance:
- JavaScript
- TypeScript
swaggerUi.setup(swaggerDoc, {
customCss: `
.swagger-ui .topbar { display: none }
.swagger-ui .info { margin: 20px 0 }
`,
customSiteTitle: "My API Documentation",
customfavIcon: "/favicon.ico",
});
swaggerUi.setup(swaggerDoc, {
customCss: `
.swagger-ui .topbar { display: none }
.swagger-ui .info { margin: 20px 0 }
`,
customSiteTitle: "My API Documentation",
customfavIcon: "/favicon.ico",
});
Group APIs with Tagsโ
Use tags to organize your endpoints. Add a tags array to the definition in scripts/generate-swagger.js:
- JavaScript
- TypeScript
const spec = swaggerJsdoc({
definition: {
// ... other config
tags: [
{ name: "Users", description: "User management endpoints" },
{ name: "Posts", description: "Blog post endpoints" },
{ name: "Auth", description: "Authentication endpoints" },
],
},
apis: ["./src/**/*.ts", "!./src/swaggerSpec.ts"],
});
const spec = swaggerJsdoc({
definition: {
// ... other config
tags: [
{ name: "Users", description: "User management endpoints" },
{ name: "Posts", description: "Blog post endpoints" },
{ name: "Auth", description: "Authentication endpoints" },
],
},
apis: ["./src/**/*.ts", "!./src/swaggerSpec.ts"],
});
For more options, see the swagger-jsdoc documentation and swagger-ui-express documentation.