HTTP API может быть очень разным и по возможностям, и по внутреннему устройству данных. Подробнее об этом мы поговорим дальше, а сейчас рассмотрим один из популярных вариантов HTTP API.
Обычно HTTP API построен по следующим правилам:
- Данные передаются в формате JSON
- Для каждого набора данных используется свой URL
Это далеко не единственный способ организации HTTP API, но один из самых распространенных.
Для примера возьмем сервис HTTP Server, созданный специально для экспериментов с API. Он включает в себя ненастоящие данные, с которыми можно попрактиковаться.
В документации сервиса описываются ресурсы — сущности, информацию о которых мы можем получать по API. Ниже их неполный список:
URL | Описание |
---|---|
/posts | Список постов |
/comments | Список комментариев к постам |
/users | Список пользователей |
/tasks | Список задач |
Каждая ссылка, по которой мы получаем какие-то данные в HTTP API, называется эндпоинтом.
Для получения списка пользователей нужно загрузить https://http.hexlet.app/http-api/users. Ее можно открыть даже в браузере. В ответ вернется такой текст:
{
"users": [
{
"id": "1",
"email": "max@hotmail.com",
"firstName": "Allison",
"lastName": "Bernier"
},
{
"id": "2",
"email": "Colt97@yahoo.com",
"firstName": "Hudson",
"lastName": "Schowalter"
}
{
...
}
],
"total": 10,
"skip": 0,
"limit": 30
}
Здесь мы работаем с ненастоящими данными. В реальном API мы бы еще подтвердили доступ, потому что нельзя отдавать такие данные всем подряд.
Формат, в котором данные передаются, называется JSON. Давайте остановимся на этом подробнее.
Формат — это способ описания данных. С ним можно работать двумя способами:
- упаковать данные — то есть сериализовать их
- извлечь данные — десериализовать их
Задача сериализации и десериализации возникает тогда, когда нам нужно передать данные из программы наружу — например, другим программам.
Данные внутри языков представляются каким-то способом, специфичным для данного языка и даже его конкретной версии. Поэтому для передачи данных и используются универсальные форматы, которые известны всем.
В случае HTTP API этот механизм работает так:
- Сервис, который предоставляет HTTP API, извлекает данные из хранилища, формирует JSON и отдает его наружу
- Затем этот JSON может прочитать любая программа с поддержкой JSON (а это большинство современных программ)
Поддержка JSON часто реализована прямо на уровне языков программирования. JSON — это всего лишь текст. У него есть понятная структура, которая прослеживается визуально. Отступы, пробелы и переносы для JSON не имеют значения.
Пример выше может выглядеть и так:
{"users":[{"id": "1","email": "max@hotmail.com","firstName": "Allison","lastName": "Bernier"},{"id": "2","email": "Colt97@yahoo.com","firstName": "Hudson","lastName": "Schowalter"}],"total": 10,"skip": 0,"limit": 100}
Разберемся, чем это отличается от передачи данных в HTML.
HTML — обычно служит для передачи данных в браузеры, так как это язык разметки, с помощью которого формируется текст для браузеров. Браузеры считывают HTML и отображают его в виде веб-страницы. HTML не подразумевает работу с данными, которые содержатся внутри него. Теоретически это можно сделать, но на практике будет очень сложно.
JSON — это не единственный формат данных. До него популярным форматом был XML, и сейчас он встречается довольно часто. Так выглядит XML-файл:
<?xml version="1.0"?>
<Recipe>
<Name>Lime Jello Marshmallow Cottage Cheese Surprise</Name>
<Description>
My grandma's favorite (may she rest in peace).
</Description>
<Ingredients>
<Ingredient>
<Qty unit="box">1</Qty>
<Item>lime gelatin</Item>
</Ingredient>
<Ingredient>
<Qty unit="g">500</Qty>
<Item>multicolored tiny marshmallows</Item>
</Ingredient>
</Ingredients>
<Instructions>
<Step>
Prepare lime gelatin according to package instructions
</Step>
<!-- And so on... -->
</Instructions>
</Recipe>
XML похож на HTML, но решает другую задачу. XML — это формат данных, как и JSON. Разница лишь в том, что XML не предназначен для вывода.
Структура JSON
Данные в формате JSON хранятся внутри объектов. Объект — это часть данных, ограниченная фигурными скобками, внутри которых задаются ключи и их значения:
{ "id": 3, "hasBranches": true, "name": "Hexlet", "country": "Finland" }
Ключи в JSON всегда обернуты кавычками. В качестве значений могут выступать числа, булевы значения, строки и null
:
1
,3
,2.5
true
,false
"one"
,"two"
Также значениями могут быть массивы:
{ "courses": ["php", "ruby", "python"] }
Причем весь JSON может быть только массивом:
["one", "two", "three"]
Объекты могут быть вложенными в другие объекты:
{ "id": 3, "hasBranches": true, "name": "Hexlet", "address": { "country": "Finland", "city": "Helsinki" } }
А еще объекты можно вложить в массивы:
{ "courses": [{ "id": 1, "name": "php" }, { "id": 2, "name": "javascript" }] }
Метаданные
Если посмотреть на структуру ответа /users, то становится видно, что список пользователей передается как массив внутри объекта с дополнительными параметрами:
{
"users": [],
"total": 100,
"skip": 0,
"limit": 30
}
Зачем так сделано? Почему бы сразу не отдавать массив пользователей?
[{ ... }, { ... }]
Ответ здесь очень простой. Часто нужно передавать не только данные, но и метаданные — то есть данные о данных. Например, к метаданным относится общее количество пользователей. Если бы у нас был массив, то эту информацию было бы невозможно добавить без изменения структуры и перехода от массива к объекту.
Объект же позволяет добавлять новые данные, сохраняя обратную совместимость в структуре, не ломая ее. Нужно просто добавить новый ключ на верхний уровень, и все готово.
Пагинация
Иногда данных слишком много: как на Хекслете, у которого сотни тысяч пользователей. JSON с таким объемом данных получится огромным и тяжелым.
Для решения этой задачи используют пагинацию — с ней данные отдаются не целиком, а небольшими наборами. Пагинацию мы встречаем в интернете на каждом шагу. Вспомните результаты поиска в Google — поисковик находит миллионы страниц, но показываются только первые десять результатов, а остальные скрывает на других страницах.
В API, с которым мы работаем, по умолчанию отдается 30 результатов. Это видно из возвращаемого JSON:
{
"users": [...],
"total": 10,
"skip": 0,
"limit": 30
}
Как в таком случае получить вторые 30 человек? Нужно добавить параметр skip: https://http.hexlet.app/http-api/users?skip=30. Так будет выглядеть JSON:
{
"users": [],
"total": 10,
"skip": 30,
"limit": 30
}
В примере с пользователями это не имеет смысла, так как пользователей всего 10. Но, например, для запроса постов полезно, так как их количество больше https://http.hexlet.app/http-api/posts?skip=30:
{
"posts": [...],
"total": 10,
"skip": 30,
"limit": 30
}
Ограничение данных
Представим, что нам нужны не все данные, а только их часть. Для этого в нашем HTTP API есть параметр запроса select: https://http.hexlet.app/http-api/users?select=firstName,email. Так он выглядит:
{
"users": [
{
"id": "1",
"email": "max@hotmail.com",
"firstName": "Allison",
},
{
"id": "2",
"email": "Colt97@yahoo.com",
"firstName": "Hudson",
},
{
"id": "3",
"email": "Landen50@gmail.com",
"firstName": "Reinhold",
},
...
],
"total": 10,
"skip": 0,
"limit": 30
}
Одиночный ресурс
Эндпоинт /users возвращает список пользователей. Если нам нужен один пользователь, то для этого понадобится другой эндпоинт — /users/:id.
Этот эндпоинт называется динамическим, потому что у него есть меняющаяся часть. Вместо :id подставляется идентификатор конкретного пользователя, данные которого мы хотим получить.
Возьмем для примера https://http.hexlet.app/http-api/users/1 и посмотрим на результат:
{
"id": "1",
"email": "max@hotmail.com",
"firstName": "Allison",
"lastName": "Bernier"
}
Вложенные ресурсы
Часто пользователи могут писать посты на сайте. Если мы захотим увидеть весь список постов, то используем эндпоинт /posts.
Чтобы увидеть посты конкретного пользователя, мы воспользуемся вложенными ресурсами: https://http.hexlet.app/http-api/users/1/posts.
Этот эндпоинт вернет все посты пользователя с идентификатором 1
:
{
"posts": [
{
"id": "11",
"authorId": "1",
"title": "comitatus considero termes",
"body": "Cultura fuga adicio conforto. Dolorum curtus teneo sollicito. Vulpes truculenter capitulus.\nRepellat virtus reiciendis admiratio torqueo cubicularis tempore alii. Sustineo apud vorax amissio. Aestivus catena dolore quo antiquus tantillus vinculum talis desidero curia.\nIllum blanditiis concido tepidus talus laborum laudantium aequitas vilitas. Consuasor ago patria. Thermae crur amo."
},
{
"id": "12",
"authorId": "1",
"title": "territo utrimque ab",
"body": "Spargo sponte tum rerum. Thymum comes concido taedium. Claustrum voluptas via armarium tremo decens nemo bellicus.\nChirographum auctor vehemens animi bardus acsi. Desino ullus aranea. Vestrum eos deleniti accendo capio aut sto xiphias.\nFacilis assumenda amplitudo deputo attero peccatus. Spes labore civis eligendi adduco cupiditas error. Vulariter considero repudiandae blanditiis tot unde."
},
...
],
"total": 10,
"skip": 0,
"limit": 30
}
По такому же принципу устроена работа со всеми остальными ресурсами:
URL | Описание |
---|---|
/users/:id/posts | Список постов пользователя |
/users/:id/comments | Список комментариев пользователя |
/users/:id/todos | Список задач пользователя |
Выводы
Мы разобрали одно конкретное HTTP API, которое имеет свои правила по взаимодействию с эндпоинтами. В других HTTP API все будет по-другому — здесь каждый разработчик решает сам. Неизменным остается то, что мы работаем через HTTP и используем его возможности.
Самостоятельная работа
Приложения для управления задачами очень популярны. Не исключено, что в будущем вы будете работать с API одного из таких приложений. Потренируемся работать с ними:
-
Подключитесь к "HTTP Server" с помощью команды:
telnet http.hexlet.app 80
-
Выполните запрос на получение списка Tasks. Введите строку запроса и заголовок
host
-
Выполните новый запрос с добавлением параметров «Пропуск» и «Лимит»
При успешном выполнении запросов вы получите HTTP-ответ с JSON.
Остались вопросы? Задайте их в разделе «Обсуждение»
Вам ответят команда поддержки Хекслета или другие студенты
Для полного доступа к курсу нужен базовый план
Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.