Skip to main content

Swagger API Documentation New

Available from v1.3.0-beta

Arkos.js automatically generates comprehensive OpenAPI documentation for your API endpoints, providing interactive documentation that stays synchronized with your actual API behavior. The documentation system supports three different schema generation approaches and integrates seamlessly with your existing validation and query configurations.

Quick Start

Enable API documentation with minimal configuration:

// src/app.ts
import arkos from "arkos";

arkos.init({
swagger: {
mode: "prisma", // or "class-validator" or "zod"
options: {
definition: {
info: {
title: "My API",
version: "1.0.0",
description: "API documentation generated by Arkos.js",
},
},
},
},
});

Start your server and visit /api/docs to see your generated API documentation.

Schema Generation Modes

Arkos offers three approaches to generate OpenAPI schemas, each with distinct advantages:

Prisma Mode: Live Schema Reflection

Best for: Rapid prototyping, APIs that closely mirror database structure

arkos.init({
swagger: {
mode: "prisma",
},
});

Prisma mode automatically generates schemas directly from your Prisma models and synchronizes with your Custom Prisma Query Options (also supported on another modes):

  • Includes become schema properties: If user.query.ts contains include: { posts: true }, the User response schema will include a posts array
  • Selects limit schema fields: Only selected fields appear in documentation - select: { id: true, name: true } shows only those fields
  • Omits exclude from docs: password: false removes password from all generated schemas
  • Deep nesting respected: Complex nested selects and includes are fully reflected in schemas

Example with query options integration:

// src/modules/user/user.query.ts
import { PrismaQueryOptions } from "arkos/prisma";
import prisma from "../../utils/prisma";

export type UserDelegate = typeof prisma.user;

const userPrismaQueryOptions: PrismaQueryOptions<UserDelegate> = {
findMany: {
select: {
id: true,
name: true,
email: true,
posts: {
select: {
id: true,
title: true,
},
},
},
// password field automatically excluded from documentation
},
};

export default userPrismaQueryOptions;

The generated OpenAPI schema will show User responses with exactly these fields, ensuring documentation matches actual API behavior.

Class-Validator Mode: Decorator-Based Documentation

Best for: Projects using class-validator for validation, fine-grained control over schemas

arkos.init({
validation: {
resolver: "class-validator",
},
swagger: {
mode: "class-validator",
},
});

Uses your existing class-validator DTOs to generate schemas:

// src/modules/user/dtos/create-user.dto.ts
import { IsString, IsEmail, IsOptional } from "class-validator";

export default class CreateUserDto {
@IsString()
name: string;

@IsEmail()
email: string;

@IsOptional()
@IsString()
bio?: string;
}

The decorators automatically generate JSON Schema with validation rules included in the documentation.

Zod Mode: Schema-First Documentation

Best for: TypeScript-heavy projects, schema-first development, type safety

arkos.init({
validation: {
resolver: "zod",
},
swagger: {
mode: "zod",
},
});

Leverages Zod schemas for both validation and documentation:

// src/modules/user/schemas/create-user.schema.ts
import { z } from "zod";

const CreateUserSchema = z.object({
name: z.string().min(1).max(100),
email: z.string().email(),
bio: z.string().optional(),
});

export default CreateUserSchema;

Provides excellent TypeScript integration and maintains a single source of truth for data structures.

Configuration Deep Dive

Essential Configuration

arkos.init({
swagger: {
endpoint: "/docs", // Documentation URL
mode: "prisma",
options: {
definition: {
openapi: "3.0.0",
info: {
title: "My API",
version: "1.0.0",
description: "Comprehensive API documentation",
},
servers: [
{
url: "http://localhost:8000",
description: "Development Server",
},
{
url: "https://api.myapp.com",
description: "Production Server",
},
],
},
},
},
});

Security Configuration

Add JWT authentication to your documentation:

NOTE

Note that if authentication is enabled the JWT authentication is automatically added to the swagger documenation.

swagger: {
mode: "prisma",
options: {
definition: {
components: {
securitySchemes: {
BearerAuth: {
type: "http",
scheme: "bearer",
bearerFormat: "JWT"
},
ApiKeyAuth: {
type: "apiKey",
in: "header",
name: "X-API-Key"
}
}
},
security: [
{ BearerAuth: [] }
]
}
}
}

Scalar UI Customization

Customize the documentation interface:

swagger: {
mode: "prisma",
scalarApiReferenceConfiguration: {
theme: "deepSpace", // "default", "alternate", "deepSpace"
darkMode: true,
layout: "modern", // "classic", "modern"
showSidebar: true,
hideDownloadButton: false,
metaData: {
title: "My API Documentation",
description: "Interactive API documentation"
}
}
}

