A Fast Node.js Framework: Fastify Explained

Fastify is a responsive Node.js framework whose design emphasizes performance and flexibility. Influenced by predecessor frameworks such as Express.js, it incorporates async/await. More modern development is possible, such as support.In this article, we will explain in detail the characteristics of Fastify and its advantages.

overview

Fastify is a Node.js web framework designed for speed and low overhead, with a focus on performance and flexibility.

Fastify’s capabilities include support for routing, request and response processing, and input validation. It also has a plugin-based architecture, making it easy for developers to extend its functionality.

Fastify is based on hapi and Express.js, and is designed to return responses at high speed when building an API that returns JSON as a response.

Here, we will introduce the basic usage of Fastify using the following versions.

Fastify v4.0.0
nodejs v19.7.0

Basic concept of Fastify

Routing

Routing is a mechanism for receiving HTTP requests from clients and processing them accordingly. Fastify can use router objects to accurately match requests for different URL paths and HTTP methods.

const fastify = require('fastify');

const app = fastify();

// define route for GET method
app.get('/', (request, reply) => {
  reply.send('Hello, world!');
});

// Define route for POST method
app.post('/users', (request, reply) => {
  const { name, email } = request.body;
  // process user data and return response
  reply.send({ message: `User created: ${name} (${email})` });
});

// route definition with parameters
app.get('/users/:id', (request, reply) => {
  const userId = request.params.id;
  // get user data from a database or other source
  const user = { id: userId, name: 'Taro Yamada' };
  reply.send(user);
});

// start the server
app.listen({ port:3000 }, (err) => {
  if (err) {
    console.error('An error occurred while starting the server:', err);
    process.exit(1);
  }
  console.log('Server started on port 3000');
});

The above example creates a Fastify server and shows an example of routing. A route for the GET method, a route for the POST method, and a route with parameters are defined. In each route’s handler function, we process the request and return the appropriate response. Finally, we are starting the server on the specified port.

Handler

In Fastify, handler functions define what to do with routed requests. A handler is responsible for receiving a request, performing the necessary processing, and returning a response.

Below is an example of a handler in Fastify.

const fastify = require('fastify');

const app = fastify();

// define a handler for the GET method
app.get('/', async (request, reply) => {
  try {
    // Execute an asynchronous function to process the request
    const data = await getDataFromDatabase();
    reply.send(data);
  } catch (error) {
    console.error('An error has occurred:', error);
    reply.status(500).send('An error occurred');
  }
});

// define handler for POST method
app.post('/users', (request, reply) => {
  const { name, email } = request.body;
  // process user data
  if (!name || !email) {
    reply.status(400).send('Name and email are required');
  } else {
    // store and process data
    saveUserData(name, email);
    reply.send({ message: `User created: ${name} (${email})` });
  }
});

// start the server
app.listen({ port:3000 }, (err) => {
  if (err) {
    console.error('An error occurred while starting the server:', err);
    process.exit(1);
  }
  console.log('Server started on port 3000');
});

// Example of an asynchronous function that retrieves data from the database
async function getDataFromDatabase() {
  // Execute database access asynchronous processing
  return await db.query('SELECT * FROM users');
}

// Example of processing to save user data
function saveUserData(name, email) {
  // data save processing
  // ...
}

The example above defines handlers for the GET and POST methods. The GET method handler uses an asynchronous function to retrieve data from the database and return it as a response. The POST method handler obtains the necessary data from the request body and performs validation and data storage processing.

Inside the handler function, we use async and await for asynchronous processing of requests, and try-catch syntax for error handling. If an error occurs, the appropriate status code and error message are returned as a response.

Here are some examples of handlers in Fastify. This allows you to implement any logic you want inside the handler function, such as handling requests or manipulating data.

Plugin

I will explain the concept of plugins in Fastify with an example of how to use plugins.

const fastify = require('fastify');
const cors = require('fastify-cors');

const app = fastify();

// register the plugin
app.register(cors, {
  origin: '*',
  methods: ['GET', 'POST'],
});

// route definition
app.get('/', (request, reply) => {
  reply.send('Hello, World!');
});

// start the server
app.listen({ port:3000 }, (err) => {
  if (err) {
    console.error('An error occurred while starting the server:', err);
    process.exit(1);
  }
  console.log('Server started on port 3000');
});

