Xodocs is a developer-first tool that generates clean, human-readable OpenAPI documentation for your Express backend application using Zod and Swagger under the hood.
It simplifies the documentation process by reducing the amount of boilerplate comments required, promoting schema reusability, and keeping your API definitions tightly coupled to your code β not scattered across YAML files or verbose decorators.
Swagger has become the de facto standard for documenting APIs, but maintaining Swagger annotations in complex projects often turns into a mess:
- Annotating every route with verbose comments or decorators
- Duplicating schema definitions across files
- Managing large Swagger configuration files manually
- Constantly syncing code and documentation
These issues lead to bloated, error-prone documentation that is painful to maintain.
Xodocs solves this by providing a clean, code-first documentation experience for Express applications.
β¨ Key features:
- βοΈ Use minimal, structured JSDoc-style route annotations
- π§ Automatically detects routes and methods
- π Seamlessly integrates with
zod-openapi - π Simple authentication configuration
- π Zero boilerplate OpenAPI generation
- π Keeps your documentation and code in sync
Install xodocs along with its peer dependency zod-openapi:
npm install xodocs zod zod-openapior with yarn:
yarn add xodocs zod zod-openapiAt the entry point of your Express app (e.g., index.ts or server.ts):
import 'zod-openapi/extend';This ensures that all Zod schemas are extended with the OpenAPI capabilities provided by zod-openapi.
import express from 'express';
import { generateOpenAPIDocs } from 'xodocs';
import { AuthResponse, UserParamsId } from './schemas';
const app = express();
generateOpenAPIDocs(app, {
info: {
title: 'Xodocs Sample',
description: 'This is the official API of "Xodocs Sample"',
},
schemas: {
AuthResponse,
UserParamsId,
},
auth: {
type: 'bearer',
in: 'header',
scheme: 'token',
},
baseURL: 'http://localhost:3000',
});| Property | Type | Description |
|---|---|---|
info |
Partial<InfoObject> |
OpenAPI info object (e.g., title, version, description) |
docsPath |
Partial<DocsPath> |
Override default UI/JSON documentation routes |
auth |
AuthConfig |
Optional global authentication configuration |
baseURL |
string |
Optional base URL of the express app. |
schemas |
Record<string, ZodType> |
Zod schemas used in route annotations (@response, @params) |
| Property | Type | Description | Default |
|---|---|---|---|
ui |
string |
Route where Swagger UI is served | "/docs" |
json |
string |
Route for raw OpenAPI JSON | "/docs/openapi.json" |
| Property | Type | Description | Notes |
|---|---|---|---|
type |
"bearer" | "apiKey" |
Type of authentication | Required |
name |
string |
Name of the header/query param (for apiKey) |
Required for apiKey |
in |
"header" | "query" |
Location of the apiKey parameter |
Required for apiKey |
scheme |
string |
Auth scheme (defaults to "bearer" for bearer auth) |
Optional |
description |
string |
Description of the auth mechanism | Optional |
Here's how you define routes with clean top-of-function comments:
export class AuthController {
// @public
// @route POST /login
// @summary Login a user
// @response 200: AuthResponse
// @tags Auth
static login = (_: any, res: any) => {
res.json({ token: 'abc123' });
};
// @route GET /user/{id}
// @summary Get user details
// @response 200: AuthResponse
// @params UserParamsId
// @tags Users
static user = (_: any, res: any) => {
res.json({ token: 'abc123' });
};
}π§ Xodocs will automatically read these annotations, match the method name, and link the referenced schemas from the config.
Using zod-openapi, your schemas should be defined like this:
import { z } from 'zod';
// Request Body Schema
export const AuthResponse = z.object({
token: z.string().openapi({
description: 'JWT token returned after successful login',
example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
}),
});
// Paramter Schema
export const UserParamsId = z.object({
id: z
.string()
.uuid()
.openapi({
param: {
name: 'id',
in: 'path',
},
example: 'f8b50a58-23f5-4f20-a08b-53f233e704a1',
description: 'The UUID of the user',
}),
page: z
.number()
.int()
.openapi({
param: {
name: 'page',
in: 'query',
},
example: 25,
description: 'Page',
}),
});Once configured, Xodocs generates:
- A beautiful Swagger UI at
/docs - A raw OpenAPI JSON spec at
/docs/openapi.json
These can be easily customized with the docsPath config option.
Configure authentication globally with the auth option:
auth: {
type: 'bearer',
in: 'header',
scheme: 'token',
description: 'JWT token authentication',
}Xodocs will automatically include this security scheme in the spec and apply it to all routes except those marked with @public.
We welcome contributions!
- Found a bug?
- Have a feature idea?
- Want to help make Xodocs better?
π Contribute here
Unlike traditional Swagger tools that rely on bloated decorators or out-of-sync YAML files, Xodocs embraces:
- π Simplicity
- π§© Zod-first validation and schema linking
- π§Ό Clean function-level documentation
- βοΈ Automated generation with no runtime overhead
Itβs the Swagger generation tool your Node.js projects actually deserve.
MIT License Β© Elijah Soladoye