Skip to content

API Standards

Response Envelope

typescript
// All successful responses follow this format
interface SuccessResponse<T> {
  success: true;
  data: T;
  meta?: {
    pagination?: PaginationMeta;
    [key: string]: unknown;
  };
}

interface PaginationMeta {
  total: number;
  page: number;
  pageSize: number;
  totalPages: number;
  hasNext: boolean;
  hasPrevious: boolean;
}

Examples

Single item

json
{
  "success": true,
  "data": {
    "id": "uuid",
    "email": "user@example.com"
  }
}

List with pagination

json
{
  "success": true,
  "data": [
    { "id": "uuid1", "name": "Product 1" },
    { "id": "uuid2", "name": "Product 2" }
  ],
  "meta": {
    "pagination": {
      "total": 100,
      "page": 1,
      "pageSize": 20,
      "totalPages": 5,
      "hasNext": true,
      "hasPrevious": false
    }
  }
}

Pagination

typescript
// Offset pagination with query params: ?page=1&pageSize=20

interface PaginationQuery {
  page?: number;      // Default: 1, min: 1
  pageSize?: number;  // Default: 20, max: 100
}

// Controller usage
@Get()
async findAll(
  @Query() pagination: PaginationQuery,
): Promise<SuccessResponse<Product[]>> {
  const { page = 1, pageSize = 20 } = pagination;
  const result = await this.productService.findAll({ page, pageSize });

  return {
    success: true,
    data: result.items,
    meta: { pagination: result.pagination },
  };
}

Filtering and Sorting

typescript
// Query params for filtering
// GET /api/v1/products?status=ACTIVE&categoryId=uuid&minPrice=100&maxPrice=500

// Query params for sorting
// GET /api/v1/products?sortBy=price&sortOrder=asc

interface ProductFilterQuery {
  status?: ProductStatus;
  categoryId?: string;
  minPrice?: number;
  maxPrice?: number;
  search?: string;       // Full-text search on name/description
  sortBy?: 'price' | 'name' | 'createdAt';
  sortOrder?: 'asc' | 'desc';
}

API Versioning

/api/v1/...  ← Current version

Future:
/api/v2/...  ← Major breaking changes only

Strategy: URL-based versioning (simplest). Only create v2 when breaking changes are unavoidable.


API Documentation (Scalar)

Interactive API documentation using Scalar — a modern alternative to Swagger UI with better UX, dark mode, and faster rendering.

Installation

bash
npm install @nestjs/swagger @scalar/nestjs-api-reference

Setup

typescript
// main.ts
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import { apiReference } from '@scalar/nestjs-api-reference';

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

  // OpenAPI specification
  const config = new DocumentBuilder()
    .setTitle('IWM Platform API')
    .setDescription('MLM Platform with Investment and Product Marketplaces')
    .setVersion('1.0')
    .addBearerAuth()
    .addTag('auth', 'Authentication endpoints')
    .addTag('users', 'User management')
    .addTag('mlm', 'MLM/Partner operations')
    .addTag('products', 'E-commerce products')
    .addTag('orders', 'Order management')
    .addTag('investments', 'Investment operations')
    .build();

  const document = SwaggerModule.createDocument(app, config);

  // Scalar UI at /api/docs (replaces Swagger UI)
  app.use('/api/docs', apiReference({
    spec: { content: document },
    theme: 'purple',  // or 'default', 'moon', 'mars'
  }));

  // Optional: JSON spec endpoint for external tools
  app.use('/api/docs/openapi.json', (req, res) => res.json(document));

  await app.listen(3000);
}

Features

FeatureDescription
Try ItInteractive request builder with auth support
SearchFull-text search across all endpoints
Dark ModeBuilt-in theme switching
Code SamplesAuto-generated examples in multiple languages
OpenAPI 3.1Full specification support

Access

  • Interactive Docs: http://localhost:3000/api/docs
  • OpenAPI JSON: http://localhost:3000/api/docs/openapi.json