In the example above, we are using a plugin called fastify-cors to add CORS (Cross-Origin Resource Sharing) functionality to our Fastify application. Register the plugin using the app.register() method and specify the desired options.

In this example, we are using the fastify-cors plugin to allow requests from all origins and only GET and POST methods. This allows your application to make cross-origin requests.

Plugins are a convenient way to add and customize functionality. There are various plugins in Fastify’s ecosystem to easily add features such as authentication, logging, database connectivity, etc. This allows you to extend the functionality of your application as needed.

Schema and Validation

Fastify provides functionality to validate requests using JSON Schema. By using a schema, you can define request parameters, bodies, query parameters, etc. and apply validation rules. This allows you to easily check the integrity of your input data.

Response handling: Fastify also gives you flexibility in how you handle responses. For example, you can return responses in different formats. Fastify supports different types of responses such as JSON, HTML and binary data.

const fastify = require('fastify');

const app = fastify();

// JSON schema definition
const userSchema = {
  type: 'object',
  properties: {
    name: { type: 'string' },
    age: { type: 'integer', minimum: 0 },
    email: { type: 'string', format: 'email' },
  },
  required: ['name', 'email'],
};

// Define route and apply validation for POST method
app.post('/users', {
  schema: {
    body: userSchema,
  },
}, (request, reply) => {
  const { name, age, email } = request.body;

  // process user data
  const userData = { name, age, email };

  // send response
  reply.send(userData);
});

// start the server
app.listen({ port:3000 }, (err) => {
  if (err) {
    console.error('An error occurred while starting the server:', err);
    process.exit(1);
  }
  console.log('Server started on port 3000');
});

The example above uses Fastify’s JSON schema to validate the request. An object called userSchema defines the user data schema. Each property specifies data type and validation rules.

The route definition for the POST method uses the schema option to set the validation of the request body. By specifying the userSchema defined earlier in the body property, it will be verified whether the request body data matches the schema.

Inside the handler, I am getting the request body data and doing some user data processing. When sending the resulting data as a response, Fastify will automatically generate the response in JSON format.

Fastify also gives you flexibility in how you handle responses. For example, when you send an object or array using the reply.send() method, Fastify will automatically convert it to JSON format and return it to the client. Additionally, Fastify supports different types of responses and allows you to create custom responses such as HTML or binary data.

This allows you to use Fastify to validate requests and generate flexible responses.

Processing the response

Fastify also gives you flexibility in how you handle responses. For example, you can return responses in different formats. Fastify supports different types of responses such as JSON, HTML and binary data.

Let’s take a look at handling responses, with code examples for returning different types of responses in Fastify.

const fastify = require('fastify');

const app = fastify();

// JSON response example
app.get('/api/users', (request, reply) => {
  const users = [
    { id: 1, name: 'John Doe' },
    { id: 2, name: 'Jane Smith' },
    { id: 3, name: 'Bob Johnson' }
  ];
  reply.send(users);
});

// HTML response example
app.get('/about', (request, reply) => {
  const htmlContent = `
    <html>
      <head>
        <title>About Us</title>
      </head>
      <body>
        <h1>About Us</h1>
        <p>Welcome to our website!</p>
      </body>
    </html>
  `;
  reply.type('text/html').send(htmlContent);
});

// binary data example
app.get('/image', (request, reply) => {
  const imagePath = 'path/to/image.jpg';
  reply.type('image/jpeg').sendFile(imagePath);
});

// start the server
app.listen({ port:3000 }, (err) => {
  if (err) {
    console.error('An error occurred while starting the server:', err);
    process.exit(1);
  }
  console.log('Server started on port 3000');
});

The above examples show how to return responses in different formats.

  1. JSON response example: A GET request to the /api/users path will return a response containing user data in JSON format.

  2. HTML response example: A GET request to the /about path will return a response containing HTML content. You are specifying the content type using reply.type('text/html').

  3. Binary data example: If there is a GET request to the /image path, the binary data of the specified image file will be returned as a response. You are specifying the content type using reply.type('image/jpeg').

As you can see from these examples, Fastify supports different types of responses. You can also easily return responses by using reply.send() or reply.sendFile(). It is also possible to specify the content type if necessary.

Features of Fastify

Asynchronous processing and event-driven architecture:

Fastify employs an asynchronous processing and event-driven architecture leveraging Node.js’s EventEmitter. This allows requests to be processed in parallel at the same time. Compared to traditional synchronous web frameworks, Fastify offers asynchronous processing flexibility and efficiency. With its event-driven architecture, Fastify takes full advantage of the event loop’s properties to efficiently handle asynchronous processing of requests. This allows multiple requests to be processed simultaneously, resulting in faster response times and better scalability.

Low overhead and resource optimization

Fastify is a very lightweight framework that minimizes the overhead required to process HTTP requests and responses. This allows efficient use of system resources and can effectively respond to server load.

In addition, Fastify also focuses on resource optimization. Detail optimizations such as dependency management and memory usage optimizations. This allows Fastify applications to run fast and efficiently, providing highly scalable performance.

Let’s check the benchmark on the official website to see how good it is.

Excellent scalability

Fastify has a plugin system that makes it easy to customize and extend. Using various plug-ins makes it easy to add functionality and incorporate modules. Also, plugins can be added or removed without restarting the application.

Strict schema-based validation

Fastify uses JSON schemas to validate requests. Schema-based validation rules can be applied to ensure the integrity of request and response data. This allows for reliable data processing.

Rich ecosystem and documentation

Fastify has an active community and a wealth of plugins and tools available. The official documentation is detailed and substantial, and it supports a wide range of users from beginners to advanced users. In addition to the official documentation, there are plenty of resources such as tutorials and sample code.

Fastify vs Express.js

Fastify and Express.js are both popular Node.js-based web frameworks, but each has different characteristics. In this article, we’ll compare Fastify and Express.js and take a closer look at each framework’s advantages and appropriate use cases.

Speed ​​and efficiency

Fastify is known as a fast and efficient framework. Asynchronous processing and an event-driven architecture ensure excellent performance even under heavy loads. On the other hand, Express.js is also very popular, but a bit slower than Fastify. Fastify is optimized internally and works with low overhead, so it’s especially good when you need fast processing.

Conclusion: Fastify provides fast performance and has great efficiency in high load environments.

Extensibility and plugin ecosystem

Fastify has great scalability. By utilizing the plugin system, you can easily add and customize functions. A wealth of official and community-provided plugins are available to easily add features such as authentication, logging, and database connectivity.

Express.js, on the other hand, is a simpler framework and its extensibility is more limited than Fastify. Plugins exist for Express.js, but they don’t have as wide a plugin ecosystem as Fastify.

Conclusion: Fastify offers a great plugin ecosystem for extensibility and flexibility.

Learning curve and speed of development

Express.js is a very simple framework that has a relatively short learning curve and is easy to handle for beginners. The development speed is also high, and applications can be built quickly.

Fastify, on the other hand, has a slightly steeper learning curve and requires more in-depth knowledge and understanding. This is due to Fastify optimizing for speed and efficiency. Fastify may take some time to learn, but the trade-off is the ability to build high-performance applications.

Conclusion: Express.js has a shorter learning curve and faster development speed, while Fastify has a slightly steeper learning curve, but allows you to build fast and efficient applications.

Use case

Fastify is ideal for high-performance scenarios such as fast API servers, microservices, and real-time applications. Especially when large traffic or real-time data processing is required, the advantages of Fastify become more pronounced.

Express.js, on the other hand, is primarily used for simple application and prototype development and middleware processing. For small or monolithic applications, Express.js will do just fine.

Conclusion: Fastify is good for high performance applications and Express.js is good for simple applications and middleware usage.

summary

Fastify is currently supported by nearForm and LetzDoIt.

Fastify is a very useful framework when developing web applications because it is fast, highly extensible, and offers additional features such as JSON schema validation and TypeScript support. However, it should be noted that the Japanese documentation is scarce and the test function is not the default.

Compared to Express.js, Fastify has better performance and offers great features such as plugin encapsulation to avoid conflicts, faster JSON parsing, and a cleaner implementation of asynchronous operations.

However, it doesn’t have the rich documentation and module support of Express.js, making it a better framework for individual development and small development teams.