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>() 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>() function, it is even type safe. The typia.assertStringify<T>() function validates response data type, via typia.assert<T>() 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>() function, that is combined with typia.assert<T>() 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>() 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, 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.

Configuration

tsconfig.json
{
  "compilerOptions": {
    "strict": true,
    "plugins": [
      { "transform": "typia/lib/transform" },
      {
        "transform": "@nestia/core/lib/transform",
        "stringify": "assert",
        // "llm": {
        //   "model": "chatgpt",
        //   "strict": true,
        // },
      }
    ]
  }
}

Change JSON serializer to another one.

If you configure stringify property of plugin defined in the tsconfig.json file, you can change the @TypedRoute module to utilize another JSON serialization function instead of the default typia.json.assertStringify<T>() function. For example, if you change the property to "validate", the JSON serialization function of @TypedRoute module be changed to typia.json.validateStringify() function.

Here is the list of available options.

By the way, this is not a recommended way, but you can skip the response type validation for. If you set the stringify property to null, the response type validation will be skipped and just JSON.stringify() function be used.

Also, validate.log performs the validation, but does not throw 500 internal server error. When type error be detected, it seralizes response data by JSON.stringify() function, and logs the error message to the console or somewhere you’ve specified. It is useful when you want to know the error message, but do not want to throw 500 internal server error to the client application.

TypedRoute.setValidateErrorLogger((err: TypedRoute.IValidateErrorLog) => {
  // you can customize the validation error logging
  console.error(err);
});

Additionally, if you configure llm property of the plugin, @nestia/core considers that your backend application has been developed for LLM function calling, and validates the request/response body types following the target LLM model’s restrictions.

For example, if you configure chatgpt with strict option, dynamic properties and optional properties are not allowed in the request/response body types. If your some request/response body types are not following the target LLM model’s restrictions, @nestia/core will throw a compilation error.

Here is the list of available LLM models. Read their definitions, and follow their restrictions.

Benchmark

JSON

Comparing JSON serialization speed, typia 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

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