Arkos uses Scalar instead of traditional Swagger UI for several compelling reasons:

  • Modern API Client Experience: Scalar provides an interface much closer to tools like Postman and Insomnia, making it immediately familiar to developers
  • Superior Visual Design: Scalar offers a significantly more polished and beautiful interface compared to the dated Swagger UI aesthetic
  • Better Developer Experience: Features like better syntax highlighting, improved request/response visualization, and more intuitive navigation
  • Performance: Lighter weight and faster rendering compared to traditional Swagger UI
  • Modern Tech Stack: Built with modern web technologies for better maintainability and extensibility

Learn more about Scalar's features and philosophy at scalar.com.

Customizing Generated Documentation

Override Auto-Generated Paths with JSDoc

Add custom documentation to your router files:

// src/modules/user/user.router.ts
import { Router } from "express";
import userController from "./user.controller";

const userRouter = Router();

/**
* @swagger
* /api/users/analytics:
* get:
* tags:
* - Users
* summary: Get user analytics
* description: Returns comprehensive analytics about user engagement and activity
* security:
* - BearerAuth: []
* parameters:
* - in: query
* name: period
* schema:
* type: string
* enum: [week, month, year]
* description: Analytics time period
* responses:
* 200:
* description: Analytics data retrieved successfully
* content:
* application/json:
* schema:
* type: object
* properties:
* totalUsers:
* type: number
* activeUsers:
* type: number
* growthRate:
* type: number
* 401:
* description: Authentication required
*/
userRouter.get("/analytics", userController.getAnalytics);

export default userRouter;

Enhance Auto-Generated Endpoints

Override specific aspects of auto-generated documentation:

/**
* @swagger
* /api/users:
* post:
* summary: Create a new user account
* description: |
* Creates a new user with the provided information.
* Email addresses must be unique across the system.
* requestBody:
* description: User account information
* required: true
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/CreateUserDto'
* examples:
* standard:
* summary: Standard user creation
* value:
* name: "John Doe"
* email: "john@example.com"
* role: "user"
* admin:
* summary: Admin user creation
* value:
* name: "Jane Admin"
* email: "admin@example.com"
* role: "admin"
* responses:
* 201:
* description: User created successfully
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/UserDto'
* 409:
* description: Email address already exists
*/

Add Tags and Organization

Group your endpoints logically:

swagger: {
mode: "prisma",
options: {
definition: {
tags: [
{
name: "Authentication",
description: "User authentication and authorization"
},
{
name: "Users",
description: "User management operations"
},
{
name: "Posts",
description: "Blog post operations"
}
]
}
}
}

Advanced Schema Handling

Strict Mode Configuration

Control schema fallback behavior:

swagger: {
mode: "class-validator",
strict: true // Only use class-validator DTOs, no Prisma fallback
}

Strict mode behaviors:

  • strict: true - Only uses the specified mode, no fallbacks
  • strict: false (default) - Falls back to Prisma schemas when DTOs/schemas are missing

Mixed Schema Sources

When strict: false, Arkos intelligently chooses schema sources:

  1. Custom DTOs/Schemas (if they exist)
  2. Prisma models (fallback)
  3. Auto-generated schemas (for missing pieces)
// This works even if you only define some DTOs
// Missing DTOs will be auto-generated from Prisma models

// src/modules/user/dtos/create-user.dto.ts - exists
// src/modules/user/dtos/update-user.dto.ts - missing (auto-generated)

Custom Component Schemas

Add reusable schema components:

swagger: {
mode: "prisma",
options: {
definition: {
components: {
schemas: {
ErrorResponse: {
type: "object",
properties: {
status: { type: "string", example: "error" },
message: { type: "string" },
code: { type: "number" },
errors: {
type: "array",
items: {
type: "object",
properties: {
field: { type: "string" },
message: { type: "string" }
}
}
}
}
},
PaginationMeta: {
type: "object",
properties: {
total: { type: "number" },
page: { type: "number" },
limit: { type: "number" },
totalPages: { type: "number" }
}
}
}
}
}
}
}

Live Schema Synchronization with Query Options

The most powerful feature of Arkos documentation is automatic synchronization with your Custom Prisma Query Options. This ensures your documentation always reflects actual API behavior.

How Synchronization Works

// src/modules/post/post.query.ts
import { PrismaQueryOptions } from "arkos/prisma";
import prisma from "../../utils/prisma";

export type PostDelegate = typeof prisma.post;

