Node.js Quick Start

Get started with Bytedocs in Node.js applications

Bytedocs for Node.js supports the most popular frameworks with automatic route detection and TypeScript support.

Supported Frameworks

  • Express - Fast, unopinionated web framework
  • Fastify - High performance web framework
  • NestJS - Progressive Node.js framework
  • Hono - Ultrafast web framework
  • Koa - Next generation web framework
  • AdonisJS - Full-featured MVC framework

Installation

Choose your framework:

# Express
npm install @bytedocs/express

# Fastify
npm install @bytedocs/fastify

# NestJS
npm install @bytedocs/nestjs

# Hono
npm install @bytedocs/hono

# Koa
npm install @bytedocs/koa

# AdonisJS
npm install @bytedocs/adonisjs

Quick Start Examples

Express

import express from 'express';
import { setupByteDocs } from '@bytedocs/express';

const app = express();
app.use(express.json());

// Setup Bytedocs - One line!
setupByteDocs(app, {
  title: 'My API',
  version: '1.0.0',
  description: 'My awesome API',
});

// Define your routes as normal
app.get('/users/:id', (req, res) => {
  res.json({ id: req.params.id, name: 'John Doe' });
});

app.post('/users', (req, res) => {
  const { name, email } = req.body;
  res.status(201).json({ id: 1, name, email });
});

app.listen(3000, () => {
  console.log('Server running on http://localhost:3000');
  console.log('Docs available at http://localhost:3000/docs');
});

Express with TypeScript

import express, { Request, Response } from 'express';
import { setupByteDocs } from '@bytedocs/express';

interface User {
  id: number;
  name: string;
  email: string;
}

interface CreateUserRequest {
  name: string;
  email: string;
}

const app = express();
app.use(express.json());

setupByteDocs(app, {
  title: 'My API',
  version: '1.0.0',
});

// TypeScript interfaces are automatically detected
app.get('/users/:id', (req: Request, res: Response<User>) => {
  res.json({
    id: parseInt(req.params.id),
    name: 'John Doe',
    email: 'john@example.com'
  });
});

app.post('/users', (req: Request<{}, {}, CreateUserRequest>, res: Response<User>) => {
  const { name, email } = req.body;
  res.status(201).json({ id: 1, name, email });
});

app.listen(3000);

Fastify

import Fastify from 'fastify';
import { setupByteDocs } from '@bytedocs/fastify';

const fastify = Fastify();

// Setup Bytedocs
setupByteDocs(fastify, {
  title: 'My Fastify API',
  version: '1.0.0',
});

// Define routes with schema validation
fastify.get('/users/:id', {
  schema: {
    params: {
      type: 'object',
      properties: {
        id: { type: 'number' }
      }
    },
    response: {
      200: {
        type: 'object',
        properties: {
          id: { type: 'number' },
          name: { type: 'string' },
          email: { type: 'string' }
        }
      }
    }
  },
  handler: async (request, reply) => {
    return {
      id: request.params.id,
      name: 'John Doe',
      email: 'john@example.com'
    };
  }
});

await fastify.listen({ port: 3000 });

NestJS

// main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { setupByteDocs } from '@bytedocs/nestjs';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  // Setup Bytedocs
  setupByteDocs(app, {
    title: 'My NestJS API',
    version: '1.0.0',
  });

  await app.listen(3000);
}
bootstrap();
// users.controller.ts
import { Controller, Get, Post, Body, Param } from '@nestjs/common';

interface User {
  id: number;
  name: string;
  email: string;
}

class CreateUserDto {
  name: string;
  email: string;
}

@Controller('users')
export class UsersController {
  @Get(':id')
  findOne(@Param('id') id: string): User {
    return {
      id: parseInt(id),
      name: 'John Doe',
      email: 'john@example.com'
    };
  }

  @Post()
  create(@Body() createUserDto: CreateUserDto): User {
    return {
      id: 1,
      ...createUserDto
    };
  }
}

Hono

import { Hono } from 'hono';
import { setupByteDocs } from '@bytedocs/hono';

const app = new Hono();

// Setup Bytedocs
setupByteDocs(app, {
  title: 'My Hono API',
  version: '1.0.0',
});

app.get('/users/:id', (c) => {
  const id = c.req.param('id');
  return c.json({ id, name: 'John Doe' });
});

app.post('/users', async (c) => {
  const body = await c.req.json();
  return c.json({ id: 1, ...body }, 201);
});

export default app;

Koa

import Koa from 'koa';
import Router from '@koa/router';
import bodyParser from 'koa-bodyparser';
import { setupByteDocs } from '@bytedocs/koa';

const app = new Koa();
const router = new Router();

app.use(bodyParser());

// Setup Bytedocs
setupByteDocs(app, router, {
  title: 'My Koa API',
  version: '1.0.0',
});

