πŸ“– Guide Documents
Core Library
TypedBody

Outline

@nestia/core
export function TypedBody(): ParameterDecorator;

Request body decorator 20,000x faster, even easy to use.

@TypedBody() is a decorator function parsing application/json typed request body, and validates the request body value type through typia.assert<T>() (opens in a new tab) function. If the request body is not following the promised type, 400 bad request error would be thrown.

It is almost same with original @Body() function of NestJS, however, 20,000x faster.

Also, @TypedBody() is much more easier to use than class-validator, because it can use pure TypeScript type. If you can't understand the word "pure TypeScript type", then move to below #How to use section and read the IBbsArticle.IUpdate interface type. You may understand what it means.

If you want other Content-Type, use one of below:

⚠️

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

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

How to use

BbsArticlesController.ts
import { TypedBody, TypedRoute } from "@nestia/core";
import { Controller } from "@nestjs/common";
import { tags } from "typia";
 
import { IBbsArticle } from "./IBbsArticle";
 
@Controller("bbs/articles")
export class BbsArticlesController {
  @TypedRoute.Post()
  public async store(
    @TypedBody() input: IBbsArticle.IStore,
  ): Promise<IBbsArticle> {
    return {
      ...input,
      id: "2b5e21d8-0e44-4482-bd3e-4540dee7f3d6",
      created_at: "2023-04-23T12:04:54.168Z",
    };
  }
}

Just call @TypedBody() function on the request body parameter, that's all.

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

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

Special Tags

You can enhance validation logic, of @TypedBody(), through special tags.

You know what? @TypedBody() utilizes typia.assert<T>() (opens in a new tab) function for request body data validation, and the typia.assert<T>() (opens in a new tab) function supports additional type checking logics through type and comment tags. 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>;
}

Configuration

tsconfig.json
{
  "strict": true,
  "strictNullChecks": true,
  "compilerOptions": {
    "plugins": [
      { "transform": "typia/lib/transform" },
      { 
        "transform": "@nestia/core/lib/transform",
        "validate": "valiateEquals",
        "stringify": "assert", 
      },
    ],
  },
}

Change type validation function to other one.

If you configure validate property of plugin defined in the tsconfig.json file, you can change the @TypedBody() to use another validation function instead of using the default typia.assert<T> (opens in a new tab) function. For example, if you want to use typia.validateEquals<T>() (opens in a new tab) function instead, then set the validate property to validateEquals.

Below is the list of available validation functions.

EncryptedBody

Encrypted request body decorator function.

@EncryptedBody() is a decorator function similar with @TypedBody(), but it encrypts the request body through AES-128/256-CBC algorithm like below. Therefore, it would be slower than @TypedBody(), but it guarantees the security of request 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

Super-fast and super-safe.

Nestia utilizes typia (opens in a new tab), and NestJS uses class-validator. One thing amazing is, typia is maximum 20,000x faster than class-validator of NestJS. Color of class-transformer is skyblue, and can you find the skyblue color in the below benchmark graph? It may hard to find because class-validator is extremely slow.

Assert Function Benchmark

Measured on Intel i5-1135g7, Surface Pro 8 (opens in a new tab)

Furthermore, while other libraries can't validate complicate union types, typia can validate every TypeScript types. However, in the class-validator case, it always be failed when any type of complicate comes. I can't understand why NestJS has adopted such slow and unstable library.

Moreover, only typia can utilize pure TypeScript type, without any extra schema definition. Beside, all of other libraries require extra and duplicated schema definition, different with pure TypeScript type. Nestia is using such wonderful, super-fast and super-fast typia library.

ComponentstypiaTypeBoxajvio-tszodC.V.
Easy to useβœ…βŒβŒβŒβŒβŒ
Object (simple) (opens in a new tab)βœ”βœ”βœ”βœ”βœ”βœ”
Object (hierarchical) (opens in a new tab)βœ”βœ”βœ”βœ”βœ”βœ”
Object (recursive) (opens in a new tab)βœ”βŒβœ”βœ”βœ”βœ”
Object (union, implicit) (opens in a new tab)βœ…βŒβŒβŒβŒβŒ
Object (union, explicit) (opens in a new tab)βœ”βœ”βœ”βœ”βœ”βŒ
Object (additional tags) (opens in a new tab)βœ”βœ”βœ”βœ”βœ”βœ”
Object (template literal types) (opens in a new tab)βœ”βœ”βœ”βŒβŒβŒ
Object (dynamic properties) (opens in a new tab)βœ”βœ”βœ”βŒβŒβŒ
Array (rest tuple) (opens in a new tab)βœ…βŒβŒβŒβŒβŒ
Array (hierarchical) (opens in a new tab)βœ”βœ”βœ”βœ”βœ”βœ”
Array (recursive) (opens in a new tab)βœ”βœ”βœ”βœ”βœ”βŒ
Array (recursive, union) (opens in a new tab)βœ”βœ”βŒβœ”βœ”βŒ
Array (R+U, implicit) (opens in a new tab)βœ…βŒβŒβŒβŒβŒ
Ultimate Union Type (opens in a new tab)βœ…βŒβŒβŒβŒβŒ

C.V. means class-validator