Fastify is a framework for backend web development with a powerful plugin architecture and the least overhead. It’s primarily inspired by Hapi and Express and is one of the fastest web frameworks running on Node.js.
Fastify v3.0 is the latest version and has been available since early July 2020. Version 3 has some exceptional new functionalities such as:
Now that we’ve covered Fastify’s latest version update functionalities, let’s review a shortlist of Fastify’s most important features:
Depending on code complexity, it can serve around 30,000 requests per second or more for less complex business logic
Hooks, plugins, and decorators make it fully extensible
Internally, Fastify compiles a JSON schema to a highly performant function that can be used for route validation and output serialization
Pino is a highly cost-effective logger used for faster logging
The framework is expressive and easy to get started with. Furthermore, it allows developers to quickly scale small projects to larger performant applications without sacrificing performance or security
The TypeScript type declaration file maintains support to the TypeScript community
Besides the vast amount of features that Fastify offers, it also has a strong plugin architecture. Any developer can build plugins that work with Fastify to create quick building blocks for bootstrapping your API project.
Plugins developed by external developers fall under the category of “community plugins,” while the Fastify team also maintains some plugins of their own, which they label as “core plugins.” However, it’s important to know that any community plugin must adhere to Fastify’s best practices.
The benefit of using core plugins is that the Fastify team actively maintains those plugins, but keep in mind that community plugins may not be maintained.
Here are some important Fastify plugins to note:
And that’s not even a comprehensive list. Fastify has a wide range of plugins to choose from.
Each framework, of course, has its pros and cons — but each framework also has its application. It’s not easy to compare diverse frameworks. However, I tried to select relevant evaluation criteria for when you are choosing a framework.
Here’s an overview of the speed comparison by StackShare.io.
Express: Express processes the least amount of request/sec. The benchmark proves that Express can handle 15,978 requests/sec
Koa: Koa is a better option than Express. It’s also a lightweight framework that handles 54,848 requests/sec
Fastify: Fastify received the best benchmark results with 78,956 requests/sec
As discussed in the previous section, Fastify is the only web framework of these three that has a wide range of plugins, and it makes a major difference. It’s a big plus for developers because they don’t have to rely on multiple frameworks or packages to build their applications. Fastify becomes the one-stop solution.
Again, Fastify is the only framework that has TypeScript support out of the box. Depending on your Node.js version, you may need to install @types/node
.
And now, the exciting part! This tutorial will guide you through building your first server with Fastify, covering the following aspects:
Ready? Let’s begin.
First, start a new npm project using:
npm init -y
Next, let’s add the Fastify dependency to your project.
Using npm:
npm i fastify --save
Using yarn:
yarn add fastify
Make sure to have the latest Node.js version installed on your system. You can use nvm (Node Version Manager) for quickly switching between different Node.js versions. You’ll also need a tool to send requests such as cURL or Postman.
Next, let’s create a new file called server.js
in the root of your project. Add the following code to your server.js
file:
const fastify = require('fastify')({ logger: true }) //Add routes here, discussed in further steps //@Server fastify.listen(5000, (err) => { if (err) { console.log(err) process.exit(1) } else { console.log(`Server running, navigate to https://localhost:5000`) } })
As you can see, the listen function starts the server on port 5000
. It also accepts a callback that accepts one argument, which can contain an error object. This is the most basic server setup for running a Fastify API.
If you want to try out this basic setup, you can use the node
command to run the server.js
file like this:
node server.js
This will start your server on the address http://localhost:5000. If you try navigating to the address, you’ll see an error that this route doesn’t exist because we haven’t defined any routes yet. Now we’ll need to add some simple CRUD routes.
Let’s add some basic CRUD routes to our application. First, let’s add a GET route.
Imagine we have a stack object that’s a type array. First, we want to add a GET route to retrieve the contents of this array. To do so, we can use the Fastify object to define a get
route. The first argument accepts the path we want to attach our route to and the second argument accepts a callback that sends back a reply to your client.
const stack = [] //@Routes fastify.get('/getStack', (request, reply) => { reply.send(stack) })
Next, let’s try adding items to our stack array using a POST route. This way, we can send data with our request. Here we expect the user to send a JSON object with one parameter called item
. We push this item
to our stack array. Now we can use the first argument of the callback request
, which contains the data being sent with the POST request.
fastify.post('/addItem', (request, reply) => { const item = request.body.item stack.push(item) reply.send(stack) })
The same principles apply for other route methods such as PUT, DELETE, HEAD, PATCH, and OPTIONS. More information about route options can be found in the Fastify documentation.
Your final routing code should look like this:
const fastify = require('fastify')({ logger: true }) const stack = [] //@Routes fastify.get('/getStack', (request, reply) => { reply.send(stack) }) fastify.post('/addItem', (request, reply) => { const item = request.body.item stack.push(item) reply.send(stack) }) //@Server fastify.listen(5000, (err) => { if (err) { console.log(err) process.exit(1) } else { console.log(`Server running, navigate to https://localhost:5000`) } })
Now let’s try out the code we’ve created. First, start the server with node server.js
. Next, visit the following route http://localhost:5000/getStack, which should return an empty array object.
Let’s add an item to the stack using cURL. I want to add an apple to the stack. Therefore, I send a JSON object with key item
and value apple
.
curl --header "Content-Type: application/json" --request POST --data '{"item": "apple"}' http://localhost:5000/addItem
If you visit http://localhost:5000/getStack again, you’ll notice that the stack array is populated with the apple
item.
All good? Let’s add a plugin!
To demonstrate how easy it is to add and use a Fastify plugin, let’s install fastify-routes, which enables us to retrieve a map of all registered routes with our Fastify instance.
First, install the Fastify-routes dependency from the CLI:
npm i fastify-routes
After installing the plugin, register the plugin by including it before you register any routes.
Here’s a snippet of the server.js
file that includes the fastify-routes
plugin. I’ve also added a console.log
statement that shows how you can use the plugin to return all registered routes.
const fastify = require('fastify')({ logger: true }) fastify.register(require('fastify-routes')) // Add and register plugin const stack = [] //@Routes fastify.get('/getStack', (request, reply) => { reply.send(stack) }) fastify.post('/addItem', (request, reply) => { const item = request.body.item stack.push(item) reply.send(stack) }) //@Server fastify.listen(5000, (err) => { console.log(fastify.routes) // Log all registered routes if (err) { console.log(err) process.exit(1) } else { console.log(`Server running, navigate to https://localhost:5000`) } })
Now when you start the server with node server.js
, your CLI prints all registered routes.
This plugin demonstrates how easy it is to add a plugin to your server. You don’t need to initialize them. The fastify
object that forms your server also acts as the parent for all the registered plugins, and you can call them directly from this fastify
object.
Finally, let’s add some basic data validation to our server.
As the final element in this tutorial, let’s add data validation to your routes. Specifically, we want to add validation for the POST route we created earlier. Let’s validate if the body object contains the item
property and the type of data should match a string
type.
Luckily, Fastify allows us to define validation schemas for routes. Here’s an example that verifies if the item
property is present and contains a string
. Furthermore, we tell the Fastify server that we don’t allow any additional properties on the body object using the additionalProperties: false
setting.
You can also define a response property that describes the response when the request is successful.
Here’s the full code after adding the data validation options. Do not forget to add the itemValidation
as the second argument to the POST route.
const fastify = require('fastify')({ logger: true }) fastify.register(require('fastify-routes')) const itemValidation = { // Define validation schema: { body: { type: 'object', additionalProperties: false, required: [ 'item' ], properties: { item: { type: 'string' } } }, response: { 201: { type: 'object', properties: { item: { type: 'string' } } } } } } const stack = [] //@Routes fastify.get('/getStack', (request, reply) => { reply.send(stack) }) fastify.post('/addItem', itemValidation, (request, reply) => { // Add validation options to POST route const item = request.body.item stack.push(item) reply.send(stack) }) //@Server fastify.listen(5000, (err) => { console.log(fastify.routes) if (err) { console.log(err) process.exit(1) } else { console.log(`Server running, navigate to https://localhost:5000`) } })
Let’s try out the code again by sending the same request to our server, adding the apple
item. This request should be successfully executed.
curl --header "Content-Type: application/json" --request POST --data '{"item": "apple"}' http://localhost:5000/addItem
Next, let’s try sending an item that contains an empty object so we can test if the server rejects the request. Send the below request to your server to verify the data validation implementation.
curl --header "Content-Type: application/json" --request POST --data '{"item": {}}' http://localhost:5000/addItem
The server should send you the following error message:
{"statusCode":400,"error":"Bad Request","message":"body.item should be string"}
All good? Congratulations! You’ve successfully completed your first Fastify API server.
I hope you enjoyed building a simple CRUD API using Fastify while implementing data validation and adding plugins.
Many more plugins exist, so definitely check out the Fastify plugin ecosystem to see what’s available. Plugins are useful to quickly bootstrap your API, removing the need to build an API from scratch.
Feel free to check out the following concepts Fastify offers:
That’s it, folks! Full code can be found on my GitHub repository.
Install LogRocket via npm or script tag. LogRocket.init()
must be called client-side, not
server-side
$ npm i --save logrocket // Code: import LogRocket from 'logrocket'; LogRocket.init('app/id');
// Add to your HTML: <script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script> <script>window.LogRocket && window.LogRocket.init('app/id');</script>
Hey there, want to help make our blog better?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowBuild scalable admin dashboards with Filament and Laravel using Form Builder, Notifications, and Actions for clean, interactive panels.
Break down the parts of a URL and explore APIs for working with them in JavaScript, parsing them, building query strings, checking their validity, etc.
In this guide, explore lazy loading and error loading as two techniques for fetching data in React apps.
Deno is a popular JavaScript runtime, and it recently launched version 2.0 with several new features, bug fixes, and improvements […]