đź“– Guide Documents
Core Library
TypedRoute

Outline

@nestia/core
export namespace TypedRoute {
  export function Get(path?: string): MethodDecorator;
  export function Post(path?: string): MethodDecorator;
  export function Put(path?: string): MethodDecorator;
  export function Patch(path?: string): MethodDecorator;
  export function Delete(path?: string): MethodDecorator;
}

Route decorators 200x faster, even type safe and easy to use.

TypedRoute is a namespaced module containing router decorators utilizing typia.assertStringify<T>() (opens in a new tab) function. Those decorators are almost same with original NestJS, but TypedRoute can boost up JSON serialization speed maximum 200x times faster than class-transformer, therefore much faster than original NestJS.

Furthermore, as TypedRoute utilizes typia.assertStringify<T>() (opens in a new tab) function, it is even type safe. The typia.assertStringify<T>() (opens in a new tab) function validates response data type, via typia.assert<T>() (opens in a new tab) function, before JSON serialization. Therefore, if you try to return wrong typed value, it would be blocked with 500 internal server error.

Moreover, TypedRoute is much easier than class-transformer, because it just needs only pure TypeScript type definition. If you can't understand the word "pure TypeScript type", then move to below #How to use section and read the IBbsArticle interface type. You may understand what it means.

If you want application/x-www-form-urlencoded type, use @TypedQuery.Post() instead.

⚠️

@TypedRoute.Get() is not essential for Swagger Documents or SDK Library building.

Therefore, it is not a matter to use @TypedRoute.Post() or @Post() of the original NestJS.

How to use

BbsArticlesController.ts
import { TypedRoute } from "@nestia/core";
import { Controller } from "@nestjs/common";
 
import { IBbsArticle } from "./IBbsArticle";
 
@Controller("bbs/articles")
export class BbsArticlesController {
  /**
   * Get random article for testing.
   */
  @TypedRoute.Get("random")
  public async random(): Promise<IBbsArticle> {
    return {
      id: "2b5e21d8-0e44-4482-bd3e-4540dee7f3d6",
      title: "Hello nestia users",
      body: "Just use `TypedRoute.Get()` function like this",
      created_at: "2023-04-23T12:04:54.168Z",
      files: [],
    };
  }
}

Just call @TypedRoute.${method}() function on the target method, that's all.

Nestia will analyze your type (IBbsArticle), and writes optimal code for the target type, in the compilation level. If you click the "Compiled JavaScript File" tab of above, you can see the optimal validation and JSON serialization code.

Such optimization is called AOT (Ahead of Time) compilation, and it is the secret of TypedRoute.

Special Tags

You can enhance validation logic, of TypedRoute, through comment tags.

You know what? @TypedRoute.${method}() functions are using typia.assertStringify<T>() (opens in a new tab) function, that is combined with typia.assert<T>() (opens in a new tab) and typia.stringify<T>() functions. It is the secret of @TypedRoute.${method}() functions, which can validates response body data type before JSON serialization, and throws 500 internal server error when the data type is not matched.

Also, as typia.assert<T>() (opens in a new tab) function can utililze comment tags for additional validation, TypedRoute also can utillze them, too. For reference, "Type Tag" means a intersection type with atomic type and special tag type of typia like number & tags.Type<"uint32">, and "Comment Tag" means a comment starting from @ symbol following @${name} ${value} format.

With those type and comment tags, you can add additional validation logics. If you want to add a custom validation logic, you also can do it. Read below Guide Docments of typia (opens in a new tab), and see the example code. You may understand how to utilize such type and comment tags, in a few minutes.

examples/src/is-special-tags.ts
import typia, { tags } from "typia";
 
export const checkSpecialTag = typia.createIs<SpecialTag>();
 
interface SpecialTag {
  int32: number & tags.Type<"int32">;
  range?: number & tags.ExclusiveMinimum<19> & tags.Maximum<100>;
  minLength: string & tags.MinLength<3>;
  pattern: string & tags.Pattern<"^[a-z]+$">;
  date: null | (string & tags.Format<"date">);
  ip: string & (tags.Format<"ipv4"> | tags.Format<"ipv6">);
  uuids: Array<string & tags.Format<"uuid">> &
    tags.MinItems<3> &
    tags.MaxItems<100>;
}

EncrypedRoute

@nestia/core
export namespace EncrypedRoute {
  export function Get(path?: string): MethodDecorator;
  export function Post(path?: string): MethodDecorator;
  export function Put(path?: string): MethodDecorator;
  export function Patch(path?: string): MethodDecorator;
  export function Delete(path?: string): MethodDecorator;
}

Encrypted router decorator functions.

EncryptedRoute is a namespaced module similar with TypedRoute, but it encrypts response body data through AES-128/256 CBC algorithm like below. Therefore, it would be slower than TypedRoute, but it guarantees the security of response body data.

  • AES-128/256
  • CBC mode
  • PKCS #5 Padding
  • Base64 Encoding

For reference, such encryption spec is not supported in the Swagger-UI. Instead, SDK (Software Development Kit) generated by @nestia/sdk supports it. Thus, you have to build and distribute the SDK library to the client developers when using such encryption decorators.

Benchmark

JSON

Comparing JSON serialization speed, typia (opens in a new tab) is maximum 200x faster than class-transformer.

For reference, Nestia is using typia, and NestJS is using class-transformer. The other one fast-json-stringify is made and used by fastify (do not mean NestJS fastify mode, but mean pure fastify library. NestJS fastify mode still utilizes class-transformer), and it requires JSON schema definition.

From above benchmark graph, you can see that class-transformer is extremely slower than others, even including built-in JSON.stringify() function. I can't understand why NestJS has adopted such slow and difficult library. The other fast-json-stringify is enough faster, but it needs extra schema definition like class-validator, therefore not easy to use.

Stringify Function Benchmark

Measured on AMD R9-7940HS, Rog Flow X13 (opens in a new tab)

Server

Looking at above benchmark, someone may ask:

JSON serialization speed affects on the server performance?

I think that the JSON serialization is just a tiny thing in the server side, isn't it?

My answer is, "Yes, it affects on the server performance".

Most operations in NodeJS server are asynchronously executed in background thread, what are called "event based non-blocking I/O model". However, JSON serialization is a synchronous operation running on the main thread. Therefore, if the JSON serialization speed is slow, it makes the entire server program slow.

I'll show you the benchmark result that, how JSON serizliation speed affects on the server performance.

Server Benchmark

Measured on AMD R9-7940HS, Rog Flow X13 (opens in a new tab)