How to use routing with Fastify

overview

Fastify provides the ability to easily define routes. Routing is defined by specifying endpoints for handling HTTP requests.

Below, we’ll explore routing concepts, defining routes, creating route handlers, handling routing parameters, and options for routes in more detail.

Here, we will explain the routing method using the following versions.

Fastify v4.0.0
nodejs v19.7.0

Also, all the code I’ve created so far is listed below. https://github.com/wiblok/Fastify

Routing concepts

Routing defines how your Fastify application handles requests from clients when they reach a particular endpoint.

Routing is defined by a combination of HTTP methods (GET, POST, PUT, DELETE, etc.) and paths (URLs).

How to define routes

There are several ways to use routing, but the four most common are:

  1. How to use the short method
fastify.'<HTTP method>'({'<path>', async (request, reply) => {
  // handling routes
}});
  1. Using the fastify.route() method
fastify.route({
  method: '<HTTP method>',
  url: '<path>',
  handler: async (request, reply) => {
    // handling routes
  }
});
  1. How to use the route handler function directly
const routeHandler = async (request, reply) => {
  // handling routes
};
fastify.<HTTP method>('<path>', routeHandler);
  1. How to use root options
const routeOptions = {
  method: '<HTTP method>',
  url: '<path>',
  handler: async (request, reply) => {
    // handling routes
  }
};
fastify.route(routeOptions);
  • HTTP method: Specify the HTTP request method (eg get, post, put, delete, etc.).
  • Path: Specifies the URL path that requests from clients will match.

From the heading below, write the code.

How to use short methods

short.js

const fastify = require("fastify")();

fastify.get("/hello", async (request, reply) => {
  return "Hello, Fastify!";
});

fastify.post("/users", async (request, reply) => {
  const user = request.body;
  // user creation, etc...
  return { id: 1, name: user.name };
});

fastify.put("/users/:id", async (request, reply) => {
  const userId = request.params.id;
  const user = request.body;
  // user updates, etc...
  return { id: userId, name: user.name };
});

fastify.delete("/users/:id", async (request, reply) => {
  const userId = request.params.id;
  // user deletion etc...
  return { message: `User ${userId} has been deleted.` };
});

fastify.listen({ port: 3000 }, (err) => {
  if (err) {
    console.error("Error starting server:", err);
    process.exit(1);
  }
  console.log("Server started on port 3000");
});

Commentary

  • Create a Fastify instance
const fastify = require("fastify")();

Import the Fastify module and create an instance of it.

  • Handling GET requests:
fastify.get("/hello", async (request, reply) => {
  return "Hello, Fastify!";
});

Handles GET requests to the path /hello. When a request comes in, it responds with the string “Hello, Fastify!”.

  • Handling POST requests
fastify.post("/users", async (request, reply) => {
  const user = request.body;
  // user creation, etc...
  return { id: 1, name: user.name };
});

Handles POST requests to the path /users. Get user information from the request body and create a new user. Returns the created user information as a response.

  • Handling PUT requests
fastify.put("/users/:id", async (request, reply) => {
  const userId = request.params.id;
  const user = request.body;
  // user updates, etc...
  return { id: userId, name: user.name };
});

Handles PUT requests to the path /users/:id. Get the user ID from the URL parameters and update information from the request body. Use that information to update the user information and return the updated user information as a response.

  • Handling DELETE requests
fastify.delete("/users/:id", async (request, reply) => {
  const userId = request.params.id;
  // user deletion etc...
  return { message: `User ${userId} has been deleted.` };
});

Handles DELETE requests to the path /users/:id. Get the user id from the URL parameter and delete that user. A message indicating the deletion is returned as a response.

  • Start server
fastify.listen({ port: 3000 }, (err) => {
  if (err) {
    console.error("Error starting server:", err);
    process.exit(1);
  }
  console.log("Server started on port 3000");
});

Start the server with an instance of Fastify listening on port 3000. If any error occurs, print the error message to the console and terminate the process. If there are no errors, print the message “Server started on port 3000” to the console.

test

# test GET request
curl -X GET http://localhost:3000/hello
# test the POST request
curl -X POST -H "Content-Type: application/json" -d '{"name":"John Doe"}' http://localhost:3000/users
# test the PUT request
curl -X PUT -H "Content-Type: application/json" -d '{"name":"Jane Smith"}' http://localhost:3000/users/1
# test DELETE request
curl -X DELETE http://localhost:3000/users/1

How to use root methods

route.js

const fastify = require("fastify")();

fastify.route({
  method: "GET",
  url: "/hello",
  handler: async (request, reply) => {
    return "Hello, Fastify!";
  },
});

fastify.route({
  method: "POST",
  url: "/users",
  handler: async (request, reply) => {
    const user = request.body;
    // user creation, etc...
    return { id: 1, name: user.name };
  },
});

