Based on RESTful API Design — Step By Step Guide
- Держать простым
- Не забывать про методы
- Использовать корректные статус-коды в ответах
- Ресурсы как существительное, не глагол
- Использовать множественное значение
- Использовать пагинацию, а не выдавать всё разом
- В коллекциях возвращать информацию о пагинации
- Использовать квери-параметры для GET запросов, если нужно сузить выборку
- Использовать версионирование
- Использовать JSON и обязательно через хедер
accept: application/json
- Давать чёткие ошибки
- Не использовать общий нейминг
- Документировать
Основное, на что нужно обратить внимание:
Использовать корректные статус-коды в ответах
Будет проще отрабатывать ответ и меньше работы: вместо ошибки { error: 'Сервер упал, к сожалению' }
достаточно послать код 503
И принцип от общего к частному: сначала продукты, потом — конкретный продукт.
Самая удобная пагинация — на оффсетах (когда через квери-параметры передаётся offset
и limit
)
В коллекциях удобно иметь структуру
{
items: Array<{MyModel}>,
pagination: {
offset: Number = 0,
limit: Number = 32,
total: Number,
}
}
По моему субъективному опыту в несколько лет, самый удобный формат таков:
Через limit=&offset=&
Через orderBy[key]={asc,desc}
(orderBy[name]=asc
или orderBy[id]=desc
)
- фильтры через префикс
filter[]
и ключ (например,filter[id]
,filter[name]
,filter[price]
) - по строке через
*
:filter[name]=*esl*
для поиска Tesla - несколько значений через
,
:filter[id]=1,2,3,4
- диапазон через
..
, где оба поля опциональны:filter[price]=..100
(до 100),filter[price]=200..
(от 200),filter[price]=50..500
(от 50 до 500) - булеан-значения в прямом виде:
filter[isResale]=true
- вложенные поля через точку:
filter[location.settlementId]=134
filterNot
для обратного поведения (filterNot[isDisabled]=true
: вернуть все объекты, гдеisDisabled
не стоит вtrue
— удобно, еслиisDisabled
необязательное поле и может быть как иnull
, так иfalse
)
📌 tip: такие фильтры реализовываются через Elastic и Elasticsearch
Даже если это внутренний API — меньше когнитивная нагрузка на «сломали ли АПИ или будет работать?». Раз стоит версия, значит разработчик пообещал что она будет стабильна.
АПИ должен явно задавать через хедер accept
что он принимает mime-type application/json
и никакой больше.
📌 Исключение: файлы всё ещё удобнее заливать через multipart/form-data
— тут велосипедов строить не нужно
Клиент должен передавать заголовок content-type
с тем mime-type, который он хочет послать. Сервер явно должен обрабатывать этот хедер и слать ошибку, если он не принимает этот content-type
.
Ошибки дают понимание конкретной проблемы
Типа items
, products
, elements
.
Если возвращаете список автомобилей — ресурс /cars
, если производителей — /manufacturers
, мест — /places
.
Желательно через Сваггер