Fastify is a Node.js framework focused on providing the best developer experience and optimal performance with the least overhead. Consequently, Fastify servers are highly efficient and cost-effective.
Fastify is inspired by Express, Restify and, Hapi but provides a faster alternative with less overhead.
Although Fastify is built as a general-purpose web development framework, it shines when developing fast HTTP API that uses JSON as its data format. Thus Fastify could improve the throughput of most modern applications.
TypeScript support
Fastify is built with vanilla JavaScript so it ships with a type definition file to provide support for TypeScript.
In Fastify version 3x, all http, https, and http2 types are inferred from @types/node so there is still a need to install @types/node.
When using Fastify and TypeScript, it is recommended we import Fastify using the import/from syntax so that types can be resolved. Â Using require() imports Fastify but does not resolve types.
Fastify type system heavily relies on generic properties for accurate type checking.
Version 3 provides an improved types system with generic constraining and defaulting, plus a new way to define schema types. We would elaborate on this as we build our API in the coming sections.Let’s get started with the prerequisites in the next section.
Prerequisite
To follow along in this article, here are a few prerequisites to note:
To get started with Fastify and TypeScript, we will first set up our server.
Follow the steps below to create the server:
Create an npm project, install dependencies and peer dependencies:
npm init -y
npm i fastify nodemon mongoose fastify-plugin
npm i -D typescript @types/node @types/pino @types/mongoose
Initialize a TypeScript configuration file:
npx tsc --init
Configure the TypeScript compiler:
First in the root directory create a src and a build directory. Then modify the tsconfig.json files as seen below:
...
"outDir": "./build", /* Redirect output structure to the directory. */
"rootDir": "./src", /* Specify the root directory of input files. Use to control the output
...
This tells the TypeScript compiler that the src directory contains all our source code and the build directory contains our compile code.
Create an index.ts file in the src  directory and add the following codes:
import { fastify } from 'fastify';
import pino from 'pino';
const Port = process.env.PORT || 7000;
const uri = process.env.MONGODB_URI || 'mongodb://localhost:27017/blogs';
const server = fastify({
logger: pino({ level: 'info' })
});
// register plugin below:
const start = async () => {
try {
await server.listen(Port);
console.log('Server started successfully');
} catch (err) {
server.log.error(err);
process.exit(1);
}
};
start();
Add a build and start commands by adding the following codes to the "scripts" section  of the package.json:
"build": tsc -w" runs the TypeScript compiler in watch mode
"dev": "nodemon build/index.js" uses nodemon to restart our server any time we compile our code.
"start": "node build/index.js" is the production command to start our server it uses node.
Start our server:
We can start our server by running mongod  to start mongodb then npm start. We should get:
[start:run] {"level":30,"time":1618928488354,"pid":14840,"hostname":"pcname","actor":"MongoDB","msg":"connected"}
[start:run] {"level":30,"time":1618928488375,"pid":14840,"hostname":"pcname","msg":"Server listening at http://127.0.0.1:7000"}
[start:run] Server started successfully
The design pattern of the blog model  above solves two major issues of getting TypeScript to work with mongoose. These are:
Getting TypeScript to check the type of arguments passed to the blog constructor when creating a new document. TypeScript does not check for type when we call new Blog(doc).
To get TypeScript involved when creating a blog document, we add a custom method called addOne to the blog model.
addOne takes an argument of type BlogAttrs defined by the BlogAttrs interface. Thus TypeScript can check what type of values are passed to the blog constructor when creating a blog.
But TypeScript does not understand what it means to assign a property to the statics object. To make TypeScript aware of the existence of the addOne  method, we use the  BlogModel interface — which describes all the properties of the blog model.
Now we can do effective type checking as seen below:
Accessing additional properties added by the timestamps.
The timestamps property in our blog model adds the createdAt and updatedAt properties to a new document. These properties are not specified in the BlogAttrs interface so TypeScript does not know about them as seen below:
To make TypeScript aware of the existence of these properties we use the BlogDocument interface — which extends a mongoose document and contains all the properties that exist in a new blog document.
Here we add the createdAt and updatedAt properties to make TypeScript aware of their existence as seen below:
Create a Fastify plugin for our database connection
In the config directory create and index.ts file containing the code below:
The Fastify plugin above exposes our db access and models. Notice our Fastify plugin  decorates Fastify with a new property db. This property contains all our models — only the blog model in this case.
Also, we declared three interfaces; Models for models and MyPluginOptions for our custom uri property added to the Fastify options object. Now TypeScript can check the type of this property as seen below:
Also, we added the Db interface for our new Fastity property db.
But in the default definitions, Fastify server instance does not contain any property called db. However, Fastify plugin use declaration merging to modify existing Fastify type interfaces. Thus, we can add this by using the declaration merging pattern.
Let’s do this in the next section as we build our routes.
Building the blog routes:
In the src directory create a folder called routes and add a blogRoute.ts file with the code below inside it:
In the Fastify plugin above, we used declaration merging to add the db property to the appropriate Fastify interface.
Also, the shorthand route methods — e.g get accepts a generic object RequestGenericInterface. This object contains four named properties: Body, Querystring, Params, and Headers.
The blogParams interface is provided as a property in the generic object passed to Server.get. This tells TypeScript the properties available in request.params and their types.
The interfaces will be passed down through the route method into the route method handler request instance. Consequently, we can do effective type checking in our routes.
Without blogParams interface. Alt=typescript catches error in request object property
With blogParams interface. Alt=Error in request object property resolved.
Activate plugin
In Fastity we active our plugins using .register() method.
Import the plugins using:
import db from './config/index';
import BlogRoutes from './routes/BlogRoute';
Then add the following codes below the // Activate plugins below: comment in the index.ts file:
Our plugins are now registered and our app is complete. we can start testing our routes using postman.
Testing  on curl
We will test our endpoints using two CLI utitlity tools namely curl and jq
POST: /blogs:
curl -H "Content-Type: application/json" -d '{
> "title": "Getting started With Fastify",
> "content": "when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged.",
> "category": "nodejs"
> }' http://127.0.0.1:7000/blogs | jq
// return
{
"_id": "608687070284475d62512eda",
"title": "Getting started With Fastify",
"content": "when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged.",
"category": "nodejs",
"createdAt": "2021-04-26T09:25:27.313Z",
"updatedAt": "2021-04-26T09:25:27.313Z",
"__v": 0
}
GET: /blogs:
curl http://127.0.0.1:7000/blogs | jq
// returns
[
{
"_id": "607edf673a91c9300e83d233",
"title": "Getting started With Fastify",
"content": "when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged.",
"category": "nodejs",
"createdAt": "2021-04-20T14:04:23.654Z",
"updatedAt": "2021-04-20T14:04:23.654Z",
"__v": 0
}
]
GET: /blogs/:id:
curl http://127.0.0.1:7000/blogs/607edf673a91c9300e83d233 | jq
// return
{
"_id": "607edf673a91c9300e83d233",
"title": "Getting started With Fastify",
"content": "when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged.",
"category": "nodejs",
"createdAt": "2021-04-20T14:04:23.654Z",
"updatedAt": "2021-04-20T14:04:23.654Z",
"__v": 0
}
Conclusion
Although TypeScript makes us write more boilerplate codes, the benefits are worth it.
Fastify provides a type system that enables TypeScript to effectively type-check our code at development time.
Fastity provides faster alternatives to other Nodejs frameworks, with less overhead and a great developer experience.