fastify.route({
  method: "PUT",
  url: "/users/:id",
  handler: async (request, reply) => {
    const userId = request.params.id;
    const user = request.body;
    // user updates, etc...
    return { id: userId, name: user.name };
  },
});

fastify.route({
  method: "DELETE",
  url: "/users/:id",
  handler: async (request, reply) => {
    const userId = request.params.id;
    // user deletion etc...
    return { message: `User ${userId} has been deleted.` };
  },
});

fastify.listen({ port: 3000 }, (err) => {
  if (err) {
    console.error("Error starting server:", err);
    process.exit(1);
  }
  console.log("Server started on port 3000");
});

Commentary

  • Create a Fastify instance
const fastify = require("fastify")();

Import the Fastify module and create an instance of it.

  • Handling GET requests:
fastify.route({
  method: "GET",
  url: "/hello",
  handler: async (request, reply) => {
    return "Hello, Fastify!";
  },
});

Handles GET requests to the path /hello. When a request comes in, it responds with the string “Hello, Fastify!”.

  • Handling POST requests
fastify.route({
  method: "POST",
  url: "/users",
  handler: async (request, reply) => {
    const user = request.body;
    // user creation, etc...
    return { id: 1, name: user.name };
  },
});

Handles POST requests to the path /users. Get user information from the request body and create a new user. Returns the created user information as a response.

  • Handling PUT requests
fastify.route({
  method: "PUT",
  url: "/users/:id",
  handler: async (request, reply) => {
    const userId = request.params.id;
    const user = request.body;
    // user updates, etc...
    return { id: userId, name: user.name };
  },
});

Handles PUT requests to the path /users/:id. Get the user ID from the URL parameters and update information from the request body. Use that information to update the user information and return the updated user information as a response.

  • Handling DELETE requests
fastify.route({
  method: "DELETE",
  url: "/users/:id",
  handler: async (request, reply) => {
    const userId = request.params.id;
    // user deletion etc...
    return { message: `User ${userId} has been deleted.` };
  },
});

Handles DELETE requests to the path /users/:id. Get the user id from the URL parameter and delete that user. A message indicating the deletion is returned as a response.

  • Start server
fastify.listen({ port: 3000 }, (err) => {
  if (err) {
    console.error("Error starting server:", err);


    process.exit(1);
  }
  console.log("Server started on port 3000");
});

Start the server with an instance of Fastify listening on port 3000. If any error occurs, print the error message to the console and terminate the process. If there are no errors, print the message “Server started on port 3000” to the console.

test

# test GET request
curl -X GET http://localhost:3000/hello
# test the POST request
curl -X POST -H "Content-Type: application/json" -d '{"name":"John Doe"}' http://localhost:3000/users
# test the PUT request
curl -X PUT -H "Content-Type: application/json" -d '{"name":"Jane Smith"}' http://localhost:3000/users/1
# test DELETE request
curl -X DELETE http://localhost:3000/users/1

How to use the route handler function directly

handler.js

const fastify = require("fastify")();

const helloHandler = async (request, reply) => {
  return "Hello, Fastify!";
};

const createUserHandler = async (request, reply) => {
  const user = request.body;
  // user creation, etc...
  return { id: 1, name: user.name };
};

const updateUserHandler = async (request, reply) => {
  const userId = request.params.id;
  const user = request.body;
  // user updates, etc...
  return { id: userId, name: user.name };
};

const deleteUserHandler = async (request, reply) => {
  const userId = request.params.id;
  // user deletion etc...
  return { message: `User ${userId} has been deleted.` };
};

fastify.get("/hello", helloHandler);
fastify.post("/users", createUserHandler);
fastify.put("/users/:id", updateUserHandler);
fastify.delete("/users/:id", deleteUserHandler);

fastify.listen({ port: 3000 }, (err) => {
  if (err) {
    console.error("Error starting server:", err);
    process.exit(1);
  }
  console.log("Server started on port 3000");
});

Commentary

  • Create a Fastify instance
const fastify = require("fastify")();

Import the Fastify module and create an instance of it.

  • Handler definition
const helloHandler = async (request, reply) => {
  return "Hello, Fastify!";
};

const createUserHandler = async (request, reply) => {
  const user = request.body;
  // user creation, etc...
  return { id: 1, name: user.name };
};

const updateUserHandler = async (request, reply) => {
  const userId = request.params.id;
  const user = request.body;
  // user updates, etc...
  return { id: userId, name: user.name };
};

const deleteUserHandler = async (request, reply) => {
  const userId = request.params.id;
  // user deletion etc...
  return { message: `User ${userId} has been deleted.` };
};

Define a handler for each request as a function. These functions handle GET, POST, PUT, and DELETE requests respectively.

  • routing settings
fastify.get("/hello", helloHandler);
fastify.post("/users", createUserHandler);
fastify.put("/users/:id", updateUserHandler);
fastify.delete("/users/:id", deleteUserHandler);

