Введение в API архитектуру
API (Application Programming Interface) — это контракт между клиентом и сервером. Правильный выбор архитектуры API критически важен для масштабируемости и удобства разработки.
В этой статье мы сравним два популярных подхода: REST API и GraphQL, рассмотрим их преимущества и недостатки, а также лучшие практики проектирования.
REST API: классический подход
REST (Representational State Transfer) — архитектурный стиль, основанный на HTTP методах и ресурсах. Каждый endpoint представляет ресурс.
// Типичные REST endpoints
GET /api/users // Список пользователей
GET /api/users/:id // Один пользователь
POST /api/users // Создать пользователя
PUT /api/users/:id // Обновить пользователя
DELETE /api/users/:id // Удалить пользователя
// Express.js реализация
import express from 'express';
const router = express.Router();
router.get('/users', async (req, res) => {
const { page = 1, limit = 10, sort = 'createdAt' } = req.query;
const users = await prisma.user.findMany({
skip: (page - 1) * limit,
take: limit,
orderBy: { [sort]: 'desc' }
});
res.json({ data: users, page, limit });
});
router.get('/users/:id', async (req, res) => {
const user = await prisma.user.findUnique({
where: { id: req.params.id },
include: { posts: true, profile: true }
});
if (!user) {
return res.status(404).json({ error: 'User not found' });
}
res.json(user);
});
Версионирование API
Версионирование позволяет развивать API без поломки существующих клиентов:
// Версионирование через URL
app.use('/api/v1', v1Router);
app.use('/api/v2', v2Router);
// Версионирование через заголовки
app.use((req, res, next) => {
const version = req.headers['api-version'] || 'v1';
req.apiVersion = version;
next();
});
GraphQL: гибкий подход
GraphQL — язык запросов для API, позволяющий клиенту запрашивать только нужные данные. Один endpoint, множество возможностей.
// GraphQL схема
import { gql } from 'graphql-tag';
const typeDefs = gql`
type User {
id: ID!
name: String!
email: String!
posts: [Post!]!
profile: Profile
}
type Post {
id: ID!
title: String!
content: String!
author: User!
createdAt: DateTime!
}
type Query {
users(limit: Int, offset: Int): [User!]!
user(id: ID!): User
posts(authorId: ID): [Post!]!
}
type Mutation {
createUser(input: CreateUserInput!): User!
updateUser(id: ID!, input: UpdateUserInput!): User!
deleteUser(id: ID!): Boolean!
}
`;
// Resolvers
const resolvers = {
Query: {
users: (_, { limit = 10, offset = 0 }) => {
return prisma.user.findMany({ take: limit, skip: offset });
},
user: (_, { id }) => {
return prisma.user.findUnique({ where: { id } });
}
},
User: {
posts: (parent) => {
return prisma.post.findMany({ where: { authorId: parent.id } });
}
}
};
Преимущества GraphQL
- Нет over-fetching — клиент получает только запрошенные поля
- Нет under-fetching — один запрос вместо нескольких
- Строгая типизация — схема как контракт
- Интроспекция — автоматическая документация
Документация API с OpenAPI/Swagger
Документация — обязательная часть любого API. OpenAPI (Swagger) — стандарт для описания REST API:
# openapi.yaml
openapi: 3.0.0
info:
title: User API
version: 1.0.0
description: API для управления пользователями
paths:
/users:
get:
summary: Получить список пользователей
parameters:
- name: page
in: query
schema:
type: integer
default: 1
- name: limit
in: query
schema:
type: integer
default: 10
responses:
'200':
description: Успешный ответ
content:
application/json:
schema:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/User'
components:
schemas:
User:
type: object
properties:
id:
type: string
name:
type: string
email:
type: string
format: email
Когда выбрать REST, а когда GraphQL
| Критерий | REST | GraphQL |
|---|---|---|
| Простота | ✅ Проще начать | Требует изучения |
| Кэширование | ✅ HTTP кэш из коробки | Сложнее настроить |
| Гибкость запросов | Фиксированные ответы | ✅ Клиент выбирает поля |
| Мобильные приложения | Много запросов | ✅ Один запрос |
| Микросервисы | ✅ Независимые сервисы | Federation сложнее |
Лучшие практики проектирования API
- Используйте существительные — /users, не /getUsers
- HTTP статусы — 200, 201, 400, 404, 500
- Пагинация — limit/offset или cursor-based
- Фильтрация и сортировка — query параметры
- Версионирование — планируйте заранее
- Rate limiting — защита от злоупотреблений
Заключение
REST остаётся отличным выбором для простых CRUD API и микросервисов. GraphQL идеален для сложных клиентов с разными потребностями в данных. Часто лучшее решение — комбинация обоих подходов.
Хороший API — это API с хорошей документацией. Инвестируйте время в Swagger/OpenAPI или GraphQL схему.
