Метаданные — это информация о данных, которая описывает или сопровождает основное содержимое запроса или ответа. В контексте REST API метаданные могут включать такие данные, как информация о пагинации, статусе запроса, идентификация пользователя, обработка ошибок и другая служебная информация, которая не является основной частью ресурса, но необходима для его использования.
REST API позволяет передавать метаданные разными способами. Мы рассмотрим два из них: в теле ответа и через заголовки HTTP.
Передача метаданных в теле ответа
Метаданные можно передавать вместе с основным содержимым в теле ответа. Обычно они находятся в отдельной структуре или уровне объекта, который включает как основную информацию, так и вспомогательную информацию.
Допустим, API возвращает список пользователей, и нам нужно передать метаданные о пагинации. Сделать это можно переместив список пользователей внутрь поля data
и добавив на верхнем уровне поле meta
, куда мы поместим дополнительные параметры. Делается это для того, чтобы случайно не перемешивать данные и метаданные:
{
"data": [
{
"id": 1,
"name": "John Doe"
},
{
"id": 2,
"name": "Jane Doe"
}
],
"meta": {
"total": 100,
"page": 1,
"per_page": 10
}
}
В этом примере объект meta содержит метаданные о пагинации: общее количество записей (total), текущую страницу (page) и количество записей на странице (per_page). Этот подход удобен, когда метаданные тесно связаны с данными и их логически уместно передавать в одном месте. То же самое можно проделать и в случае запроса конкретного ресурса.
{
"data": {
"id": 1,
"name": "John Doe"
},
"meta": {
"key": "какое-то значение"
}
}
Преимущества:
- Легкость в восприятии и логичность: вся информация, включая метаданные, находится в одном объекте.
- Поддержка более сложных метаданных, таких как фильтры, сортировка или контекст запроса.
Недостатки:
- Увеличение размера тела ответа.
- Если такой подход не был заложен сразу, то изменение структуры приведет к потере обратной совместимости. Это критично для внешнего апи, которое должно оставаться обратно совместимым в рамках одной версии.
- В некоторых случаях могут потребоваться дополнительные данные, которые не связаны с ресурсом напрямую.
Когда использовать?
Если вы решили передавать метаданные таким образом или знаете, что в будущем это понадобится, то имеет смысл сразу проектировать API с учетом метаданных, даже если сейчас их нет. То есть имеет смысл любой ответ упаковывать в свойство data
, чтобы иметь возможность расширять структуру без нарушения обратной совместимости.
Использование в Fastify
Для изменения структуры ответа, достаточно поменять возвращаемый объект с, например, return users
на:
return { data: users, meta: {/* какие-то данные */} }
В ответ мы получим:
curl localhost:3000/api/users
{
"data": [
{
"createdAt": "1726856145",
"email": "sylvia31@yahoo.com",
"fullName": "Dr. Jessie Tremblay",
"id": 1,
"updatedAt": null
}
],
"meta": {}
}
При росте количества эндпонитов, такой подход начнет приводить к дублированию. Чтобы его избежать, можно вынести процесс генерации ответа в сериализаторы таким образом:
// serializers/UserSerializer.js
export default class UserSerializer {
static index(users, meta) {
return { data: users, meta }
}
}
Пример использования:
return UserSerializer.index(users, meta)
Передача метаданных через HTTP-заголовки
Ту же самую информацию можно передать через HTTP-заголовки. Заголовки используются для передачи служебной информации, которая не должна быть частью основного содержимого ответа. Такой подход позволяет отделить метаданные от основного тела ответа, что может быть полезно для упрощения структуры данных или если метаданные служат исключительно техническим целям.
Пример с пагинацией:
HTTP/1.1 200 OK
Content-Type: application/json
X-Total-Count: 100
X-Page: 1
X-Per-Page: 10
Преимущества:
- Разделение данных и метаданных: основной контент остаётся чистым, а метаданные передаются отдельно.
- Простота для случаев, когда метаданные носят технический характер (например, кэширование, идентификация, контроль токенов).
- Уменьшение размера основного тела ответа, если метаданные не должны быть частью ресурса.
Недостатки:
- Ограничения по объему информации: заголовки HTTP имеют ограничения по размеру, поэтому они не подходят для передачи больших объёмов данных.
- Могут быть сложнее для тестирования, так как метаданные, передаваемые через заголовки, могут не быть сразу видны в теле ответа, что требует дополнительного анализа ответа.
- Клиенты могут не всегда легко извлекать информацию из заголовков, особенно если API взаимодействует с простыми приложениями или библиотеками.
Когда использовать?
Передача метаданных через заголовки удобна, когда метаданные носят технический характер или не связаны напрямую с основными данными. Например, это может быть информация о кэшировании, идентификации пользователя, заголовки с токенами или информация, которая не должна изменять тело основного ответа.
Самостоятельная работа
- Добавьте метаданные в маршруты, возвращающие списки. Метаданные должны содержать: текущую страницу, количество элементов на странице, общее количество элементов
- Запушьте изменения в репозиторий
Для полного доступа к курсу нужен базовый план
Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.