API Documentation (Swagger/OpenAPI)
JifiJs includes an automatic API documentation system using OpenAPI 3.1.0 specification and Swagger UI for interactive exploration.
Featuresβ
- π OpenAPI 3.1.0 - Latest OpenAPI specification
- π¨ Swagger UI - Interactive API explorer
- π Auto-Generation - Build from route documentation files
- π Security Schemes - API Key and JWT Bearer authentication
- π·οΈ Tagged Routes - Organized by functionality
- π§ͺ Try It Out - Test endpoints directly from docs
- πΎ Persistent Auth - Remember authentication between requests
- β‘ Request Duration - Display response times
Accessing the Documentationβ
Once your server is running, access the API documentation at:
http://localhost:3000/api-docs
Production URL:
{YOUR_APP_URL}/api-docs
Swagger UI Featuresβ
Interactive Interfaceβ
The Swagger UI provides:
- Endpoint List: All available API endpoints organized by tags
- Request Builder: Form-based request creation
- Response Viewer: JSON-formatted responses with syntax highlighting
- Authentication: Built-in support for API keys and JWT tokens
- Schema Viewer: Request/response data structures
- Example Values: Pre-filled example data for testing
Try It Outβ
- Click on any endpoint
- Click "Try it out" button
- Fill in required parameters
- Click "Execute"
- View the response
Authentication in Swaggerβ
API Key Authenticationβ
All endpoints require an API key:
- Click "Authorize" button at the top
- Enter your API key in
x-api-keyfield - Click "Authorize"
- Click "Close"
Now all requests will include the API key header.
JWT Bearer Authenticationβ
For authenticated endpoints:
- Login via
/auth/loginendpoint - Copy the
access_tokenfrom response - Click "Authorize" button
- Paste token in
bearerAuthfield (without "Bearer" prefix) - Click "Authorize"
All authenticated requests will now include the JWT token.
OpenAPI Document Structureβ
Base Configurationβ
The OpenAPI document is automatically generated with:
{
openapi: '3.1.0',
info: {
title: 'API BASE',
version: '1.0.0',
description: "API de base pour la gestion de l'authentification et des logs.",
license: {
name: 'MIT',
url: 'https://spdx.org/licenses/MIT.html'
},
contact: {
name: 'Mr NJIFANDA',
url: 'https://njifanda.com',
email: 'contact@njifanda.com'
}
},
servers: [
{
url: '{APP_URL}{ROUTE_PREFIX}',
description: 'API Server (Production/Development)'
}
]
}
Security Schemesβ
Two authentication methods are defined:
1. API Key (x-api-key)β
apiKeyAuth:
type: apiKey
in: header
name: x-api-key
description: API key required for all endpoints
2. Bearer Token (JWT)β
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
description: JWT token for authenticated endpoints
Standard Response Formatsβ
All endpoints follow standardized response structures:
Success Response (200)β
{
"error": false,
"message": "Operation successful",
"data": { /* response data */ }
}
Created Response (201)β
{
"error": false,
"message": "Resource created",
"data": { /* created resource */ }
}
Error Responsesβ
Bad Request (400):
{
"error": true,
"message": "Bad request"
}
Unauthorized (401):
{
"error": true,
"message": "Unauthorized"
}
Forbidden (403):
{
"error": true,
"message": "Forbidden"
}
Not Found (404):
{
"error": true,
"message": "Resource not found"
}
Validation Error (422):
{
"error": true,
"message": "Validation failed",
"errors": [
{
"field": "email",
"message": "email must be a valid email"
}
]
}
Server Error (500):
{
"error": true,
"message": "Internal server error"
}
Building Documentationβ
Automatic Buildβ
The OpenAPI document is automatically generated from route documentation files:
npm run docs:build
What it does:
- Scans
docs/routes/directory recursively - Finds all
*.doc.tsfiles - Merges paths, schemas, and tags
- Generates
docs/openapi.json
Watch Modeβ
Auto-rebuild on changes:
npm run docs:watch
Outputβ
Generated file: docs/openapi.json
β
OpenAPI document generated successfully!
Output: /path/to/docs/openapi.json
Paths: 25
Tags: 5
Schemas: 12
Creating Route Documentationβ
File Structureβ
Create documentation files in docs/routes/:
docs/routes/
βββ auth.doc.ts # Authentication routes
βββ admin-user.doc.ts # Admin user routes
βββ admin-logs.doc.ts # Admin log routes
βββ app-user.doc.ts # User routes
βββ app-upload.doc.ts # Upload routes
βββ your-resource.doc.ts # Your custom routes
Documentation Templateβ
/**
* OpenAPI Documentation for Product routes
* Corresponds to: routes/app/product.route.ts
*/
import OpenAPIHelper from '../../utils/helpers/openapi.helper';
import { RouteDocumentation } from '../../src/types/openapi.types';
export const documentation: RouteDocumentation = OpenAPIHelper.createRouteDoc(
// Paths
OpenAPIHelper.mergePaths(
// GET /product - List all products
OpenAPIHelper.GET('/product', {
tags: ['Product'],
summary: 'List all products',
description: 'Get paginated list of products',
operationId: 'listProducts',
security: OpenAPIHelper.security.both, // API Key + JWT
parameters: [
{
name: 'page',
in: 'query',
description: 'Page number',
schema: { type: 'integer', default: 1 }
},
{
name: 'limit',
in: 'query',
description: 'Items per page',
schema: { type: 'integer', default: 20 }
}
],
responses: {
'200': OpenAPIHelper.responses.Success,
'401': OpenAPIHelper.responses.Unauthorized,
}
}),
// GET /product/:id - Get single product
OpenAPIHelper.GET('/product/{id}', {
tags: ['Product'],
summary: 'Get product by ID',
description: 'Retrieve a single product by ID',
operationId: 'getProduct',
security: OpenAPIHelper.security.both,
parameters: [
{
name: 'id',
in: 'path',
required: true,
description: 'Product ID',
schema: { type: 'string' }
}
],
responses: {
'200': OpenAPIHelper.responses.Success,
'404': OpenAPIHelper.responses.NotFound,
}
}),
// POST /product - Create product
OpenAPIHelper.POST('/product', {
tags: ['Product'],
summary: 'Create new product',
description: 'Create a new product',
operationId: 'createProduct',
security: OpenAPIHelper.security.both,
requestBody: {
required: true,
content: {
'application/json': {
schema: {
type: 'object',
required: ['name', 'price'],
properties: {
name: {
type: 'string',
example: 'Product Name'
},
description: {
type: 'string',
example: 'Product description'
},
price: {
type: 'number',
example: 99.99
},
category: {
type: 'string',
example: 'Electronics'
},
}
}
}
}
},
responses: {
'201': OpenAPIHelper.responses.Created,
'422': OpenAPIHelper.responses.ValidationError,
}
}),
// PUT /product/:id - Update product
OpenAPIHelper.PUT('/product/{id}', {
tags: ['Product'],
summary: 'Update product',
description: 'Update an existing product',
operationId: 'updateProduct',
security: OpenAPIHelper.security.both,
parameters: [
{
name: 'id',
in: 'path',
required: true,
description: 'Product ID',
schema: { type: 'string' }
}
],
requestBody: {
required: true,
content: {
'application/json': {
schema: {
type: 'object',
properties: {
name: { type: 'string' },
description: { type: 'string' },
price: { type: 'number' },
category: { type: 'string' },
}
}
}
}
},
responses: {
'200': OpenAPIHelper.responses.Success,
'404': OpenAPIHelper.responses.NotFound,
'422': OpenAPIHelper.responses.ValidationError,
}
}),
// DELETE /product/:id - Delete product
OpenAPIHelper.DELETE('/product/{id}', {
tags: ['Product'],
summary: 'Delete product',
description: 'Soft delete a product',
operationId: 'deleteProduct',
security: OpenAPIHelper.security.both,
parameters: [
{
name: 'id',
in: 'path',
required: true,
description: 'Product ID',
schema: { type: 'string' }
}
],
responses: {
'200': OpenAPIHelper.responses.Success,
'404': OpenAPIHelper.responses.NotFound,
}
})
),
// Components (optional) - shared schemas
{
schemas: {
Product: {
type: 'object',
properties: {
_id: { type: 'string', example: '65abc123...' },
name: { type: 'string', example: 'Product Name' },
description: { type: 'string', example: 'Product description' },
price: { type: 'number', example: 99.99 },
category: { type: 'string', example: 'Electronics' },
created_at: { type: 'string', format: 'date-time' },
updated_at: { type: 'string', format: 'date-time' },
}
}
}
},
// Tags
[
{
name: 'Product',
description: 'Product management endpoints'
}
]
);
OpenAPIHelper Methodsβ
The OpenAPIHelper utility provides convenient methods:
HTTP Methodsβ
// GET endpoint
OpenAPIHelper.GET(path, config)
// POST endpoint
OpenAPIHelper.POST(path, config)
// PUT endpoint
OpenAPIHelper.PUT(path, config)
// DELETE endpoint
OpenAPIHelper.DELETE(path, config)
// PATCH endpoint
OpenAPIHelper.PATCH(path, config)
Security Presetsβ
// API Key only
security: OpenAPIHelper.security.apiKey
// JWT Bearer only
security: OpenAPIHelper.security.bearer
// Both API Key AND Bearer token required
security: OpenAPIHelper.security.both
// No authentication
security: []
Standard Responsesβ
OpenAPIHelper.responses.Success // 200
OpenAPIHelper.responses.Created // 201
OpenAPIHelper.responses.BadRequest // 400
OpenAPIHelper.responses.Unauthorized // 401
OpenAPIHelper.responses.Forbidden // 403
OpenAPIHelper.responses.NotFound // 404
OpenAPIHelper.responses.ValidationError // 422
OpenAPIHelper.responses.ServerError // 500
Merge Multiple Pathsβ
OpenAPIHelper.mergePaths(
path1,
path2,
path3,
// ...
)
Create Complete Route Docβ
OpenAPIHelper.createRouteDoc(
paths, // Merged paths object
components, // Optional schemas/responses
tags // Array of tag objects
)
Customizing Swagger UIβ
Configurationβ
Edit docs/swagger.ts:
import { Express } from 'express';
import swaggerUi from 'swagger-ui-express';
import * as swaggerDocument from './openapi.json';
export default function setupSwagger(app: Express): void {
app.use(
'/api-docs',
swaggerUi.serve,
swaggerUi.setup(swaggerDocument, {
explorer: true,
customCss: '.swagger-ui .topbar { display: none }',
customSiteTitle: 'API Documentation',
swaggerOptions: {
persistAuthorization: true,
displayRequestDuration: true,
filter: true,
tryItOutEnabled: true,
},
})
);
}
Available Optionsβ
| Option | Description | Default |
|---|---|---|
explorer | Enable search/filter | true |
customCss | Custom CSS styling | Hides topbar |
customSiteTitle | Browser tab title | 'API Documentation' |
persistAuthorization | Remember auth tokens | true |
displayRequestDuration | Show response time | true |
filter | Enable endpoint filtering | true |
tryItOutEnabled | Enable "Try it out" | true |
Custom Stylingβ
Add custom CSS:
customCss: `
.swagger-ui .topbar { display: none }
.swagger-ui .info { margin: 50px 0 }
.swagger-ui .scheme-container { padding: 30px 0 }
`
Change Routeβ
Change the documentation URL:
app.use(
'/docs', // Changed from /api-docs
swaggerUi.serve,
swaggerUi.setup(swaggerDocument, options)
);
Updating Base Infoβ
Edit docs/build.ts:
const baseDocument: OpenAPIDocument = {
openapi: '3.1.0',
info: {
title: 'Your API Name', // Change title
version: '2.0.0', // Update version
description: 'Your API description',
license: {
name: 'MIT',
url: 'https://spdx.org/licenses/MIT.html',
},
contact: {
name: 'Your Name',
url: 'https://yourwebsite.com',
email: 'contact@yourwebsite.com',
},
},
servers: [
{
url: configs.getUrl() + configs.getPrefixRoutes(),
description: `${configs.getName()} - API`,
},
],
// ...
};
Tags and Organizationβ
Organize Endpoints by Tagsβ
Tags group related endpoints together:
tags: ['Authentication'] // Auth endpoints
tags: ['User'] // User management
tags: ['Product'] // Product CRUD
tags: ['Admin'] // Admin operations
tags: ['Upload'] // File uploads
Tag Descriptionsβ
Add tag metadata:
[
{
name: 'Authentication',
description: 'Authentication and authorization endpoints'
},
{
name: 'User',
description: 'User profile management'
},
{
name: 'Product',
description: 'Product CRUD operations'
},
]
Best Practicesβ
1. Descriptive Operation IDsβ
Use unique, descriptive operation IDs:
operationId: 'listProducts' // β
Good
operationId: 'getProducts' // β Ambiguous
operationId: 'op1' // β Bad
2. Complete Examplesβ
Provide realistic example values:
properties: {
email: {
type: 'string',
format: 'email',
example: 'user@example.com' // β
Good example
},
price: {
type: 'number',
example: 99.99 // β
Realistic value
}
}
3. Required Fieldsβ
Always specify required fields:
schema: {
type: 'object',
required: ['name', 'email'], // β
Explicit requirements
properties: { /* ... */ }
}
4. Response Documentationβ
Document all possible responses:
responses: {
'200': OpenAPIHelper.responses.Success,
'400': OpenAPIHelper.responses.BadRequest,
'401': OpenAPIHelper.responses.Unauthorized,
'404': OpenAPIHelper.responses.NotFound,
'422': OpenAPIHelper.responses.ValidationError,
}
5. Parameter Descriptionsβ
Describe all parameters:
parameters: [
{
name: 'page',
in: 'query',
description: 'Page number for pagination (1-based)', // β
schema: { type: 'integer', default: 1, minimum: 1 }
}
]
6. Use Shared Schemasβ
Define reusable schemas in components:
components: {
schemas: {
Product: { /* schema */ },
User: { /* schema */ },
}
}
// Reference in responses
responses: {
'200': {
content: {
'application/json': {
schema: { $ref: '#/components/schemas/Product' }
}
}
}
}
Troubleshootingβ
Documentation Not Updatingβ
Problem: Changes not reflected in Swagger UI
Solution:
- Rebuild the OpenAPI document:
npm run docs:build - Restart the server:
npm run dev - Clear browser cache (Ctrl+Shift+R)
"No documentation export found"β
Problem: Warning when building docs
Solution:
Ensure your .doc.ts file exports documentation:
export const documentation: RouteDocumentation = /* ... */
Endpoints Not Appearingβ
Problem: New endpoints not in Swagger UI
Solution:
- Check file naming: must end with
.doc.ts - Place file in
docs/routes/directory - Export
documentationconstant - Rebuild:
npm run docs:build - Restart server
Authentication Not Workingβ
Problem: 401 errors when testing endpoints
Solution:
- Click Authorize button
- Enter valid API key
- For protected routes, also add JWT token
- Ensure tokens haven't expired
- Check security configuration matches backend
Exporting Documentationβ
OpenAPI JSONβ
The generated openapi.json can be:
- Imported into Postman
- Used with API clients
- Uploaded to API documentation platforms
- Shared with frontend developers
Download from Swagger UIβ
- Open
/api-docs - Look for
/api-docs/swagger.jsonlink - Download the JSON file
Use with Other Toolsβ
Postman:
- File β Import
- Select
openapi.json - All endpoints imported with examples
Insomnia:
- Create β Import From β File
- Select
openapi.json
API Clients: Generate client code using OpenAPI Generator:
npx @openapitools/openapi-generator-cli generate \
-i docs/openapi.json \
-g typescript-axios \
-o ./generated-client
Next Stepsβ
- Authentication System - Secure your endpoints
- Code Generator - Auto-generate resources
- Testing - Test your documented endpoints
- Deployment - Deploy with documentation
Questions? Check the GitHub Discussions or open an issue.