How to Write a REST API in TypeScript in 30 Minutes: A Step-by-Step Guide
Creating a REST API is a fundamental task for any backend developer. Using TypeScript adds strict typing, improves code readability, and reduces the number of errors. In this article, we will walk through how to write a full-fledged REST API in TypeScript from scratch in just 30 minutes. You will get acquainted with Express, TypeORM, and best practices for code organization.
1. Project Setup and Dependency Installation
First, create a new directory and initialize a Node.js project:
mkdir my-rest-apicd my-rest-apinpm init -yInstall the necessary packages:
npm install express reflect-metadata typeorm sqlite3npm install -D typescript @types/node @types/express ts-node nodemonCreate a tsconfig.json file for TypeScript configuration:
{ "compilerOptions": { "target": "ES2020", "module": "commonjs", "outDir": "./dist", "rootDir": "./src", "strict": true, "esModuleInterop": true, "experimentalDecorators": true, "emitDecoratorMetadata": true, "skipLibCheck": true }, "include": ["src/**/*"]}2. Creating the Basic Structure and Entry Point
Organize the folder structure as follows:
src/— main codesrc/controllers/— controllerssrc/entities/— database entitiessrc/routes/— routes
Create the file src/index.ts — the application entry point:
import "reflect-metadata";import express from "express";import { AppDataSource } from "./data-source";import { userRoutes } from "./routes/userRoutes";
const app = express();const PORT = process.env.PORT || 3000;
app.use(express.json());
AppDataSource.initialize() .then(() => { console.log("Database connected"); app.use("/api/users", userRoutes); app.listen(PORT, () => { console.log(`Server running on http://localhost:${PORT}`); }); }) .catch((error) => console.log(error));Now create src/data-source.ts for TypeORM configuration:
import { DataSource } from "typeorm";import { User } from "./entities/User";
export const AppDataSource = new DataSource({ type: "sqlite", database: "database.sqlite", synchronize: true, logging: false, entities: [User],});3. Defining the Entity and Controller
Create the file src/entities/User.ts — the user model:
import { Entity, PrimaryGeneratedColumn, Column } from "typeorm";
@Entity()export class User { @PrimaryGeneratedColumn() id!: number;
@Column() name!: string;
@Column() email!: string;
@Column({ default: true }) isActive!: boolean;}Now let's create the controller src/controllers/userController.ts:
import { Request, Response } from "express";import { AppDataSource } from "../data-source";import { User } from "../entities/User";
const userRepository = AppDataSource.getRepository(User);
export const getUsers = async (req: Request, res: Response) => { try { const users = await userRepository.find(); res.json(users); } catch (error) { res.status(500).json({ message: "Error fetching users" }); }};
export const getUserById = async (req: Request, res: Response) => { try { const user = await userRepository.findOneBy({ id: parseInt(req.params.id) }); if (!user) { return res.status(404).json({ message: "User not found" }); } res.json(user); } catch (error) { res.status(500).json({ message: "Error fetching user" }); }};
export const createUser = async (req: Request, res: Respo