Fastify, Why another JavaScript framework?
An introduction to the concepts and motivations behind the framework.
All of us know that the JavaScript ecosystem is builtin by several frameworks. In this article, I’ll show you a framework called Fastify and why it’s taken my attention.
Fastify is a web framework for Node.js focused in performance and low overhead, making it a great choice for those who are developing an architecture based on microservices.
We’re working to let the documentation even better. So, if you find any mistake, feel free to send a PR.
Benchmarks
Here comparing the http-router of others frameworks:
- find-my-way — (Fastify)
- routr — (Yahoo INC)
- koa-router — (Koa)
- express — (Express)
That’s because find-my-way uses an algorithm called radix tree under the hood to perform the routing, this is an exceptional performance factor compared to the others http-routers. I’ll talk about the algorithm itself in a future post.
More information about benchmarks can be found on the Fastify website, and the Nearform blog post.
In Fastify, Everything is a plugin!
Your routes, your utilities, everything is a plugin! Fastify uses an awesome design to avoid high coupling and thus make the asynchronous bootstrap of the plugins. Thanks to Avvio!
So, show the code!
First of all, let’s install Fastify:
$ npm i -S fastify
And now, let’s create the index.js
with our plugins:
As you can see in the above script:
- Row 1 - Initialize the Fastify.
- Row 3 - We create a Decorator (more about it bellow) and add a property called: *configuration.
- Row 8 - Register the plugin1.js.
- Row 10 - Register the plugin2.js.
- Row 12 - Initialize the http-router of Fastify to accept HTTP connections on port 3000.
And now our plugins:
At plugins, we receive the current context (Fastify instance) to work from this scope.
The Fastify provides us an API with several functionalities, among them (used in the code above): fastify.register
.
This API creates a new scope to encapsulate our plugin. Which will receive as dependency injection:
- fastify — Fastify instance in the current context.
- opts — options from register.
- next — Callback as any handler on express.
And fastify.decorate
. The decorate API has the power to define an attribute to the current instance of Fastify.
That’s the encapsulation, the changes will not spread to their parents, only to their children.
This feature allows us to obtain plugin inheritance along with the encapsulation, in this way, able to build a Direct Acyclic Graph(DAG).
Note that, in
plugin2.js
at line 5, it printed undefined because that context passed to the plugin does not contain that property. Encapsulation!
_“But, what if I need to add a property in the same context?”
The Fastify provides a plugin for that: fastify-plugin.
Why encapsulation is so important?
Fastify due to it’s encapsulation model avoids cross dependencies (Separation of Concerns). Therefore, it helps the maintenance/debugging of your application.
Following this model, we can break our application into several microservices at any time without having to refactor the entire project.
Schema Validation?
Validating the request parameters and documenting it at same time would be awesome, uh?
By default, Fastify makes use of Ajv for parameter validation and alongside the plugin fastify-swagger one can document while validating the data.
Let’s do an API with validation/documentation as an example.
First, we’ll install our dependencies:
npm i -S fastify-swagger
And so:
This is an fairly simple example just to show the plugins feature of Fastify and it’s standard validation with Ajv
(you can use the schema compiler that you want, Joi is a good one).
So, let’s go to the most important row:
-
Row 15: We register the route and associate a schema, and this structure above tell us that we’re expecting a
parameter in the query named
anyParam
which it’s type is number and this same field is required. So, at route / we expect a param of name anyParam of numeric type.
Therefore, if you start your server and go to /docs, you will see your route is already documented with Swagger. If you want to customize it further, read the documentation.
Now, let’s test the validation without passing the required param anyParam:
curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X GET http://localhost:3000/
It will return
{
"statusCode":400,
"error":"Bad Request",
"message":"querystring should have required property 'anyParam'"
}
Therefore, it’s validating property your required parameter. Now, we’ll send it, but as the wrong type (string):
curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X GET [http://localhost:3000/](http://localhost:3000/)?anyParam=stringQualquer
It will return
{
"statusCode":400,
"error":"Bad Request",
"message":"querystring.anyParam should be number"
}
As you can, the type is also validated. Finally, let’s send the correct request:
curl -i -H "Accept: application/json" \
-H "Content-Type: application/json" \
-X GET [http://localhost:3000/](http://localhost:3000/)?anyParam=10
{"ok":true}
Excellent, schema validated and documented!
Final considerations
I hope I got your curiosity about Fastify a little bit, and that you don’t follow the old herd behavior, and use express for everything.
Social networks: Github, Twitter.