Skip to content

Repository files navigation

Nzoth logo

@lonestone/nzoth

npm packagenode compatibilitybuild status

NZOTH: Nest + Zod + OpenAPI + Typed + Helpers (pronounced "n'zoth")

A collection of NestJS utilities for building RESTful APIs with support for filtering, pagination, sorting, type-safe request/response validation, and OpenAPI schema registration using Zod. Allows registering Zod schemas with OpenAPI metadata for automatic documentation generation.

Why NZOTH?

NZOTH significations:

  • NestJS: The progressive Node.js framework for building efficient, reliable, and scalable server-side applications
  • Zod: TypeScript-first schema validation with static type inference
  • OpenAPI: Automated API documentation that stays in sync with your code
  • Typed: End-to-end type safety from your routes to your controllers to your clients
  • Helpers: A comprehensive collection of utilities for filtering, pagination, sorting, and more

Our goal is to provide a type-safe API solution that's easy to use while still being compatible with various languages and tools. NZOTH offers a simple yet powerful alternative to solutions like tRPC and GraphQL for projects that need REST APIs with strong typing.

We aimed to keep things simple, with the following goals:

  • Things should be as type-safe as possible;
  • It should allow developers to follow the code as much as possible (ctrl+click on a DTO should bring them to the implementation);
  • It should be easy to use in a monorepo environment;
  • It should provide a standard way to paginate, filter and sort data;
  • It should allow for data validation, input and output;
  • It should help to get a CRUD API up and running quickly;
  • It should be able to generate OpenAPI documentation from your Zod schemas, without modifying NestJS Swagger behavior;
  • In general, it should be as unobtrusive as possible.

Features

  • Validation: Comprehensive Zod-based validation for requests and responses
  • 🎯 Decorators: Decorators to validate route response, parameters, query params, and body
  • 🔍 Filtering: Flexible query parameter-based filtering with multiple operators
  • 📄 Pagination: Easy-to-use pagination with offset and page size
  • 🔃 Sorting: Multi-field sorting with ascending/descending support
  • 📄 OpenAPI: Automatically generate OpenAPI documentation from your Zod schemas, without modifying NestJS Swagger behavior

Installation

npm install @lonestone/nzoth
# or
yarn add @lonestone/nzoth
# or
pnpm add @lonestone/nzoth

Type safety and validation

Warning

⚠️Module Augmentation Warning: This package augments the Zod module by adding a .meta() method to all Zod types. This is a global modification that affects all Zod instances in your application. This is done to provide a seamless integration with OpenAPI documentation generation see here.

Schema Definition

First, define your schemas using z (which adds OpenAPI metadata support to Zod):

// Define an enum with OpenAPI metadataexportconstUserRole=z.enum(['admin','user']).meta({title: 'UserRole',description: 'User role',example: 'admin',});// Define the main schema with OpenAPI metadataexportconstUserSchema=z.object({id: z.string().uuid(),name: z.string().min(2),email: z.string().email(),age: z.number().positive(),role: UserRole,tags: z.array(z.string()),}).meta({title: 'User',description: 'User schema',});// Create derived schemasexportconstUserCreateSchema=z.meta(UserSchema.omit({id: true}),{title: 'UserCreate',description: 'User create schema',});exportconstUserUpdateSchema=z.meta(UserSchema.omit({id: true}),{title: 'UserUpdate',description: 'User update schema',});// Export typesexporttypeUser=z.infer<typeofUserSchema>;exporttypeUserCreate=z.infer<typeofUserCreateSchema>;exporttypeUserUpdate=z.infer<typeofUserUpdateSchema>;

Route Validation

Use TypedRoute decorators to validate response data:

// All routes in this controller will require the clientId parameter// But we do not need to define it in the route path if not needed for the route logic (See put)// Ownership should be checked in a Guard, not inside the controller
@TypedController('/clients/:clientId/users',z.object({clientId: z.string().uuid(),}),)classUserController{
@TypedRoute.Get(undefined,UsersSchema)findAll(
@TypedParam('clientId')clientId: string,
@FilteringParams(userFilteringSchema)filters?: any[],
@PaginationParams(userPaginationSchema)pagination?: any,
@SortingParams(userSortingSchema)sort?: any[],): User[]{// Response will be validated against UsersSchemareturnthis.userService.findAll(clientId,filters,pagination,sort);}
@TypedRoute.Get(':id',UserSchema)findOne(@TypedParam('id','uuid')id: string): User{// Response will be validated against UserSchemareturnthis.userService.findOne(id);}
@TypedRoute.Post('',UserSchema)create(
@TypedParam('clientId')clientId: string,
@TypedBody(UserCreateSchema)userData: UserCreate,): User{// Request body validated against UserCreateSchema// Response validated against UserSchemareturnthis.userService.create(clientId,userData);}
@TypedRoute.Put(':id',UserUpdateSchema)update(
@TypedParam('id','uuid')id: string,
@TypedBody(UserUpdateSchema)userData: UserUpdate,): User{// Both request and response are validatedreturnthis.userService.update(id,userData);}
@TypedRoute.Delete(':id')remove(@TypedParam('id','uuid')id: string){returnthis.userService.remove(id);}}

Filtering, Pagination, and Sorting

Define your filtering, pagination, and sorting schemas:

// FilteringexportconstenabledUserFilteringKeys=['name','email','role','tags']asconst;exportconstuserFilteringSchema=createFilterQueryStringSchema(enabledUserFilteringKeys);// SortingexportconstenabledUserSortingKeys=['name','email','role','tags'];exportconstuserSortingSchema=createSortingQueryStringSchema(enabledUserSortingKeys);// PaginationexportconstuserPaginationSchema=createPaginationQuerySchema({defaultPageSize: 10,maxPageSize: 100,minPageSize: 1,});exporttypeUserPagination=z.infer<typeofuserPaginationSchema>;

Filtering

Supported filter rules:

  • eq - Equals
  • neq - Not equals
  • gt - Greater than
  • gte - Greater than or equals
  • lt - Less than
  • lte - Less than or equals
  • like - Like (string pattern matching)
  • nlike

Built on top of:

Logo by Alexandra Chaillou

About

A collection of NestJS utilities for building RESTful APIs with OpenAPI metadata for automatic documentation generation.

Topics

Resources

Contributing

Stars

9 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages