diff --git a/docs/reference/server-adapters/nestjs.mdx b/docs/reference/server-adapters/nestjs.mdx index 8d0d8c4d..1d558d3d 100644 --- a/docs/reference/server-adapters/nestjs.mdx +++ b/docs/reference/server-adapters/nestjs.mdx @@ -66,6 +66,97 @@ export class MyController { You can still use the regular Prisma service by injecting as usual. +### Using the API handler service to automate request handling + +This module also provides an `ApiHandlerService` that can be used to automate the request handling using API handlers. This is useful if you want to handle requests in a more structured way, such as using a controller or middleware. Before using it, you should ensure `ENHANCED_PRISMA` is registered in the module. For example: + +```ts +import { ZenStackModule, ApiHandlerService } from '@zenstackhq/server/nestjs'; +import { enhance } from '@zenstackhq/runtime'; +import { PrismaService } from './prisma.service'; + +@Module({ + imports: [ + // Register the ZenStack module + // The module exports the ENHANCED_PRISMA token and could be used in the ApiHandlerService + ZenStackModule.registerAsync({ + useFactory: (prisma: PrismaService) => { + return { + getEnhancedPrisma: () => enhance(prisma, { user: ... }), + }; + }, + inject: [PrismaService], + extraProviders: [PrismaService], + }), + ], + providers: [ApiHandlerService] +}) +export class AppModule {} +``` + +Then, you can inject the `ApiHandlerService` into your code and use it to handle requests. The service provides a method `handleRequest` to handle request using API handler automatically. + +RPC API Handler: + +```ts +import { Controller, Get, Post } from '@nestjs/common'; +import { ApiHandlerService } from '@zenstackhq/server/nestjs'; + +@Controller('post') +export class PostController { + constructor(private readonly apiHandlerService: ApiHandlerService) {} + + // should align with the route generated by API handler + @Get('findMany') + async findMany() { + return this.apiHandlerService.handleRequest() + } + + @Post('create') + async create() { + return this.apiHandlerService.handleRequest() + } +} +``` + +RESTful API Handler: + +```ts +import { Controller, Get, Post } from '@nestjs/common'; +import { ApiHandlerService } from '@zenstackhq/server/nestjs'; +import RESTApiHandler from '@zenstackhq/server/api/rest'; + +const ENDPOINT = 'http://localhost'; + +@Controller('post') +export class PostController { + constructor(private readonly apiHandlerService: ApiHandlerService) {} + + // should align with the route generated by API handler + @Get() + async list() { + return this.apiHandlerService.handleRequest( + { + handler: RESTApiHandler({ + endpoint: ENDPOINT, + }), + } + ) + } + + @Post() + async create() { + return this.apiHandlerService.handleRequest( + { + handler: RESTApiHandler({ + endpoint: ENDPOINT, + }), + } + ) + } +} +``` + ### API reference #### `ZenStackModule.registerAsync` @@ -121,3 +212,57 @@ interface ZenStackModuleOptions { getEnhancedPrisma: (model?: string | symbol) => unknown; } ``` + +#### `ApiHandlerService.handleRequest` + +##### Signature + +```ts +handleRequest(options?: ApiHandlerOptions): Promise; +``` + +##### Parameter `options` + +```ts +interface ApiHandlerOptions { + /** + * Logger settings + */ + logger?: LoggerConfig; + + /** + * Model metadata. By default loaded from the `node_module/.zenstack/model-meta` + * module. You can pass it in explicitly if you configured ZenStack to output to + * a different location. + */ + modelMeta?: ModelMeta; + + /** + * Zod schemas for validating request input. Pass `true` to load from standard location + * (need to enable `@core/zod` plugin in schema.zmodel) or omit to disable input validation. + */ + zodSchemas?: ZodSchemas | boolean; + + /** + * Api request handler function. Can be created using `@zenstackhq/server/api/rest` or `@zenstackhq/server/api/rpc` factory functions. + * Defaults to RPC-style API handler. + */ + handler?: HandleRequestFn; + + /** + * The base URL for the API handler. This is used to determine the base path for the API requests. + * If you are using the ApiHandlerService in a route with a prefix, you should set this to the prefix. + * + * e.g. + * without baseUrl(API handler default route): + * - RPC API handler: [model]/findMany + * - RESTful API handler: /:type + * + * with baseUrl(/api/crud): + * - RPC API handler: /api/crud/[model]/findMany + * - RESTful API handler: /api/crud/:type + */ + baseUrl?: string; +} +``` +