const postPrismaQueryOptions: PrismaQueryOptions<PostDelegate> = {
findMany: {
select: {
id: true,
title: true,
excerpt: true,
author: {
select: {
id: true,
name: true,
},
},
createdAt: true,
},
},

findOne: {
include: {
author: true,
comments: {
include: {
author: true,
},
},
tags: true,
},
},
};

export default postPrismaQueryOptions;

Generated documentation will show:

  • GET /api/posts responses with only the selected fields
  • GET /api/posts/{id} responses with full author, comments, and tags included
  • Nested author information in comments
  • No sensitive fields that were omitted

Complex Example: User Profile API

// src/modules/user/user.query.ts
import { PrismaQueryOptions } from "arkos/prisma";
import prisma from "../../utils/prisma";

export type UserDelegate = typeof prisma.user;

const userPrismaQueryOptions: PrismaQueryOptions<UserDelegate> = {
queryOptions: {
select: {
id: true,
name: true,
email: true,
createdAt: true,
// Automatically excludes password, resetToken, etc.
password: false,
resetToken: false,
},
},

findMany: {
include: {
profile: {
select: {
bio: true,
avatar: true,
},
},
_count: {
select: {
posts: true,
followers: true,
},
},
},
},
};

export default userPrismaQueryOptions;

Documentation automatically shows:

  • User list includes profile bio, avatar, and post/follower counts
  • Password and reset tokens never appear in any schema
  • Response examples match actual API responses exactly

Production Considerations

Performance Optimization

swagger: {
mode: "prisma",
enableAfterBuild: false, // Disable in production builds
options: {
// Limit schema generation for large APIs
apis: [
"./src/routers/*.router.{ts,js}",
"./src/modules/user/*.router.{ts,js}",
// Only include specific modules for documentation
]
}
}

Security Best Practices

swagger: {
mode: "prisma",
enableAfterBuild: process.env.NODE_ENV !== "production",
options: {
definition: {
// Only show documentation in development
servers: process.env.NODE_ENV === "production"
? [{ url: "https://api.myapp.com" }]
: [{ url: "http://localhost:8000" }]
}
}
}

Environment-Specific Configuration

// src/app.ts
const isDevelopment = process.env.NODE_ENV === "development";

arkos.init({
swagger: isDevelopment
? {
mode: "prisma",
endpoint: "/docs",
options: {
definition: {
info: {
title: "My API - Development",
version: "1.0.0",
},
},
},
}
: undefined, // Completely disable in production
});

Troubleshooting & Common Issues

Schema Resolution Problems

Issue: Missing or incorrect schemas in documentation

Solutions:

  1. Check file naming conventions match exactly
  2. Verify export statements use export default
  3. Ensure TypeScript compilation is working
// ✅ Correct
export default class CreateUserDto {}

// ❌ Incorrect
export class CreateUserDto {}

Performance Issues

Issue: Slow documentation generation

Solutions:

  1. Use strict: true to avoid Prisma model parsing
  2. Limit apis configuration to essential files
  3. Consider disabling in production environments

Missing Documentation for Custom Routes

Issue: Custom endpoints not appearing in documentation

Solution: Add JSDoc comments to your router files:

// src/modules/user/user.router.ts
/**
* @swagger
* components:
* schemas:
* UserStats:
* type: object
* properties:
* totalPosts:
* type: number
* averageRating:
* type: number
*/

/**
* @swagger
* /api/users/{id}/stats:
* get:
* summary: Get user statistics
* parameters:
* - name: id
* in: path
* required: true
* schema:
* type: string
* responses:
* 200:
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/UserStats'
*/
userRouter.get("/:id/stats", userController.getStats);

Debug Schema Generation

Issue: Understanding why certain schemas are generated

Use the debug analysis (development only):

// Add to your development configuration
swagger: {
mode: "prisma",
// Enable debug logging in development
}

Check your console output for schema generation details and conflicts.

Best Practices

Documentation Strategy

  • Start with Prisma mode for rapid development
  • Migrate to class-validator/Zod as your API matures
  • Use JSDoc overrides for complex endpoints
  • Keep documentation close to code in router files

Schema Design

  • Leverage query options for automatic synchronization
  • Use consistent naming across DTOs and schemas
  • Group related endpoints with meaningful tags
  • Provide examples for complex request/response structures

Production Deployment

  • Use environment-specific server configurations
  • Secure sensitive endpoints with proper authentication schemes
  • Monitor documentation size for large APIs

Team Collaboration

  • Document custom endpoints immediately when creating them
  • Review generated schemas match actual API behavior
  • Update examples when API contracts change
  • Use consistent description patterns across your team