VitNode

Controllers

Handle incoming requests and returning responses.

Controllers are responsible for handling incoming requests and returning responses to the client. They are the entry points for the application and are used to define routes and request handling logic.

Routing

Controllers are defined using the @Controller decorator. The decorator takes a path argument that defines the base route for all routes defined in the controller.

apps/backend/src/plugins/{your_plugin_code}/example.controller.ts
import { Controller, Get } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { Controllers } from 'vitnode-backend/helpers/controller.decorator';
 

@Controllers({

  plugin_name: 'Welcome',

  plugin_code: 'welcome',

  route: 'example',

})
export class ExampleWelcomeController {
  @Get()
  getHello(): string {
    return 'Hello World!';
  }
}

In the example above, the ExampleWelcomeController class is decorated with @CControllers. This means that all routes defined in the controller will be prefixed with /{your_plugin_code}/example.

Enable methods for handling HTTP requests by using the @Get(), @Post(), @Put(), @Delete(), @Patch(), @Options(), and @Head() decorators. These decorators are provided by the @nestjs/common package.

Nesting routes

You can nest routes by using the @Controller() decorator with a route argument. For example we want to create a nested route /{your_plugin_code}/example:

apps/backend/src/plugins/{your_plugin_code}/example.controller.ts
@Controllers({
  plugin_name: 'Welcome',
  plugin_code: 'welcome',

  route: 'example/nested',
})

Disable protecting per route

To disable authorization for a specific route, you can use the @OptionalAuth() decorator.

apps/backend/src/plugins/{your_plugin_code}/example.controller.ts
import { OptionalAuth } from 'vitnode-backend/guards/auth.guard';
 
export class ExampleWelcomeController {
  @Get()
  @OptionalAuth() 
  getHello(@CurrentUser() user?: User): string {
    return `Hello ${user.name}!`;
  }
}

Import into module

To use the controller, import it into the module where it will be used. Go to the module root of your plugin. That's should be apps/backend/src/plugins/{your_plugin_code}/{your_plugin_code}.module.ts. Import the controller and add it to the controllers array.

apps/backend/src/plugins/{your_plugin_code}/{your_plugin_code}.module.ts
import { Module } from '@nestjs/common';
import { ExampleWelcomeController } from './example.controller'; 
 
@Module({
  controllers: [ExampleWelcomeController], 
})
export class WelcomeModule {}

Request & Response objects

Controllers can access the request and response objects by using the @Req() and @Res() decorators. These decorators are provided by the @nestjs/common package.

apps/backend/src/plugins/{your_plugin_code}/example.controller.ts
import { Controller, Get, Req, Res } from '@nestjs/common';
import { Request, Response } from 'express'; 
 
@Controller('welcome/example')
export class ExampleWelcomeController {
  @Get()

  getHello(@Req() req: Request, @Res() res: Response): string {
    return 'Hello World!';
  }
}

NestJS detects when the handler is using either @Res() or @Next(), indicating you have chosen the library-specific option. If both approaches are used at the same time, the Standard approach is automatically disabled for this single route and will no longer work as expected. To use both approaches at the same time (for example, by injecting the response object to only set cookies/headers but still leave the rest to the framework), you must set the passthrough option to true in the @Res({ passthrough: true }) decorator.

Warning from NestJS documentation.

Operations

OpenAPI operations provide additional information about the operation. You can write documentation API automatically and validate the request.

Responses

Responses are used to define the responses that are returned by the operation. They are defined using the @ApiResponse() decorator.

apps/backend/src/plugins/{your_plugin_code}/example.controller.ts
import { ApiResponse } from '@nestjs/swagger'; 
import { Controllers } from 'vitnode-backend/helpers/controller.decorator';
 
@Controllers({
  plugin_name: 'Welcome',
  plugin_code: 'welcome',
  route: 'example',
})
export class ExampleWelcomeController {
  @Get()
  @ApiResponse({ status: 200, description: 'Hello World!' }) 
  getHello(): string {
    return 'Hello World!';
  }
}

You can use build-in responses like:

DecoratorCodeDescription
@ApiOkResponse()200The request was successful.
@ApiCreatedResponse()201The request was successful and a new resource was created.
@ApiAcceptedResponse()202The request was accepted for processing.
@ApiNoContentResponse()204The request was successful but there is no content to return.
@ApiMovedPermanentlyResponse()301The requested resource has been moved permanently.
@ApiFoundResponse()302The requested resource has been found.
@ApiBadRequestResponse()400The request was invalid.
@ApiUnauthorizedResponse()401The request was unauthorized.
@ApiNotFoundResponse()404The requested resource was not found.
@ApiForbiddenResponse()403The request was forbidden.
@ApiMethodNotAllowedResponse()405The request method is not allowed.
@ApiNotAcceptableResponse()406The request is not acceptable.
@ApiRequestTimeoutResponse()408The request has timed out.
@ApiConflictResponse()409The request conflicts with the current state of the server.
@ApiPreconditionFailedResponse()412The request failed due to a precondition.
@ApiTooManyRequestsResponse()429The request was rejected due to rate limiting.
@ApiGoneResponse()410The requested resource is no longer available.
@ApiPayloadTooLargeResponse()413The request payload is too large.
@ApiUnsupportedMediaTypeResponse()415The request media type is not supported.
@ApiUnprocessableEntityResponse()422The request was well-formed but failed validation.
@ApiInternalServerErrorResponse()500The server encountered an internal error.
@ApiNotImplementedResponse()501The server does not support the functionality required to fulfill the request.
@ApiBadGatewayResponse()502The server received an invalid response from an upstream server.
@ApiServiceUnavailableResponse()503The server is currently unavailable.
@ApiGatewayTimeoutResponse()504The server timed out while waiting for a response.
@ApiDefaultResponse()200The default response.
apps/backend/src/plugins/{your_plugin_code}/example.controller.ts
import { ApiOkResponse } from '@nestjs/swagger'; 
import { Controllers } from 'vitnode-backend/helpers/controller.decorator';
 
@Controllers({
  plugin_name: 'Welcome',
  plugin_code: 'welcome',
  route: 'example',
})
export class ExampleWelcomeController {
  @Get()
  @ApiOkResponse({ description: 'Hello World!' }) 
  getHello(): string {
    return 'Hello World!';
  }
}

Responses with DTO

You can use DTO to define the response. This is useful when you want to return a complex object and show the structure of the response in the Swagger documentation.

apps/backend/src/plugins/{your_plugin_code}/example.controller.ts
import { ApiOkResponse } from '@nestjs/swagger';
import { Controllers } from 'vitnode-backend/helpers/controller.decorator';
import { ExampleResponseObj } from 'shared/plugins/{your_plugin_code}/example.dto'; 
 
@Controllers({
  plugin_name: 'Welcome',
  plugin_code: 'welcome',
  route: 'example',
})
export class ExampleWelcomeController {
  @Get()
  @ApiOkResponse({ type: ExampleResponseObj }) 
  getHello(): ExampleResponseObj {
    return { message: 'Hello World!' };
  }
}

On this page