router.get('/users/:id', (ctx) => {
  ctx.body = {
    id: ctx.params.id,
    name: 'John Doe'
  };
});

router.post('/users', (ctx) => {
  ctx.status = 201;
  ctx.body = {
    id: 1,
    ...ctx.request.body
  };
});

app.use(router.routes());
app.listen(3000);

AdonisJS

// start/routes.ts
import Route from '@ioc:Adonis/Core/Route';
import { setupByteDocs } from '@bytedocs/adonisjs';

// Setup Bytedocs
setupByteDocs({
  title: 'My AdonisJS API',
  version: '1.0.0',
});

Route.get('/users/:id', 'UsersController.show');
Route.post('/users', 'UsersController.store');
// app/Controllers/Http/UsersController.ts
import type { HttpContextContract } from '@ioc:Adonis/Core/HttpContext';

export default class UsersController {
  public async show({ params, response }: HttpContextContract) {
    return response.json({
      id: params.id,
      name: 'John Doe'
    });
  }

  public async store({ request, response }: HttpContextContract) {
    const body = request.only(['name', 'email']);
    return response.status(201).json({
      id: 1,
      ...body
    });
  }
}

Configuration Options

Basic Configuration

setupByteDocs(app, {
  title: 'My API',
  version: '1.0.0',
  description: 'API description',
  docsPath: '/docs',        // Default: '/docs'
  autoDetect: true,          // Default: true
});

Multiple Environments

setupByteDocs(app, {
  title: 'My API',
  version: '1.0.0',
  baseUrls: [
    { name: 'Production', url: 'https://api.example.com' },
    { name: 'Staging', url: 'https://staging.example.com' },
    { name: 'Local', url: 'http://localhost:3000' },
  ],
});

With Authentication

setupByteDocs(app, {
  title: 'My API',
  version: '1.0.0',
  auth: {
    enabled: true,
    type: 'session',
    username: 'admin',
    password: process.env.DOCS_PASSWORD,
  },
});

With AI Assistant

setupByteDocs(app, {
  title: 'My API',
  version: '1.0.0',
  ai: {
    enabled: true,
    provider: 'openai',
    apiKey: process.env.OPENAI_API_KEY,
    model: 'gpt-4o-mini',
  },
});

Auto-Detection Features

1. Route Parameters

// Path parameters
app.get('/users/:id', (req, res) => {
  const id = req.params.id;  // Auto-detected
  // ...
});

// Query parameters
app.get('/users', (req, res) => {
  const page = req.query.page;  // Auto-detected
  // ...
});

// Multiple parameters
app.get('/posts/:postId/comments/:commentId', (req, res) => {
  // Both parameters auto-detected
});

2. Request Body (TypeScript)

interface CreateUserDto {
  name: string;
  email: string;
  age?: number;
}

app.post('/users', (req: Request<{}, {}, CreateUserDto>, res) => {
  // CreateUserDto schema automatically documented
  const { name, email, age } = req.body;
  // ...
});

3. Response Types (TypeScript)

interface User {
  id: number;
  name: string;
  email: string;
  createdAt: Date;
}

app.get('/users/:id', (req, res: Response<User>) => {
  // User schema automatically documented
  res.json({
    id: 1,
    name: 'John',
    email: 'john@example.com',
    createdAt: new Date()
  });
});

4. Validation with Zod

import { z } from 'zod';

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

app.post('/users', (req, res) => {
  const data = CreateUserSchema.parse(req.body);
  // Schema automatically documented with validation rules
  // ...
});

5. JSDoc Annotations

/**
 * Get user by ID
 * @summary Retrieve a specific user
 * @tag Users
 * @param id path number true "User ID"
 * @response 200 {object} User "User object"
 * @response 404 {object} Error "User not found"
 */
app.get('/users/:id', (req, res) => {
  // ...
});

JSDoc Tags Reference

Basic Tags

/**
 * Endpoint title
 * @summary Short description
 * @description Longer description with details
 * @tag TagName
 */

Parameters

/**
 * @param name in type required "description"
 *
 * Examples:
 * @param id path number true "User ID"
 * @param page query number false "Page number"
 * @param Authorization header string true "Bearer token"
 */

Request Body

/**
 * @body {object} RequestSchema "Request body description"
 *
 * Example:
 * @body {object} CreateUserRequest "User data"
 */

Responses

/**
 * @response status {type} Schema "Description"
 *
 * Examples:
 * @response 200 {object} User "Success"
 * @response 201 {object} User "Created"
 * @response 400 {object} Error "Bad request"
 * @response 404 {object} Error "Not found"
 */

TypeScript Best Practices

1. Define Interfaces

// DTOs (Data Transfer Objects)
interface CreateUserDto {
  name: string;
  email: string;
  password: string;
}

