Overview

Consistent Swagger documentation for paginated responses and errors.

Features

  • Paginated response decorator
  • Success response wrapper
  • Common error responses
  • Type-safe schemas

Installation

npx hanma add api-response --framework nest

Dependencies

@nestjs/swagger

Code

import { applyDecorators, Type } from "@nestjs/common";
import {
  ApiOkResponse,
  ApiCreatedResponse,
  ApiBadRequestResponse,
  ApiUnauthorizedResponse,
  ApiForbiddenResponse,
  ApiNotFoundResponse,
  ApiInternalServerErrorResponse,
  getSchemaPath,
  ApiExtraModels,
} from "@nestjs/swagger";

// Standard error response DTO
class ErrorResponseDto {
  statusCode: number;
  message: string | string[];
  error: string;
}

/**
 * Decorator for paginated list responses.
 * 
 * Usage:
 * @ApiPaginatedResponse(UserDto)
 * @Get()
 * findAll() {}
 */
export function ApiPaginatedResponse<TModel extends Type<unknown>>(
  model: TModel
) {
  return applyDecorators(
    ApiExtraModels(model),
    ApiOkResponse({
      description: "Paginated list response",
      schema: {
        allOf: [
          {
            properties: {
              data: {
                type: "array",
                items: { $ref: getSchemaPath(model) },
              },
              meta: {
                type: "object",
                properties: {
                  total: { type: "number" },
                  page: { type: "number" },
                  limit: { type: "number" },
                  totalPages: { type: "number" },
                  hasNext: { type: "boolean" },
                  hasPrev: { type: "boolean" },
                },
              },
            },
          },
        ],
      },
    })
  );
}

/**
 * Standard success response wrapper.
 */
export function ApiSuccessResponse<TModel extends Type<unknown>>(
  model: TModel,
  description = "Successful response"
) {
  return applyDecorators(
    ApiExtraModels(model),
    ApiOkResponse({
      description,
      schema: {
        properties: {
          success: { type: "boolean", example: true },
          data: { $ref: getSchemaPath(model) },
        },
      },
    })
  );
}

/**
 * Standard created response wrapper.
 */
export function ApiCreatedSuccessResponse<TModel extends Type<unknown>>(
  model: TModel,
  description = "Resource created successfully"
) {
  return applyDecorators(
    ApiExtraModels(model),
    ApiCreatedResponse({
      description,
      schema: {
        properties: {
          success: { type: "boolean", example: true },
          data: { $ref: getSchemaPath(model) },
        },
      },
    })
  );
}

/**
 * Apply common error responses to controller methods.
 */
export function ApiCommonErrors() {
  return applyDecorators(
    ApiBadRequestResponse({
      description: "Bad Request - Invalid input",
      type: ErrorResponseDto,
    }),
    ApiUnauthorizedResponse({
      description: "Unauthorized - Authentication required",
      type: ErrorResponseDto,
    }),
    ApiForbiddenResponse({
      description: "Forbidden - Insufficient permissions",
      type: ErrorResponseDto,
    }),
    ApiNotFoundResponse({
      description: "Not Found - Resource does not exist",
      type: ErrorResponseDto,
    }),
    ApiInternalServerErrorResponse({
      description: "Internal Server Error",
      type: ErrorResponseDto,
    })
  );
}

/**
 * Combine success and error responses.
 */
export function ApiStandardResponse<TModel extends Type<unknown>>(
  model: TModel,
  description = "Successful response"
) {
  return applyDecorators(
    ApiSuccessResponse(model, description),
    ApiCommonErrors()
  );
}

Usage

@ApiPaginatedResponse(UserDto)
@Get()
findAll() {}

Dependencies

Frequently Asked Questions

How do I install API Response?
Run the following command: npx hanma add api-response --framework nest
What dependencies are required?
This snippet requires: @nestjs/swagger. Make sure to install them before using the snippet.
How do I use this snippet?
Copy the code and paste it into your project. The snippet will be saved to src/decorators/api-response.decorator.ts.
Can I customize this snippet?
Yes! All snippets are copy-paste code that you own. Feel free to modify them to fit your needs.
Does this work with other frameworks?
This snippet is designed for the specific framework. Check the other framework pages for equivalent implementations.