A production-ready starter template for building RESTful APIs with Node.js, TypeScript, and Fastify. This template follows the MVC (Model-Routes-Controllers-Services) architecture pattern, providing a clean and scalable foundation for your backend projects.
🚀 Features
Fastify - Fast and low overhead web framework
TypeScript - Type-safe development
Sequelize ORM - Database abstraction with PostgreSQL/MySQL support
This YouTube tutorial is in Thai. I’m keeping this post in English so everyone can quickly understand the main concepts alongside the video. For deeper understanding, feel free to ask ChatGPT or your favorite AI.
What you will learn
This course teaches you how to build an API using:
Node.js
Fastify (a web framework)
Sequelize (for working with databases)
MySQL (database)
About MRCS
MRCS means Model-Routes-Controllers-Services. This is a way to organize your code. It helps you keep your code clean and easy to understand.
BillowDev Youtube
Setup Videos
Watch these videos first to install the tools you need:
How to Install Git and using GitHub
How to Install Node.js and VS code
How to Install Laragon
Node js TypeScript Fastify EP 01 Intro
In this episode, you will learn how to start your project and create your first API.
Step 1: Start a new project
First, create a new Node.js project. Open your terminal and type:
npm init -y
This command creates a file called package.json. This file stores information about your project.
Step 2: Using Yarn (Optional)
You can use npm or yarn. Both are package managers. They help you install libraries for your project.
If you want to use yarn, install it first:
npm install-g yarn
Here are the yarn commands you need to know:
npm install is the same as yarn add
npm install -D is the same as yarn add -D
npm run is the same as yarn
Step 3: Install TypeScript tools
You need to install TypeScript and some tools. TypeScript is a language that adds types to JavaScript.
Now create a TypeScript configuration file. This file tells TypeScript how to work with your code.
Type this command:
npx tsc --init
This creates a file called tsconfig.json. Copy this code into that file:
tsconfig.json
{"compilerOptions":{/* Visit https://aka.ms/tsconfig to read more about this file *//* Language and Environment */"target":"ESNext",/* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. *//* Modules */"module":"commonjs",/* Specify what module code is generated. */// "rootDir": "./", /* Specify the root folder within your source files. */"moduleResolution":"node",/* Specify how TypeScript looks up a file from a given module specifier. */"baseUrl":"./src",/* Specify the base directory to resolve non-relative module names. */"outDir":"./dist",/* Specify an output folder for all emitted files. */"esModuleInterop":true,/* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */"forceConsistentCasingInFileNames":true,/* Ensure that casing is correct in imports. *//* Type Checking */"strict":true,/* Enable all strict type-checking options. */"skipLibCheck":true/* Skip type checking all .d.ts files. */},"include":["**/*.ts","src/config/db.config.ts"],"exclude":["node_modules","**/*.d.ts","**/*.spec.ts"]}
Step 5: Install Fastify
Fastify is a web framework. It helps you build APIs quickly.
Install it with this command:
npm install fastify
Or if you use yarn:
yarn add fastify
Step 6: Create your first file
Create a new file called index.ts in your project root folder.
Step 7: Write your first API
Now you will write code to create your first API. Follow these steps:
Step 7.1: Import Fastify
importfastifyfrom"fastify";
This line imports the Fastify library.
Step 7.2: Create the app
Next, create your app:
constapp=fastify()
Step 7.3: Create your first route
A route is a URL that your API can respond to. Create your first route:
app.get("/",async ()=>"SERVER");
This creates a route at "/". When someone visits this URL, they will see "SERVER".
Step 7.4: Start your server
Now you need to start your server. Add this code:
constPORT=5000app.listen({port:Number(PORT)},(err)=>{if (err){console.error(err)process.exit(1)}console.log(`SERVE ON ${PORT}`)})
This code starts your server on port 5000.
Step 7.5: Run your API
Save your file. Then open your terminal and type:
ts-node index.ts
You should see the message "SERVE ON 5000" in your terminal. This means your API is running!
Step 8: Make your logs look better
The logs help you see what your API is doing. Let's make them look better.
Step 8.1: Add logging options
Change your app code to this:
constapp=fastify({logger:true})
This turns on logging.
Step 8.2: Update your listen code
Replace the code from step 7.4 with this:
constPORT=5000app.listen({port:Number(PORT)},(err)=>{if (err){app.log.error(err);process.exit(1)}app.log.info(`SERVE ON ${PORT}`)})
This uses the logger instead of console.log.
Step 8.3: See your logs
When you run your API now, you will see logs like this:
{"level":30,"time":1676779096246,"pid":25344,"hostname":"billo","msg":"Server listening at http://[::1]:5000"}{"level":30,"time":1676779096248,"pid":25344,"hostname":"billo","msg":"Server listening at http://127.0.0.1:5000"}{"level":30,"time":1676779096248,"pid":25344,"hostname":"billo","msg":"SERVE ON 5000"}
Step 9: Test your API
You can test your API with Thunder Client. It is a tool for testing APIs. You can find it in the Visual Studio Code extensions.
You can also use other tools like Postman or Insomnia. These tools let you test different HTTP methods like GET, POST, PUT, PATCH, and DELETE. If your API uses GET method, you can also test it in your browser.
Node js TypeScript Fastify EP 02 Thunder client
In this episode, you will learn how to test your API using Thunder Client.
What is Thunder Client?
Thunder Client is a tool for testing APIs. It works inside Visual Studio Code. You can use it to send requests to your API and see the responses.
Step 1: Install Thunder Client
Open Visual Studio Code. Go to the Extensions section. Search for "Thunder Client" and install it.
Step 2: How to use Thunder Client
After installing Thunder Client, you will see a new icon in your sidebar. Click on it to open Thunder Client. You can create requests and test your API there.
Your complete index.ts file
After following all the steps in EP 01, your index.ts file should look like this:
importfastifyfrom"fastify";constapp=fastify({logger:true})app.get("/",async ()=>"SERVER");constPORT=5000app.listen({port:Number(PORT)},(err)=>{if (err){app.log.error(err);process.exit(1)}app.log.info(`SERVE ON ${PORT}`)})
Node js TypeScript Fastify EP 03 App
In this episode, you will learn how to organize your code better. We will move the app logic to a separate file.
Why organize code?
When your code grows, it is better to organize it. This makes your code easier to read and maintain. We will create a src folder and put our code there.
Step 1: Create the src folder
First, create a new folder called src in your project root.
Step 2: Move app logic to src/app.ts
Create a new file called app.ts inside the src folder. Move the app creation code there.
This code creates a function called App. This function takes options and creates a Fastify app. It returns the app so you can use it later.
Code for index.ts
Now update your index.ts file. Import the App function and use it to create your app:
importAppfrom"./src/app";constapp=App({logger:true})constPORT=5000app.listen({port:Number(PORT)},(err)=>{if (err){app.log.error(err);process.exit(1)}app.log.info(`SERVE ON ${PORT}`)})
What changed?
Before: All your code was in index.ts
After: The app logic is in src/app.ts, and index.ts only starts the server
This makes your code more organized. When you add more features, you will add them to the src folder.
Node js TypeScript Fastify EP 04 Routes
In this episode, you will learn how to create routes. Routes are URLs that your API responds to.
What is a route?
A route is a URL path. When someone visits that URL, your API responds. For example, /api/v1/articles is a route.
Step 1: Create the routes folder
Create a new folder called routes inside the src folder.
Step 2: Create article route file
Create a new file called article.route.ts inside the src/routes folder.
Step 3: Write the route code
import{FastifyInstance}from"fastify";constarticleRouter=async (app:FastifyInstance)=>{// This is sample data for testingconstarticle={id:"1",name:"node.js fastify",desc:"Fast and easy course for building APIs"}// Create a GET route at "/"app.get("/",()=>{return{articles:[article]}});};exportdefaultarticleRouter;
This code creates a router for articles. It has one route that returns sample data.
Step 4: Create routes index file
Create a new file called index.ts inside the src/routes folder. This file exports all your routes.
Now you need to tell your app to use this route. Update your src/app.ts file.
importfastify,{FastifyServerOptions}from"fastify";import{articleRouter}from"./routes";constApp=(options:FastifyServerOptions)=>{constapp=fastify(options)app.get("/",async ()=>"SERVER");// Register the article router with a prefixapp.register(articleRouter,{prefix:"/api/v1/articles"});returnapp}exportdefaultApp
The prefix means all article routes will start with /api/v1/articles.
Step 6: Test your route
Stop your server by pressing CTRL + C in your terminal
Start it again with: ts-node index.ts
Open Thunder Client and test the route: http://localhost:5000/api/v1/articles
Result
You should see the article data when you visit the route:
Node js TypeScript Fastify EP 05 Controllers
In this episode, you will learn about controllers. Controllers handle the logic for your routes.
What is a controller?
A controller is a function that handles requests. When someone visits a route, the controller decides what to do and what to return.
Step 1: Create controllers folder
Create a new folder called controllers inside the src folder.
Step 2: Create article controller
Create a new file called article.controller.ts inside the src/controllers folder.
exportconsthandleGetArticle=()=>{// This is sample data for testingconstarticle={id:"1",name:"node.js fastify",desc:"Fast and easy course for building APIs"}return{articles:[article]}}exportdefault{handleGetArticle}
This controller function returns article data. Later, it will get data from a service.
Step 3: Create controllers index file
Create a new file called index.ts inside the src/controllers folder.
Now update your src/routes/article.route.ts file to use the controller.
import{FastifyInstance}from"fastify";importarticleControllerfrom'./../controllers/article.controller';constarticleRouter=async (app:FastifyInstance)=>{// Use the controller function as the handlerapp.get("/",articleController.handleGetArticle);};exportdefaultarticleRouter;
Now your route uses the controller. This separates the route logic from the business logic.
Node js TypeScript Fastify EP 06 Services
In this episode, you will learn about services. Services contain the business logic of your application.
What is a service?
A service is where you put your business logic. It handles things like getting data or processing information. Controllers call services.
Step 1: Create services folder
Create a new folder called services inside the src folder.
Step 2: Create article service
Create a new file called article.service.ts inside the src/services folder.
exportconstgetArticles=()=>{constdata={id:"1",name:"node.js fastify",desc:"Fast and easy course for building APIs"}return{response:data}}exportdefault{getArticles}
This service function returns article data. Later, it will get data from a database.
Step 3: Create services index file
Create a new file called index.ts inside the src/services folder.
Open Laragon and click the "Start All" button to start the MySQL server.
Step 3: Open MySQL
Click on the "Database" button in Laragon to open the database manager.
Step 4: Create a new database
Click on "Database" in the left sidebar
Right-click and select "Create Database"
Step 5: Name your database
Name your database node_fastify_db and click "OK".
Great! Your database is ready. In the next episode, you will learn how to connect your API to this database.
Node js TypeScript Fastify EP 08 Sequelize
In this episode, you will learn how to connect your API to the database using Sequelize.
What is Sequelize?
Sequelize is an ORM (Object-Relational Mapping). It helps you talk to your database. You use models to work with database tables.
What is dotenv?
Dotenv is a package that helps you use environment variables. Environment variables store secret information like database passwords. You put them in a .env file.
What is mysql2?
mysql2 is a driver for MySQL. It allows your code to connect to MySQL database. If you use PostgreSQL, you would use pg instead.
Step 1: Install packages
Install Sequelize, dotenv, and mysql2:
npm install sequelize dotenv mysql2
Or if you use yarn:
yarn add sequelize dotenv mysql2
Step 2: Create .env file
Create a new file called .env in your project root. This file stores your database settings.
Important: The default MySQL username in Laragon is root and the password is empty "".
We separate the settings for different environments: development, production, and test.
Create a new file called db.config.ts inside the src/config folder.
importconfigfrom"./config";// this is important!module.exports={development:{username:config.database.dev.username,password:config.database.dev.password,database:config.database.dev.name,host:config.database.dev.host,dialect:config.database.dialect,},test:{username:config.database.test.username,password:config.database.test.password,database:config.database.test.name,host:config.database.test.host,dialect:config.database.dialect,},production:{username:config.database.production.username,password:config.database.production.password,database:config.database.production.name,host:config.database.production.host,dialect:config.database.dialect,},};
Step 4: Create models
Models represent your database tables. They define what data you can store.
Step 4.1: Create types folder
Create a new folder called types inside the src folder.
Step 4.2: Create article model types
Create a new folder called articles inside the src/types folder. Then create a file called article.model.types.ts inside src/types/articles.
Create a new file called article.model.ts inside the src/models folder.
This file defines the Article model. The models/index.ts file will automatically read this file and create the model based on what you declare.
"use strict";import*asSequelizefrom"sequelize";import{Model,UUIDV4}from"sequelize";import{ArticleAttributes}from"types/articles/article.model.types";module.exports=(sequelize:any,DataTypes:any)=>{classArticleextendsModel<ArticleAttributes>implementsArticleAttributes{/**
* Helper method for defining associations.
* This method is not a part of Sequelize lifecycle.
* The `models/index` file will call this method automatically.
*/id!:string;title!:string;text!:string;type!:string;staticassociate(models:any){// define association here}}Article.init({id:{type:DataTypes.UUID,defaultValue:UUIDV4,allowNull:false,primaryKey:true,},title:{type:DataTypes.STRING,allowNull:false,},text:{type:DataTypes.STRING(500),},},{sequelize,modelName:"Article",});returnArticle;};
Step 4.6: Update index.ts
Now update your index.ts file to:
Import the database and config files
Get the PORT from the config file
Sync the database with Sequelize (this creates the tables)
importAppfrom"./src/app";importdbfrom"./src/models"importconfigfrom"./src/config/config"constapp=App({logger:true})constPORT:string|number=config.portdb.sequelize.sync().then(()=>{app.listen({port:Number(PORT)},(err)=>{if (err){app.log.error(err);process.exit(1)}app.log.info(`SERVE ON ${PORT}`)})})
Step 5: Use nodemon for development
Nodemon automatically restarts your app when you change the code. This is very helpful during development.
Important: Only use nodemon in development. It will restart your app every time you save a file.
Step 5.1: Install nodemon
npm install-D nodemon
Or if you use yarn:
yarn add -D nodemon
Step 5.2: Add script to package.json
Open your package.json file. Find the "scripts" section and add this line:
"dev":"nodemon index.ts"
Step 5.3: Run your app
Now you can run your app with:
npm run dev
Or if you use yarn:
yarn dev
Your app will automatically restart when you change your code!
Bonus: Complete CRUD API Example
This is a bonus section. You will learn how to create a complete CRUD API. CRUD means Create, Read, Update, and Delete.
Note: This section does not have a video tutorial. Follow the steps below to build a complete Articles API.
What you will build
You will create an Articles API with these operations:
GET - Get all articles
GET - Get one article by ID
POST - Create a new article
PUT - Update an article
DELETE - Delete an article
How it works
The flow is: routes → controllers → services → models (Sequelize) → MySQL database
Step 1: Update routes
We will create 5 routes in the article router. Each route calls a controller function.
import{FastifyInstance}from"fastify";importarticleControllerfrom'./../controllers/article.controller';constarticleRouter=async (app:FastifyInstance)=>{// GET all articlesapp.get("/",articleController.handleGetArticle);// GET one article by IDapp.get("/get/:id",articleController.handleGetArticleById);// POST create a new articleapp.post("/create",articleController.handleCreateArticle);// PUT update an articleapp.put("/update/:id",articleController.handleUpdateArticle);// DELETE delete an articleapp.delete("/delete/:id",articleController.handleDeleteArticle);};exportdefaultarticleRouter;
Step 2: Create request types
We need to define types for the request data. This helps TypeScript understand what data to expect.
Create a new file called article.controller.types.ts inside src/types/articles.