Введение
Современная веб-разработка немыслима без REST API. Это фундамент, на котором строятся мобильные приложения, SPA-фронтенды и микросервисы. Если вы новичок и хотите быстро освоить создание backend'а, то связка TypeScript + Express — идеальный старт. TypeScript добавляет строгую типизацию в JavaScript, что делает код надежнее и понятнее, особенно при работе в команде.
В этом руководстве мы за 30 минут создадим полноценный REST API для управления списком задач (Todo list). Вы научитесь настраивать проект, описывать модели данных, создавать маршруты и подключать базу данных. Никакой лишней теории — только практика и готовый к запуску код.
Предполагается, что у вас уже установлены Node.js (версия 18+) и npm. Если нет — скачайте их с официального сайта.
1. Подготовка проекта и установка зависимостей
Начнем с инициализации нового проекта TypeScript. Откройте терминал и выполните команды:
mkdir my-todo-api
cd my-todo-api
npm init -y
Теперь установим необходимые пакеты:
npm install express
npm install -D typescript @types/node @types/express ts-node nodemon
Создадим конфигурационный файл TypeScript:
npx tsc --init
В файле tsconfig.json убедитесь, что раскомментированы и настроены следующие строки:
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
Создайте папку src и файл src/index.ts — это будет точка входа нашего приложения.
Добавим скрипты в package.json для удобного запуска:
"scripts": {
"dev": "nodemon --exec ts-node src/index.ts",
"build": "tsc",
"start": "node dist/index.js"
}
2. Создание базового сервера Express
Теперь напишем минимальный сервер на Express, который будет слушать порт 3000. Откройте src/index.ts и добавьте следующий код:
import express, { Request, Response } from 'express';
const app = express();
const PORT = 3000;
// Middleware для парсинга JSON
app.use(express.json());
// Базовый маршрут для проверки
app.get('/', (req: Request, res: Response) => {
res.send('Todo API работает!');
});
app.listen(PORT, () => {
console.log(`Сервер запущен на http://localhost:${PORT}`);
});
Запустите сервер командой npm run dev и откройте браузер по адресу http://localhost:3000. Вы должны увидеть сообщение "Todo API работает!".
3. Определение модели данных и in-memory хранилище
Для простоты мы не будем сразу подключать базу данных, а используем временное хранилище в оперативной памяти. Создайте файл src/models/todo.ts:
export interface Todo {
id: number;
title: string;
completed: boolean;
createdAt: Date;
}
export let todos: Todo[] = [
{ id: 1, title: 'Изучить TypeScript', completed: false, createdAt: new Date() },
{ id: 2, title: 'Написать REST API', completed: false, createdAt: new Date() },
];
Обратите внимание на использование интерфейса Todo — это гарантирует, что все объекты в массиве имеют одинаковую структуру.
4. Реализация CRUD-маршрутов
Создадим файл src/routes/todos.ts с полноценными маршрутами для операций Create, Read, Update и Delete.
import { Router, Request, Response } from 'express';
import { Todo, todos } from '../models/todo';
const router = Router();
// GET /api/todos — получить все задачи
router.get('/', (req: Request, res: Response) => {
res.json(todos);
});
// GET /api/todos/:id — получить задачу по ID
router.get('/:id', (req: Request, res: Response) => {
const id = parseInt(req.params.id);
const todo = todos.find(t => t.id === id);
if (!todo) {
return res.status(404).json({ message: 'Задача не найдена' });
}
res.json(todo);
});
// POST /api/todos — создать новую задачу
router.post('/', (req: Request, res: Response) => {
const { title } = req.body;
if (!title || typeof title !== 'string') {
return res.status(400).json({ message: 'Поле title обязательно' });
}
const newTodo: Todo = {
id: todos.length > 0 ? Math.max(...todos.map(t => t.id)) + 1 : 1,
title,
completed: false,
createdAt: new Date(),
};
todos.push(newTodo);
res.status(201).json(newTodo);
});
// PUT /api/todos/:id — обновить задачу
router.put('/:id', (req: Request, res: Response) => {
const id = parseInt(req.params.id);
const todo = todos.find(t => t.id === id);
if (!todo) {
return res.status(404).json({ message: 'Задача не найдена' });
}
const { title, completed } = req.body;
if (title !== undefined) todo.title = title;
if (completed !== undefined) todo.completed = completed;
res.json(todo);
});
// DELETE /api/todos/:id — удалить задачу
router.delete('/:id', (req: Request, res: Response) => {
const id = parseInt(req.params.id);
const index = todos.findIndex(t => t.id === id);
if (index === -1) {
return res.status(404).json({ message: 'Задача не найдена' });
}
todos.splice(index, 1);
res.status(204).send();
});
export default router;
Теперь подключим маршруты в главном файле src/index.ts:
import todoRoutes from './routes/todos';
app.use('/api/todos', todoRoutes);
5. Тестирование API с помощью curl или Postman
Перезапустите сервер и протестируйте эндпоинты. Вот несколько примеров команд curl:
- Получить все задачи:
curl http://localhost:3000/api/todos - Создать новую задачу:
curl -X POST -H "Content-Type: