Michiel Mulders Michiel loves the NodeJS and Golang programming languages. A backend/core blockchain developer and avid writer, he's very passionate about blockchain technology.

How to build a blazingly fast API with Fastify

7 min read 2033

Fastify API server

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:

  • Running an Express application inside Fastify
  • Changes in logging serialization
  • Changes in schema substitution
  • Better TypeScript support

An overview of Fastify’s features

Now that we’ve covered Fastify’s latest version update functionalities, let’s review a shortlist of Fastify’s most important features:

High performance

Depending on code complexity, it can serve around 30,000 requests per second or more for less complex business logic

Extendibility

Hooks, plugins, and decorators make it fully extensible

Scheme-based

Internally, Fastify compiles a JSON schema to a highly performant function that can be used for route validation and output serialization

Logging

Pino is a highly cost-effective logger used for faster logging

Developer-friendly environment

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

TypeScript-ready

The TypeScript type declaration file maintains support to the TypeScript community

5 important Fastify plugins you should know

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.

We made a custom demo for .
No really. Click here to check it out.

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:

  • fastify-auth: An authentication plugin developed by the Fastify team that allows you to quickly inject authentication logic to your API routes
  • fastify-cors: Cross-origin requests are important for any application, and fastify-cors helps you manage this without the need for installing a CORS package separately
  • fastify-jwt: This plugin will decorate your application with standard JSON web token. Fastify-jwt internally uses the jsonwebtoken package
  • fastify-nextjs: Next is a React framework for building pre-rendering websites at the server-side. This plugin helps you do the same with Fastify
  • fastify-redis: This enables your Fastify application to share the same Redis connection throughout the server

And that’s not even a comprehensive list. Fastify has a wide range of plugins to choose from.

Fastify vs Koa vs Express

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.

Speed comparison

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

Plugins ecosystem

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.

TypeScript support

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.

Creating your first server with Fastify 3.0

And now, the exciting part! This tutorial will guide you through building your first server with Fastify, covering the following aspects:

  1. Installation
  2. Run your first server
  3. Add routes to your API
  4. Use Fastify plugins
  5. Add data validation capabilities

Ready? Let’s begin.

1. Installation and requirements

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.

2. Create server.js

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.

3. Adding CRUD routes

Let’s add some basic CRUD routes to our application. First, let’s add a GET route.

3.1 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)
})

3.2 POST route

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.

3.3 Final routing code

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!

4. Add a plugin to your Fastify API

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.

5. Add data validation

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.

Conclusion

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.

: Full visibility into your web apps

LogRocket is a frontend application monitoring solution that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.

In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page apps.

.
Michiel Mulders Michiel loves the NodeJS and Golang programming languages. A backend/core blockchain developer and avid writer, he's very passionate about blockchain technology.

Leave a Reply