Outline
Hello, I am developer of typia, and studying fastify
in nowadays.
During the study, I could understand why fastify
is faster than express
. Also, I did an experiment imitating the secret of the fastify
in express
with typia's faster JSON stringify function.
From the experiment (benchmark), I could get interesting result that express
became faster than fastify
. So I would like to share it with you.
Made
express
to be faster thanfastify
What typia is
// RUNTIME VALIDATORS
export function is<T>(input: unknown | T): input is T; // returns boolean
export function assert<T>(input: unknown | T): T; // throws TypeGuardError
export function validate<T>(input: unknown | T): IValidation<T>; // detailed
export const customValidators: CustomValidatorMap; // can add custom validators
// STRICT VALIDATORS
export function equals<T>(input: unknown | T): input is T;
export function assertEquals<T>(input: unknown | T): T;
export function validateEquals<T>(input: unknown | T): IValidation<T>;
// JSON
export function application<T>(): IJsonApplication; // JSON schema
export function assertParse<T>(input: string): T; // type safe parser
export function assertStringify<T>(input: T): string; // safe and faster
// +) isParse, validateParse
// +) stringify, isStringify, validateStringify
// MISC
export function random<T>(): Primitive<T>; // generate random data
export function clone<T>(input: T): Primitive<T>; // deep clone
export function prune<T extends object>(input: T): void; // erase extra props
// +) isClone, assertClone, validateClone
// +) isPrune, assertPrune, validatePrune
Before telling detailed stories, I'll introduce typia for a while.
It is a runtime validator library for TypeScript, which can perform above features just by only one line, just by utilizing pure TypeScript type. On the other hand, all of other alternative libraries require extra and duplicated schema definitions, which are different with the TypeScript type.
Furthermore, validation speed of typia is much faster than others. Comparing validation speed, typia is maximum 15,000x faster than class-validator
. When it comes to the JSON stringify function, typia is maximum 100x faster than class-transformer
and even type safe.
Secret of fastify
fastify is a competitive library of express
, which uses faster speed as a weapon.
And one of the reason why fastify
is faster than express
is, fast-json-stringify. fast-json-stringify
is another library what fastify
team had developed, which boosts up JSON conversion speed by analyzing JSON schema definition.
By using the fast-json-stringify
library, fastify
can serialize JSON string much faster than express
, and such difference makes fastify
to be faster than express
.
const fastJson = require('fast-json-stringify')
// REQUIRES JSON SCHEMA DEFINITION
const stringify = fastJson({
title: 'Example Schema',
type: 'object',
properties: {
firstName: {
type: 'string'
},
lastName: {
type: 'string'
},
age: {
description: 'Age in years',
type: 'integer'
},
reg: {
type: 'string'
}
}
});
// MAKES JSON SERIALIZATION FASTER
console.log(stringify({
firstName: 'Matteo',
lastName: 'Collina',
age: 32,
reg: /"([^"]|\\")*"/
}));
fast-json-stringify
is faster than nativeJSON.stringify()
function
Imitate secret of fastify
in express
import typia from "typia";
// PURE TYPESCRIPT TYPE
interface IPerson {
firstName: string;
lastName: string;
age: number; // Age in years
reg: RegExp;
}
// EASIER THAN ANY OTHER LIBRARIES
typia.stringify<IPerson>({
firstName: 'Matteo',
lastName: 'Collina',
age: 32,
reg: /"([^"]|\\")*"/
});
Studying source code of fastify
, I could understand why fastify
is faster.
By the way, typia has the same function like fast-json-stringify
. Therefore, imitating secret of fastify
was easily possible, too.
//----
// EXPRESS + TYPIA
//----
import express from "express";
import typia from "typia";
const server: express.Express = express();
const reply =
<T>(stringify: (input: T) => string | null) =>
(data: T) =>
(_req: express.Request, res: express.Response) =>
res
.status(200)
.header("Content-Type", "application/json")
.send(stringify(data));
// VERY EASY TO IMPLEMENT
server.get(
"/ObjectSimple",
reply(typia.createIsStringify<ObjectSimple[]>())
(storage.ObjectSimple),
);
Here is the code imitating fastify
library in express
with typia.
I think that my solution is much easier than fastify
, because typia does not require complicate JSON schema definition, and it just requires only pure TypeScript type.
Do you agree?
//----
// FASTIFY
//----
import fastify, { FastifyReply, FastifyRequest } from "fastify";
import typia from "typia";
const server = fastify();
const schema = (app: typia.IJsonApplication) => {
const definitions: Record<string, typia.IJsonSchema> = {};
for (const [key, value] of Object.entries(app.components.schemas))
definitions[key.replace("#/definitions/", "")] = value;
return {
schema: {
response: {
200: {
...app.schemas[0]!,
definitions,
},
},
},
};
};
const reply = (data: object) => (_i: FastifyRequest, o: FastifyReply) =>
o.send(data);
// DEFINING JSON SCHEMA IS A TERRIBLE WORK
// THEREFORE, I JUST USED typia.application() FUNCTION
server.get(
"/ObjectSimple",
schema(typia.application<[ObjectSimple[]], "ajv", "#/definitions">()),
reply(storage.ObjectSimple),
);
Also, to proceed experiment (benchmark) in the fastify
side, I wrote server code of fastify
, too. By the way, as defining JSON schema is a terrible work for me, I just generated the JSON schema data through typia.application()
function.
Measuring benchmark of those servers through autocannon (another library what fastify
team had built), I could get awesome result. express
became faster than fastify
in some cases, just by utilizing typia.stringify()
function.
express
became faster thanfastify
in some cases
Boost up your NestJS server speed
class-validator
andclass-transformer
are extremely slow
You know what? NestJS is utilizing class-validator
and class-transformer
. Do you remember? those libraries were slowest than any other libraries in the above benchmarks.
-
class-validator
is 15,000x times slower than typia -
class-transformer
is 100x times slower than typia
If you replace them to nestia (wrappers of typia for NestJS) supported decorators, you can boost up your NestJS developed backend server speed. Just by replacing some decorator functions like below, your server program would be much faster.
import { Controller } from "@nestjs/common";
import { TypedBody, TypedRoute } from "@nestia/core";
import type { IBbsArticle } from "@bbs-api/structures/IBbsArticle";
@Controller("bbs/articles")
export class BbsArticlesController {
/**
* Store a new content.
*
* @param inupt Content to store
* @returns Newly archived article
*/
@TypedRoute.Post() // 100x faster and safer JSON.stringify()
public async store(
// 15,000x faster validator
@TypedBody() input: IBbsArticle.IStore
): Promise<IBbsArticle>;
// do not need DTO class definition,
// just fine with interface
}
Also, with the nestia, you can build evolved swagger than swagger. Furthermore, you can build SDK library (like tRPC), therefore, client deevelopers can use your API much easily and safely like below.
Frontend developers would be happy
fastify
is still fast
Looking back above benchmark result, fastify
is faster than combination of express
and typia
, when response data is small. If making the reponse data much smaller, fastify
becomes always faster than express
+ typia
.
I just assume that fastify
has special optimized logic for header parsing, and reducing waiting time for each API call, but I don't know the exactly reason why. I need to study fastify
more, and also need to study express
, too.
I will fastify
continuously, and will come back again with the reason why.
Thanks for reading my article, and hope my article was enjoyable.
Links
- Github Repositories
- samchon
- fastify
- typestack
- Benchmark Program
- Benchmark Results
Top comments (39)
Nice work with typia, the job done has been amazing :)
Would you be willing to create a Fastify plugin for typia?
The results can be amazing! Happy to help you with it.
I’m part of Fastify team btw, in case you would like to share some thoughts or doubts about Fastify :)
Got it, I'll try at next Sunday (not tomorrow).
Anyway, where the plugin would be placed in? Just in my github account? Or as a fastify repo?
Sure thing!
Yeah, made everything within a repo of your authorship and once done, we can incorporate it at the list of community plugins :)
Feel free to ping me out if you want a second pair eyes!
What is your github accout name?
I will write an issue on
fastify
repo tagging you, and need to debate about below:At first,
fastify
provides plugin interfaces only through the JSON schema defition. Astypia
can generate JSON schema, it is possible to utilizing current plugin interface offastify
like above.However,
typia
is a transformer library generating optimal code in the compilation time, utilizing pure TypeScript type. To maximize strength oftypia
and make users to be much convenient, I think below code would be should be possible.The
typiaProvider.post<T>()
function will generate both type assertion (+ JSON serialization whenresponse
) and JSON schema definition for Swagger at the same time. Of course, above code requires modifications from plugin APIs offastify
. Therefore, I need to debate about it detaily as an issue.p.s) I'm developing protobuf features, therefore when
fastify
acceptstypia
as a plugin, you can easily support protobuf typed routers very easily.Hey! Please reach out in GH as
metcoder95
!Wow, that sounds interesting. What modifications are you looking for exactly?
In theory, the
fastify.register
should provide you access to the encapsulated context where the plugin is being added, and therefore decorate any possible route being register throughfastify.<post | get | ...>
.But please, open an issue at
fastify
repo and we can help you sorting things out :)Sorry for late.
I've been making guide documents of
typia
andnestia
in nowaydays, and such documentation works had consumed much more time than what I'd expected. Therefore, could not develop the plugin in this weekend.Anyway, stuyding
fastify
, I understood that there're enormous things to develop to adjust transform librarytypia
infastify
. There are already a lot of elements to be developed, so I'm going to make a fastifyplugin
like nestia, which can build SDK library.Please wait for one to two months, then I'll take interesting plugin.
Please, do not rush it. Happy to wait for the results, please let me know if you need any support or similar. Happy to support you with anything!
Currently, succeeded to support
fastify
throughnestia
inNestJS
.nestia.io/docs/
github.com/samchon/nestia/tree/mas...
Now, only "Swagger to NestJS" converter project is left for me. It may requires 2~3 weeks, and I'll start the pure fastify plugin project after that. Also, I'll run benchmark
fastify + typia
, too. Thanks for waiting.Hey! That's amazing! Don't worry about the plugin, take your time :)
So at this point I'm wondering if the benefits of nestia for Fastify can't be embedded upstream (as in making it fast by default when just using fastify)?
It would be nice if
JSON.stringify
function will be optimized on runtime level. And apparently this is doable.Wow, you're planning to send a PR?
It is huge effort. I can explain the idea some day :). It seems V8 devteam is not super interested in this now since they are busy enough with other stuff.
Is it really possible to enhance native
JSON.stringify()
function?Sure, let me give you a "strange" clue. You can take a look on history of how JSON serialization was improved in .NET world. Similar way native JS objects can have some internal methods for reading and writing from reader/writer objects (that hides content streaming under the hood). After that
JSON.stringify
andJSON.parse
are just tiny wrapper under internal JSON serialization pipeline. But again this work should be done in JS engine (v8 or deno). Hope this helps 😄Great article!
As I've promised, wrote an article introducing how to use
typia
inNestJS
.dev.to/samchon/nestia-boost-up-you...
잘보고 있습니다.!
엌... 태양토끼님 반갑읍니다
Hi. One thing I don't get in your benchmarks: in your Fastify code you are running with a schema validator, but in your Express code you are only replacing the default JSON parsing. How is that even comparable?
Benchmark program of current article does not have request body data. It has only response body data. Therefore, if your "schema validator" means a response data validation before JSON serialization, I wanna say that
typia.isStringify()
andtypia.assertStringify()
are doing it.Otherwise, you're meaning request DTO validation, and what you want to say is "this benchmark program does not handle request DTO validation", I want to introduce below article. Although below article's benchmark program is not measuring the pure request DTO validation logic of
fastify
, I think it may helpful for you.By the way, reading your comment, I think that I should enhance above linked article's benchmark program. I'll add
pure-fastify
component in the benchmark pogram, so that resolve your question clearly. By the enhancement, five componets would be compared:github.com/samchon/nestia/tree/mas...
Benchmark result
And how is the development of the plugin for fastify going?
Plan to start at 2023-09. Sorry for delaying
github.com/samchon/schedules/blob/...
Thanks, and do you intend to support SWC?
Not possible to support SWC, because it removes every types like Babel
Amazing work! I have one question: why did you create external dependencies instead of creating a pull request to the different projects mentioned (NestJS and Express)?
About NestJS
NestJS has used
class-validator
,class-transformer
and@nestjs/swagger
for many years.Unless those libraries have lots problems especially in productivity and performance, too much time have passed and strong dependencies had been occured.
Therefore, I think
nestia
can't be standard feature of NestJS, because of ordinary (legacy) projects.About Express
express
does not restrict any special validation and serialization logic.Therefore, whatever user choose, it is up to the user.
Sorry if I wasn't clear. What I meant was that even if NestJS is buried in old code, why not make a big pull request including the Nestia parts? It's a lot of work, but would improvde the DX of a lot of developers
Had tried very long time ago ToT.
I got answered that it would better to make a 3rd party library, and it is the
nestia
.github.com/samchon/nestia
I think you can 1.000.000x faster with you using protobuf
You must be a genius who can see the future.
Next version of typia will support protobuf features like below.
For example, I'll introduce a directory storing protobuf schema files generated by the next version of
typia.message<T>()
function:p.s) Protobuf is not such faster as you think. I'll come back with new benchmark after the next version.
I suggest you can use option on proto file for gen code. "option optimize_for = CODE_SIZE;"
Yes, current
typia.message<T>()
function writes too much long name. I need to make it shorter.How do these compare on deno instead of node?
Because I do not use deno, I do not know how it would be.
Also, deno does not support standard TypeScript compiler, it is hard (possible but not easy to configure) to test in the deno environment.
Deno dont support Typescript?
Dono does not support TypeScript compiler API
Hmm, so if you create a typia plugin for fastify so there's no way that express can beat fastify at all right?