Outline
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
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.
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
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
{
"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.
stringify
:typia.json.stringify<T>()
assert
:typia.json.assertStringify<T>()
is
:typia.json.isStringify<T>()
validate
:typia.json.validateStringify<T>()
validate.log
:typia.json.validateStringify<T>()
, but do not throw error and just log itnull
: just useJSON.stringify()
function without validation
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.
- Supported schemas
"chatgpt"
: (IChatGptSchema
), OpenAI ChatGPT"claude"
: (IClaudeSchema
), Anthropic Claude"gemini"
: (IGeminiSchema
), Google Gemini"llama"
: (ILlamaSchema
), Meta Llama
- Midldle layer schemas
"3.0"
: (ILlmSchemaV3
), middle layer based on OpenAPI v3.0 specification"3.1"
: (ILlmSchemaV3_1
), middle layer based on OpenAPI v3.1 specification
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.
typia
needs only pure TypeScript type.class-transformer
requires DTO class with decorator function calls.fast-json-stringify
requires JSON schema definition.
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.
Measured on AMD R9-7940HS, Rog Flow X13