В этой статье — мой рабочий шаблон для описания REST API в ТЗ для разработчиков. В качестве примера я спроектировала учебную базу данных для финтех-системы. Она не привязана к реальному проекту и нужна только для того, чтобы показать, как описывать REST API по шаблону.
Описание исходной базы данных (БД)
В БД четыре таблицы: users (Пользователи), accounts (Счета), currencies (Валюты), transactions (Транзакции). Ниже представлено описание таблиц.
Таблица users хранит данные о пользователях.
|
Параметр |
Тип |
Not null |
Значение по умолчанию |
Описание |
|
id |
int |
[v] |
|
Идентификатор |
|
|
varchar(255) |
[ ] |
|
Адрес электронной почты |
|
last_name |
varchar(255) |
[v] |
|
Фамилия |
|
first_name |
varchar(255) |
[v] |
|
Имя |
|
middle_name |
varchar(255) |
[v] |
|
Отчество |
|
status |
int |
[v] |
3 |
Статус: 1 — active, 2 — blocked, 3 — pending, 4 — deleted |
|
is_verified |
bool |
[v] |
false |
Флаг подтверждения личности |
|
created_at |
timestamp |
[v] |
|
Дата и время регистрации |
|
updated_at |
timestamp |
[ ] |
|
Дата и время последнего обновления |
Расшифровка возможных значений параметра users.status:
-
active — пользователь активен. Может входить в систему, совершать операции, создавать транзакции;
-
blocked — пользователь заблокирован. Вход в систему запрещён. Обычно блокируют за нарушение правил, подозрительную активность или по требованию безопасности;
-
pending — пользователь ожидает подтверждения. Например, регистрация завершена, но email не подтверждён, или аккаунт проходит модерацию. Доступ к операциям может быть ограничен;
-
deleted — пользователь удалён или деактивирован. Обычно такой статус используют вместо физического удаления записи, чтобы сохранить историю.
Таблица accounts хранит информацию о банковских счетах пользователей. У одного пользователя может быть несколько счетов, поэтому связь меду таблицами users и accounts — «одна ко многим».
|
Параметр |
Тип |
Not Null |
Значение по умолчанию |
Описание |
|
id |
int |
[v] |
|
Идентификатор |
|
user_id |
int |
[v] |
|
Ссылка на пользователя |
|
acc_number |
varchar(34) |
[v] |
|
Номер счета |
|
currency_id |
int |
[v] |
|
Ссылка на валюту |
|
balance |
numeric |
[v] |
|
Текущий остаток |
|
status |
int |
[v] |
1 |
Статус: 1 — active, 2 — frozen, 3 — closed |
|
is_default |
bool |
[v] |
false |
Основной счет |
|
created_at |
timestamp |
[v] |
|
Дата открытия счета |
|
updated_at |
timestamp |
[ ] |
|
Дата последнего обновления |
Расшифровка возможных значений параметра accounts.status:
-
active — счет активен. Все операции доступны: пополнение, списание, переводы;
-
frozen — счет заморожен. Движение средств приостановлено (обычно по решению банка, суда или службы безопасности). Пополнение может быть доступно, списание — нет;
-
closed — счет закрыт. Операции по счету недоступны.
Таблица currencies хранит информацию о валютах
|
Параметр |
Тип |
Not Null |
Значение по умолчанию |
Описание |
|
id |
int |
[v] |
|
Идентификатор |
|
name |
varchar(255) |
[v] |
|
Наименование |
|
code |
varchar(10) |
[v] |
|
Код валюты: RUB, USD, EUR |
|
default |
bool |
[v] |
false |
Флаг ( 0-обычная валюта, 1-валюта принятая в системе по умолчанию) |
|
user |
bool |
[v] |
false |
Флаг ( 0-при расчетах используется курс ЦБ, 1-при расчетах используется пользовательское значение курса) |
Таблица transactions хранит информацию о всех движениях средств между счетами.
|
Параметр |
Тип |
Not Null |
Значение по умолчанию |
Описание |
|
id |
int |
[v] |
|
Идентификатор |
|
type |
int |
[v] |
|
Тип: 1 — transfer, 2 — payment, |
|
from_account_id |
int |
[v] |
|
Ссылка на счет списания |
|
to_account_id |
int |
[v] |
|
Ссылка на счет зачисления |
|
sum |
numeric |
[v] |
|
Сума транзакции |
|
currency_id |
int |
[v] |
Валюта рубль |
Ссылка на валюту |
|
status |
int |
[v] |
1 |
Статус: 1 — pending, 2 — processing, 3 — completed, 4 — failed, 5 — reversed |
|
description |
varchar(255) |
[ ] |
|
Описание транзакции |
|
created_at |
timestamp |
[v] |
currencies.created_at |
Дата создания |
|
updated_at |
timestamp |
[v] |
|
Дата последнего обновления |
|
is_recurring |
bool |
[v] |
false |
Флаг регулярности платежа |
Добавить обязательную проверку: transactions.sum > 0.
Расшифровка возможных значений параметра transactions.type:
-
transfer — перевод средств между собственными счетами пользователя (например, с рублёвого на валютный);
-
payment — платеж в пользу третьего лица или организации (оплата товаров, услуг, коммунальных платежей);
-
refund — возврат средств от продавца или сервиса (частичный или полный).
Расшифровка возможных значений параметра transactions.status:
-
pending — транзакция создана, но ещё не обработана. Ожидает подтверждения или выполнения;
-
processing — транзакция в процессе выполнения;
-
completed — транзакция успешно завершена. Средства списаны со счета отправителя и зачислены на счет получателя;
-
failed — транзакция не выполнена. Средства не были списаны. Причина: недостаточно средств, ошибка валидации, технический сбой;
-
reversed — транзакция отменена (возврат). Средства возвращены на счет отправителя (или частично).
Шаблон описания REST API
Краткое описание модели
Указать URL ресурса
Перечислить разрешенные запросы
Далее перечислить какие параметры содержит модель. Для каждого поля указать тип, обязательность для запросов и маппинг — из какой таблицы подтягивать данные. Если поле ссылается на другую модель или таблицу — это должно быть отражено в ТЗ. Все это можно описать в виде таблицы.
|
Параметр |
Тип |
Поле в бд |
Обязательность в запросах |
Описание |
|
id |
int |
tablename.id |
post, put, delete |
Идентификатор |
|
параметр_1 |
string |
tablename.name_1 |
|
Параметр для чего-то |
|
параметр_2 |
bool |
tablename.name_2 |
post |
Обязательный параметр |
-
Если параметр вычисляемый, добавить алгоритм расчета
-
Описать бизнес-правила, которые должны выполняться при обработке запроса (при наличии). Например, некоторые параметры становятся обязательными или необязательными в зависимости от того, что указано в другом поле.
-
Указать все ограничения (например, параметр_1 > 0, значение параметра_1 не может быть отрицательным)
-
Описать проверки, которые должны выполняться перед выполнением операции
-
Добавить примеры запросов и ответов
-
Описать обработку всех невалидных данных (ошибки валидации)
-
Описать обработку ошибок на уровне бизнес-логики
Пример описания REST API на учебной БД согласно шаблону
Создать модель currencies
Модель currencies предназначена для получения данных о валютах.
URL: https://XXXXX/api/v1/currencies.json
Разрешенные запросы: только GET, у пользователя не должно быть возможности добавлять и менять валюту через API
|
Параметр |
Тип |
Поле в бд |
Обязательность в запросах |
Описание |
|
id |
int |
currencies.id |
post, put, delete |
Идентификатор |
|
name |
string |
currencies.name |
|
Наименование |
|
code |
string |
currencies.code |
post |
Код валюты: RUB, USD, EUR |
|
default |
bool |
currencies.default |
post |
Флаг ( 0-обычная валюта, 1-валюта принятая в системе по умолчанию) |
|
user |
bool |
currencies.user |
post |
Флаг ( 0-при расчетах используется курс ЦБ, 1-при расчетах используется пользовательское значение курса) |
Пример: получить список валют, GET-запрос
GET /api/v1/currencies
Пример ответа на GET-запрос
{ "data": [ { "id": 1, "name": "Российский рубль", "code": "RUB", "default": true, "user": false }, { "id": 2, "name": "Доллар США", "code": "USD", "default": false, "user": false }, { "id": 3, "name": "Евро", "code": "EUR", "default": false, "user": true } ]}
Создать модель users
Модель users описывает пользователя системы. Содержит персональные данные, статус и временные метки.
https://XXXXX/api/v1/users.json
Разрешенные запросы: GET, POST, PUT, DELETE
|
Параметр |
Тип |
Поле в бд |
Обязательность в запросах |
Описание |
|
id |
int |
users.id |
post, put, delete |
Идентификатор |
|
|
string |
users.email |
|
Адрес электронной почты |
|
last_name |
string |
users.last_name |
post |
Фамилия |
|
first_name |
string |
users.first_name |
post |
Имя |
|
middle_name |
string |
users.middle_name |
post |
Отчество |
|
status |
int |
users.status |
|
Статус: 1 — active, 2 — blocked, 3 — pending, 4 — deleted |
|
is_verified |
bool |
users.is_verified |
|
Флаг подтверждения личности |
|
created_at |
datetime |
users.created_at |
|
Дата и время регистрации |
|
updated_at |
datetime |
users.updated_at |
|
Дата и время последнего обновления |
Пример корректного POST-запроса
POST /api/v1/users HTTP/1.1Host: your-api-domain.comContent-Type: application/json{ "last_name": "Сидоров", "first_name": "Алексей", "middle_name": "Петрович"}
Пример ответа на POST-запрос (201 Created)
{ "data": { "id": 3, "email": null, "last_name": "Сидоров", "first_name": "Алексей", "middle_name": "Петрович", "status": 3, "is_verified": false, "created_at": "2025-06-30T16:00:00Z", "updated_at": null }}
В ответе на POST- и PUT-запросы можно возвращать только id.
1 Если в запросе не указан хотя бы один из обязательных параметров, то при попытке отправить запрос выводить ошибку: «Отсутствует обязательный параметр — наименование параметра«.
Пример некорректного POST-запроса
POST /api/v1/users HTTP/1.1Host: your-api-domain.comContent-Type: application/json{ "first_name": "Иван", "middle_name": "Иванович"}
Пример ответа (400 Bad Request)
{ "error": "Отсутствует обязательный параметр - last_name"}
2 Если в запросе указано некорректное значение параметра status, то выводить ошибку: «Некорректное значение параметра status. Допустимые значения: 1 (active), 2 (blocked), 3 (pending), 4 (deleted)»
Пример некорректного POST-запроса
POST /api/v1/users HTTP/1.1Host: your-api-domain.comContent-Type: application/json{ "last_name": "Иванов", "first_name": "Иван", "middle_name": "Иванович", "status": 5}
Пример ответа (400 Bad Request)
{ "error": "Некорректное значение status. Допустимые значения: 1 (active), 2 (blocked), 3 (pending), 4 (deleted)"}
Если в post-запросе не задан параметр status, то автоматически присваивать значение pending.
Создать модель accounts
Модель accounts описывает банковские счета пользователей. У одного пользователя может быть несколько счетов.
https://XXXXX/api/v1/accounts.json
Разрешенные запросы: GET, POST, PUT, DELETE
|
Параметр |
Тип |
Поле в бд |
Обязательность в запросах |
Описание |
|
id |
int |
accounts.id |
|
Идентификатор |
|
user_id |
int |
accounts.user_id |
post |
Ссылка на пользователя |
|
acc_number |
string |
accounts.acc_number |
post |
Номер счета |
|
currency_id |
int |
accounts.currency_id |
post |
Ссылка на валюту |
|
balance |
float |
accounts.balance |
|
Текущий остаток |
|
status |
int |
accounts.status |
|
Статус: 1 — active, 2 — frozen, 3 — closed |
|
is_default |
bool |
accounts.is_default |
|
Основной счет |
|
created_at |
datetime |
accounts.created_at |
|
Дата открытия счета |
|
updated_at |
datetime |
accounts.updated_at |
|
Дата последнего обновления |
1 Если в запросе не указан хотя бы один из обязательных параметров, то при попытке отправить запрос выводить ошибку: «Отсутствует обязательный параметр — наименование параметра«.
Пример некорректного POST-запроса
POST /api/v1/accounts HTTP/1.1Host: your-api-domain.comContent-Type: application/json{ "acc_number": "40817810099910004314", "currency_id": 1, "is_default": false}
Пример ответа (400 Bad Request)
{ "error": "Отсутствует обязательный параметр - user_id"}
2 Если в запросе указана некорректная ссылка (идентификатор) для параметров user_id и currency_id или некорректный номер счета (acc_number) или статус (status), выводить ошибку «Некорректное значение параметра наименование_параметра«
3 Поле balance является вычисляемым. Оно не передаётся в запросах и не хранится как статическое значение. Баланс рассчитывается как разница между всеми успешными поступлениями и списаниями по счёту. Обновление происходит автоматически при изменении статуса транзакции на completed или reversed.
-
Поле balance не может быть установлено клиентом.
-
Баланс рассчитывается как сумма всех успешных (status=3) транзакций:
balance = sum(completed incoming) - sum(completed outgoing) -
Обновление баланса происходит автоматически при изменении статуса транзакции на completed или reversed.
|
Расшифровка |
Откуда брать |
Что брать |
|
|
таблица transactions |
Все записи, где to_account_id = ID счёта и status = 3 (completed) |
|
|
таблица transactions |
Все записи, где from_account_id = ID счёта и status = 3 (completed) |
Как выглядит в SQL:
-- Остаток по счёту на текущий моментSELECT COALESCE(SUM( CASE WHEN to_account_id = {account_id} THEN sum WHEN from_account_id = {account_id} THEN -sum ELSE 0 END), 0) AS balanceFROM transactionsWHERE (to_account_id = {account_id} OR from_account_id = {account_id}) AND status = 3;
В API параметр balance рассчитывается:
balance = SUM(transactions.sum WHERE to_account_id = accounts.id AND status = 3) - SUM(transactions.sum WHERE from_account_id = accounts.id AND status = 3)
При попытке вручную задать значение параметра balance в POST- или PUT-запросах есть два сценария поведения API:
-
Запрос отправляется успешно, но входное значение параметра balance игнорируется и считается автоматически по формуле, соответственно в бд записывается вычисленное значение
-
Вывести в ответе ошибку (400 Bad Request):
{ "error": "Поле balance не может быть задано клиентом. Значение рассчитывается автоматически."}
Создать модель transactions
Модель transactions описывает движение средств между счетами пользователей.
https://XXXXX/api/v1/transactions.json
Разрешенные запросы: GET, POST, PUT, DELETE
|
Параметр |
Тип |
Поле в бд |
Обязательность в запросах |
Описание |
|
id |
int |
transactions.id |
|
Идентификатор |
|
type |
int |
transactions.type |
post |
Тип: 1 — transfer, 2 — payment, |
|
from_account_id |
int |
transactions.from_account_id |
post |
Ссылка на счет списания |
|
to_account_id |
int |
transactions.to_account_id |
post |
Ссылка на счет зачисления |
|
sum |
float |
transactions.sum |
post |
Сумма транзакции |
|
currency_id |
int |
transactions.currency_id |
|
Ссылка на валюту |
|
status |
int |
transactions.status |
|
Статус: 1 — pending, 2 — processing, 3 — completed, 4 — failed, 5 — reversed |
|
description |
string |
transactions.description |
|
Описание транзакции |
|
created_at |
datetime |
transactions.created_at |
|
Дата создания |
|
updated_at |
datetime |
transactions.updated_at |
|
Дата последнего обновления |
|
is_recurring |
bool |
transactions.is_recurring |
|
Флаг регулярности платежа |
Пример PUT-запроса на изменение суммы транзакции на 0
PUT /api/v1/transactions/1 HTTP/1.1Host: your-api-domain.comContent-Type: application/json{ "type": 1, "from_account_id": 1, "to_account_id": 3, "sum": 0.00, "currency_id": 1, "description": "Перевод другу (сумма исправлена)", "is_recurring": false}
Пример ответа (422 Unprocessable Entity)
{ "error": "Сумма должна быть больше 0"}
Чек-лист для проверки ТЗ
-
Полнота описания методов
-
Для каждого метода указан URL и HTTP-метод (GET, POST, PUT, DELETE)
-
Для каждого кода ошибки есть описание (когда возникает)
-
Есть примеры запросов и ответов (хотя бы один на каждый метод)
-
-
Модели данных и маппинг
-
Для каждого поля ответа указано, откуда оно берётся (таблица, поле, вычисление)
-
Если поле вычисляемое — описан алгоритм расчёта
-
Если данные запроса сохраняются в БД — указано, в какое поле и таблицу
-
-
Бизнес-логика
-
Описаны бизнес-правила, которые должны выполняться при обработке запроса
-
Указаны все ограничения (например, сумма > 0, сумма не может быть отрицательной)
-
Описаны проверки, которые должны выполняться перед выполнением операции
-
Если операция идемпотентна — отражено в ТЗ
-
-
Коды ответа и ошибки
-
Коды ответа — 200, 201, 400, 404, 500
-
Описана обработка всех невалидных данных (ошибки валидации)
-
Описана обработка ошибок на уровне бизнес-логики
-
Указан статус-код и тело ответа для каждой ошибки (желательно с примером)
-
ссылка на оригинал статьи https://habr.com/ru/articles/1053910/