interface UpdateUserDto {
  name?: string;
  email?: string;
}

// Response types
interface UserResponse {
  id: number;
  name: string;
  email: string;
  createdAt: string;
}

// Error types
interface ErrorResponse {
  message: string;
  errors?: Record<string, string[]>;
}

2. Use Type Assertions

app.post('/users',
  (req: Request<{}, {}, CreateUserDto>,
   res: Response<UserResponse | ErrorResponse>) => {
    // Types are automatically documented
  }
);

3. Export Types

// types/user.ts
export interface User {
  id: number;
  name: string;
  email: string;
}

// routes/users.ts
import { User } from '../types/user';

app.get('/users/:id', (req, res: Response<User>) => {
  // User type is reused across documentation
});

Middleware Integration

Express Middleware

import { byteDocsAuth } from '@bytedocs/express';

// Protect docs with custom middleware
app.use('/docs', byteDocsAuth({
  username: 'admin',
  password: process.env.DOCS_PASSWORD,
}));

Custom Authentication

app.use('/docs', (req, res, next) => {
  // Custom auth logic
  const token = req.headers.authorization;
  if (!isValidToken(token)) {
    return res.status(401).json({ error: 'Unauthorized' });
  }
  next();
});

Environment Variables

# .env file
BYTEDOCS_TITLE="My API"
BYTEDOCS_VERSION="1.0.0"
BYTEDOCS_DESCRIPTION="My awesome API"
BYTEDOCS_DOCS_PATH=/docs
BYTEDOCS_AUTO_DETECT=true

# Multiple environments
BYTEDOCS_PRODUCTION_URL=https://api.example.com
BYTEDOCS_STAGING_URL=https://staging.example.com
BYTEDOCS_LOCAL_URL=http://localhost:3000

# Authentication
BYTEDOCS_AUTH_ENABLED=true
BYTEDOCS_AUTH_TYPE=session
BYTEDOCS_AUTH_USERNAME=admin
BYTEDOCS_AUTH_PASSWORD=secret

# AI
BYTEDOCS_AI_ENABLED=true
BYTEDOCS_AI_PROVIDER=openai
BYTEDOCS_AI_API_KEY=sk-...
BYTEDOCS_AI_MODEL=gpt-4o-mini

Using in Configuration

import dotenv from 'dotenv';
dotenv.config();

setupByteDocs(app, {
  title: process.env.BYTEDOCS_TITLE,
  version: process.env.BYTEDOCS_VERSION,
  description: process.env.BYTEDOCS_DESCRIPTION,
  auth: {
    enabled: process.env.BYTEDOCS_AUTH_ENABLED === 'true',
    type: process.env.BYTEDOCS_AUTH_TYPE,
    username: process.env.BYTEDOCS_AUTH_USERNAME,
    password: process.env.BYTEDOCS_AUTH_PASSWORD,
  },
  ai: {
    enabled: process.env.BYTEDOCS_AI_ENABLED === 'true',
    provider: process.env.BYTEDOCS_AI_PROVIDER,
    apiKey: process.env.BYTEDOCS_AI_API_KEY,
    model: process.env.BYTEDOCS_AI_MODEL,
  },
});

Production Deployment

Disable in Production

if (process.env.NODE_ENV !== 'production') {
  setupByteDocs(app, {
    title: 'My API',
    version: '1.0.0',
  });
}

Or Protect with Authentication

setupByteDocs(app, {
  title: 'My API',
  version: '1.0.0',
  auth: {
    enabled: process.env.NODE_ENV === 'production',
    type: 'session',
    username: process.env.DOCS_USERNAME,
    password: process.env.DOCS_PASSWORD,
  },
});

Troubleshooting

Routes Not Appearing

  1. Ensure routes are registered before Bytedocs:
// ❌ Wrong
setupByteDocs(app, config);
app.get('/users', handler);

// ✅ Correct
app.get('/users', handler);
setupByteDocs(app, config);
  1. Check route registration:
// For debugging
app._router.stack.forEach(r => {
  if (r.route) console.log(r.route.path);
});

TypeScript Types Not Detected

  1. Enable declaration files:
// tsconfig.json
{
  "compilerOptions": {
    "declaration": true,
    "emitDeclarationOnly": false
  }
}
  1. Use explicit types:
// Instead of implicit any
const handler = (req, res) => { ... }

// Use explicit types
const handler = (req: Request, res: Response) => { ... }

Memory Issues with Large APIs

setupByteDocs(app, {
  title: 'My API',
  version: '1.0.0',
  cache: true,  // Enable caching
  excludePaths: [  // Exclude unnecessary routes
    '/health',
    '/metrics',
    '/_internal',
  ],
});

Visit Documentation

Start your server and visit:

http://localhost:3000/docs

What's Next?