Set a handler for each request on your Fastify instance. This will cause the corresponding handler to be called when a specific HTTP method request to a specific URL comes.

  • Start server
fastify.listen({ port: 3000 }, (err) => {
  if (err) {
    console.error("Error starting server:", err);
    process.exit(1);
  }
  console.log("Server started on port 3000");
});

Start the server with an instance of Fastify listening on port 3000. If any error occurs, print the error message to the console and terminate the process. If there are no errors, print the message “Server started on port 3000” to the console.

test

# test GET request
curl -X GET http://localhost:3000/hello
# test the POST request
curl -X POST -H "Content-Type: application/json" -d '{"name":"John Doe"}' http://localhost:3000/users
# test the PUT request
curl -X PUT -H "Content-Type: application/json" -d '{"name":"Jane Smith"}' http://localhost:3000/users/1
# test DELETE request
curl -X DELETE http://localhost:3000/users/1

How to use root options

option.js

const fastify = require("fastify")();

const helloRouteOptions = {
  method: "GET",
  url: "/hello",
  handler: async (request, reply) => {
    return "Hello, Fastify!";
  },
};

const createUserRouteOptions = {
  method: "POST",
  url: "/users",
  handler: async (request, reply) => {
    const user = request.body;
    // user creation, etc...
    return { id: 1, name: user.name };
  },
};

const updateUserRouteOptions = {
  method: "PUT",
  url: "/users/:id",
  handler: async (request, reply) => {
    const userId = request.params.id;
    const user = request.body;
    // user updates, etc...
    return { id: userId, name: user.name };
  },
};

const deleteUserRouteOptions = {
  method: "DELETE",
  url: "/users/:id",
  handler: async (request, reply) => {
    const userId = request.params.id;
    // user deletion etc...
    return { message: `User ${userId} has been deleted.` };
  },
};

fastify.route(helloRouteOptions);
fastify.route(createUserRouteOptions);
fastify.route(updateUserRouteOptions);
fastify.route(deleteUserRouteOptions);

fastify.listen({ port: 3000 }, (err) => {
  if (err) {
    console.error("Error starting server:", err);
    process.exit(1);
  }
  console.log("Server started on port 3000");
});

Commentary

  • Create a Fastify instance
const fastify = require("fastify")();

Import the Fastify module and create an instance of it.

  • define route options
const helloRouteOptions = {
  method: "GET",
  url: "/hello",
  handler: async (request, reply) => {
    return "Hello, Fastify!";
  },
};

const createUserRouteOptions = {
  method: "POST",
  url: "/users",
  handler: async (request, reply) => {
    const user = request.body;
    // user creation, etc...
    return { id: 1, name: user.name };
  },
};

const updateUserRouteOptions = {
  method: "PUT",
  url: "/users/:id",
  handler: async (request, reply) => {
    const userId = request.params.id;
    const user = request.body;
    // user updates, etc...
    return { id: userId, name: user.name };
  },
};

const deleteUserRouteOptions = {
  method: "DELETE",
  url: "/users/:id",
  handler: async (request, reply) => {
    const userId = request.params.id;
    // user deletion etc...
    return { message: `User ${userId} has been deleted.` };
  },
};

Define route options for each request as an object. These objects handle GET, POST, PUT, and DELETE requests respectively.

  • routing settings
fastify.route(helloRouteOptions);
fastify.route(createUserRouteOptions);
fastify.route(updateUserRouteOptions);
fastify.route(deleteUserRouteOptions);

Set route options for each request to your Fastify instance. This will cause the corresponding handler to be called when a specific HTTP method request to a specific URL comes.

  • Start server
fastify.listen({ port: 3000 }, (err) => {
  if (err) {
    console.error("Error starting server:", err);
    process.exit(1);
  }
  console.log("Server started on port 3000");
});

Start the server with an instance of Fastify listening on port 3000. If any error occurs, print the error message to the console and terminate the process. If there are no errors, print the message “Server started on port 3000” to the console.

Commentary

# test GET request
curl -X GET http://localhost:3000/hello
# test the POST request
curl -X POST -H "Content-Type: application/json" -d '{"name":"John Doe"}' http://localhost:3000/users
# test the PUT request
curl -X PUT -H "Content-Type: application/json" -d '{"name":"Jane Smith"}' http://localhost:3000/users/1
# test DELETE request
curl -X DELETE http://localhost:3000/users/1

summary

Fastify offers a rich set of routing features. It can meet various needs from simple routing to advanced routing.

Basic routing allows you to implement routing simply by specifying the HTTP method and URL path. In addition to simple routing, Fastify can implement flexible routing such as routing using regular expressions, HTTP method aliases, and handler function lifecycles.

Dynamic URLs require more advanced routing, such as URL parameter fetching, validation, and validity checks. Fastify provides a simple API for retrieving and validating parameters for dynamic URLs.

Fastify also makes it easy to implement schema-based validation and validation. Security issues can be avoided by validating requests.