How to Write a REST API in TypeScript in 30 Minutes: A Practical Guide

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Introduction: Why TypeScript and REST API Are the Perfect Pair for Rapid Development

\n

Modern web development requires speed and reliability. If you need to quickly create a backend for a mobile app, web service, or microservice architecture, the TypeScript + Node.js + Express stack is one of the most effective tools. TypeScript adds strict typing to JavaScript, allowing you to catch errors at compile time rather than at runtime. This is especially valuable when building a REST API, where each endpoint must clearly know what data it accepts and returns.

\n

In this article, we will create a fully functional REST API for managing a To-Do List in 30 minutes. You will learn how to set up a project, write controllers, routes, and middleware. Everything is based on practical examples with ready-to-use code.

\n\n

Project Setup and Configuration (5 minutes)

\n

First, let's create the project structure and install dependencies.

\n
mkdir todo-api\ncd todo-api\nnpm init -y\nnpm install express cors uuid\nnpm install -D typescript @types/express @types/cors @types/uuid ts-node nodemon
\n

Create a tsconfig.json file in the project root:

\n
{\n  "compilerOptions": {\n    "target": "ES2020",\n    "module": "commonjs",\n    "outDir": "./dist",\n    "rootDir": "./src",\n    "strict": true,\n    "esModuleInterop": true,\n    "skipLibCheck": true\n  },\n  "include": ["src/**/*"]\n}
\n

Add scripts to package.json:

\n
"scripts": {\n  "dev": "nodemon --exec ts-node src/index.ts",\n  "build": "tsc",\n  "start": "node dist/index.js"\n}
\n

Create a src folder and an index.ts file — the entry point.

\n\n

Basic Folder Structure

\n
    \n
  • src/index.ts — entry point, server startup
  • \n
  • src/routes/tasks.ts — task routes
  • \n
  • src/controllers/taskController.ts — request handling logic
  • \n
  • src/models/task.ts — interfaces and types
  • \n
  • src/middleware/errorHandler.ts — error handling (optional)
  • \n
\n\n

Creating Data Models and Interfaces (5 minutes)

\n

Let's define the data types for our task. Create the file src/models/task.ts:

\n
export interface Task {\n  id: string;\n  title: string;\n  completed: boolean;\n  createdAt: Date;\n}\n\nexport type CreateTaskDto = Pick<Task, 'title'>;\nexport type UpdateTaskDto = Partial<Pick<Task, 'title' | 'completed'>>;
\n

Here we use Pick and Partial — built-in utility types in TypeScript. CreateTaskDto accepts only the title, while UpdateTaskDto accepts optional fields for partial updates.

\n\n

Writing Controllers and Routes (15 minutes)

\n

Now for the most interesting part — the application logic. We'll create a temporary in-memory storage for tasks. For production, this should be replaced with a database.

\n\n

Task Controller

\n

File src/controllers/taskController.ts:

\n
import { Request, Response } from 'express';\nimport { v4 as uuidv4 } from 'uuid';\nimport { Task, CreateTaskDto, UpdateTaskDto } from '../models/task';\n\n// Temporary storage\nlet tasks: Task[] = [];\n\n// GET /api/tasks\nexport const getAllTasks = (req: Request, res: Response) => {\n  res.json(tasks);\n};\n\n// GET /api/tasks/:id\nexport const getTaskById = (req: Request, res: Response) => {\n  const task = tasks.find(t => t.id === req.params.id);\n  if (!task) {\n    return res.status(404).json({ message: 'Task not found' });\n  }\n  res.json(task);\n};\n\n// POST /api/tasks\nexport const createTask = (req: Request, res: Response) => {\n  const { title } = req.body as CreateTaskDto;\n  if (!title || typeof title !== 'string') {\n    return res.status(400).json({ message: 'The title field is required and must                

Blogs

Book Recommendations