ua
ua
ГоловнаБлог

Как мы делали API для социальной сети (REST API для WEB)

Эта статья впервые опубликована в издании Хабрахабр от 2 Декабря 2013. Тут публикуется полная её версия.

Об этом уже немало написано, и все же чего-то полного, позволяющего найти все необходимые мне детали в одном месте, когда я только начинал этим заниматься, в русскоязычной редакции я не встречал. Попробую собрать то, что удалось выяснить, путем проб, ошибок и постоянных поисков в работе с различными проектами. Итак, приступим!

Хочу сразу оговориться: REST для меня — это, в первую очередь, идеология, к которой я отношусь трепетно и нежно. И, если кто-то не готов принять ее такой, какая она есть — не стоит читать дальше эту статью. У программиста всегда есть куча полезных дел, которыми можно заняться, пока приходит понимание необходимости писать узнаваемые интерфейсы и прятать за их простотой логику приложений любой сложности…

Теперь давайте по порядку.

REST (Representational State Transfer — репрезентативная передача состояния).

Рой Филдинг — описал подход, названный REST, еще в 2000 году, этот подход лег в основу всем известного протокола HTTP. Можно встретить две разновидности написания для этого архитектурного стиля программирования: REST и RESTful, отличия в значениях этих терминов нет, просто RESTful это прилагательное от REST, т. е. RESTful API — это API, отвечающее принципам REST (Прошу прощения у тех, кто знал, но такие вопросы задают достаточно часто).

REST (Representational State Transfer — репрезентативная передача состояния).

Структура REST API

1. Клиент-серверная архитектура

2. Stateless сервер

3. Кешируемость

4. Многослойная структура

5. Единый интерфейс

  • Идентификация ресурсов
  • Взаимодействие с ресурсами через представления
  • Самодостаточные сообщения
  • Гипермедиа в качестве механизма управления состояниями приложения (HATEOAS)

6. Код по требованию (опционально)

Теперь о каждом элементе поподробней.

Архитектура, клиент — сервер. Отделяем логику приложения от различных клиентов, делаем их код более переносимым, а структуру сервера более простой и масштабируемой. Разработка клиентов и сервера может вестись совершенно независимо.

Stateless — сервер. Состояние клиента не хранится на сервере, ни в каком виде, этим занимается исключительно сам клиент. Это упрощает доработку и сопровождение сервера, делает его более стабильным.

Кешируемость. Должна быть разработана четкая система кеширования запросов к серверу, что позволяет значительно улучшить производительность.

Многослойная структура. Наличие/отсутствие промежуточных серверов кеширования, балансировки нагрузки, дополнительного проксирования должно оставаться совершенно незамеченным со стороны клиентов.

Единый интерфейс.

Идентификация ресурсов. Каждый ресурс обладает уникальным идентификатором URI (Uniform Resource Identifier — универсальный идентификатор ресурса). Например:

/users/ae25b8.

Что касается ID, советую посмотреть в сторону UUID (universally-unique identifier), его поддерживает большинство баз данных и такой подход поможет обеспечить кросc-системную уникальность идентификаторов. Пример:

/users/550e8400-e29b-41d4-a716-446655440000.

Взаимодействие с ресурсами через представления. Каждый ресурс имеет свой уникальный адрес URI (представление), и несколько глаголов для управления этим представлением.

Самодостаточные сообщения. Каждый ответ должен содержать всю необходимую информацию, чтобы его можно было правильно обработать, не обращаясь к помощи других ресурсов.

HATEOAS. Hypermedia As The Engine Of Application State.

Гипермедиа в качестве механизма управления состояниями приложения.

«Слова — Representational State Transfer должны вызывать в голове появление картинки работы грамотного веб приложения: сеть из веб-страниц (назовем их состояниями), в которой пользователь перемещается кликая по ссылкам (смена состояний) для перехода на следующую страницу (представляющую собой очередное состояние приложения)»

Рой Филдинг

Ключ к пониманию HATEOAS удивительно прост — в каждом полученном ответе содержится ссылка на следующий запрос.

Гипермедиа — это тип содержимого ресурса с включенной гипертекстовой разметкой. Гипертекст в данном контексте, как считает сам Филдинг, это одновременное представление информации и элементов выбора.

«Таким образом, гипермедиа это просто расширение, для которого характерно наличие в информационном содержимом временных ссылок на другое содержимое внутри медиа потока».

Код по требованию. Опциональный элемент структуры. Позволяет получать программный код для последующего его исполнения на клиенте.

Таким образом, если ваше приложение отвечает всем требованиям (ограничениям), описанным выше, оно смело может называться RESTful. Исключение представляет лишь код по требованию — этот параметр опционален.

Хороший API просто понять и легко применять.

Основы REST через HTTP.

Ресурс — уникальный объект, доступный по уникальному URL.

Основные URL должны быть понятны без документации.

Для начала, желательно все URL адреса вашего API начинать с префикса, например,

/api/

это поможет упростить сопровождение API в будущем. Хорошим вариантом может оказаться префикс в имени домена:

http://api.example.com/users/ae25b8

Существует 2 основных типа ресурса в архитектуре REST: коллекция и элемент коллекции.

Коллекция представляет собой набор самостоятельных и самодостаточных элементов.

Пример ссылки на коллекцию пользователей:

/api/users

Элемент коллекции пользователей, или конкретный пользователь, в таком случае, может быть представлен в виде:

/api/users/ae25b8

Существительные — хорошо, глаголы — плохо.

Имена коллекций должны представлять сущности (существительные во множественном числе), и они должны быть максимально конкретными и понятными (самодокументирующимися). Если речь идет о собаках, то это должны быть собаки, а не просто животные.

Каждым ресурсом в RESTful API управляет несколько определенных минимально необходимых глаголов. Для большинства случаев достаточно 4 основных глагола (HTTP метода):

GET — получить

POST — создать

PUT — изменить

DELETE — удалить

GET, PUT, DELETE — идемпотентны.

Идемпотентность означает, что сколько бы раз мы не вызывали такой метод — результат будет один и тот же.

Связи

Если необходимо показать иерархическую связь между объектами, делаем так.

Коллекция машин пользователя:

/api/users/ae43bc/cars

Конкретная машина:

/api/users/ae43bc/cars

Не стоит писать длинные адреса — это плохо:

/api/users/ae43bc/cars/c7b45e/door/346ec3b

Такие адреса нелегко читать и искать в документации, часто это вообще не имеет смысла — идентификаторы уникальные и «/cars/c7b45e» абсолютно однозначно относится к «/users/ae43bc». Данный вариант следует сократить:

/api/cars/c7b45e/door/346ec3b

Ошибки

Следует различать 2 основных семейства статус кодов (HTTP Status Code):

4xx — проблема возникла на стороне пользователя и он сам может ее исправить, правильно введя необходимую для запроса информацию.

5xx — проблема возникла на сервере и для ее решения пользователь может отправить запрос к службе поддержки.

Ошибки должны быть четко описаны, чтобы не только пользователь знал, что ему необходимо сделать, но и вы легко ориентировались, если пользователь присылает вам запрос для решения проблемы.

Пример хорошо написанного ответа на ошибку:

HTTP Status Code: 401

{«status»: 401, «message»: «Authentication Required», «code»: 20003, «more_info»: «http://www.example.com/docs/errors/20003»}

Помните! Вы пишете API для таких же разработчиков как и Вы.

Используйте необходимый минимум статус кодов в приложении.

Иногда может быть достаточно 3:

1. 200 OK

2. 400 Bad Request (некорректный запрос)

3. 500 Internal Server Error (внутренняя ошибка сервера)

Если мало, дополняйте по мере необходимости:

1. 201 Created (успешно создан)

2. 304 Not Modified (данные не изменились)

3. 404 Not Found (не найден)

4. 401 Unauthorized (не авторизован)

5. 403 Forbidden (доступ запрещен)

Старайтесь оценить пользу от каждого добавленного Вами элемента для пользователя. Помните, что большое количество, особенно ненужных элементов, способно запутать даже опытных разработчиков.

В некоторых случаях полезно иметь параметр для подавления статус кода ошибки, что бы клиент всегда, при необходимости, мог получить код 200, например.

PUT /api/users/de840a?supress_status_code=200

Это добавит нелишней гибкости Вашему API.

Версионность

Обязательно указывайте номер версии, даже если не планируете изменение интерфейса — все может быстро измениться.

Версию можно указать в строке адреса:

/api/v2/users/ae43bc

или в параметрах запроса:

/api/users/ae43bc?v=2

Нет смысла делать длинными названия версий, вставлять в них точки: v1.03

Версии интерфейса должны меняться максимально редко, в то время как внутреннюю логику работы API можно менять, как только появилась необходимость. В реальности настоящая версия API может быть, например, v2.034-beta2, но версия интерфейса, и, соответственно, представленная в адресе версия будет просто 2.

Постраничная выдача

Любая коллекция, какой бы маленькой, по Вашему мнению, она не была должна отдаваться постранично. Определитесь с форматом выдачи коллекции, например, Content-Type: application/json {«data»:{}, «paging»: {«limit»: 50, «offset»: 0, «total»: 150}} старайтесь всегда использовать одинаковый формат во всех ответах приложения — облегчите жизнь и себе и разработчикам клиентского ПО.

Стоит выбрать какие-то дефолнные значения для параметров «limit», «offset», и, скорее всего, ограничивать максимальное значение для «limit».

Прячьте все сложные компоненты запроса за «?»

Если в Вашем GET запросе необходимо использовать различные фильтры — поместите их за знаком вопроса (в параметрах URL):

GET /api/users?limit=10&offset=4&age=30&height=160&weight=120

Отдавайте пользователю только то, что он хочет

Позвольте клиенту получать только те поля в запросе, которые ему нужны:

GET /api/users/ae43bc?fields=fitst_name,last_name,age,gender,finger_count

Формат отдаваемых данных

Не ограничивайтесь каким-то одним форматом. Сделайте опционально несколько, например, json и xml. Таким легким способом можно значительно упростить разработку для клиентов, и отпадет необходимость выбора чего-то одного. Формат возвращаемых данных можно описывать как в HTTP заголовках, так и в строке запроса:

ACCEPT: application/json

GET /api/users/ae43bc.json

И обязательно стоит выбрать какой-то формат по умолчанию.

Поиск

Это один из немногих видов ресурса, которому суждено остаться глаголом. Имею в виду глобальный поиск.

GET /api/search?q=some+text+to+find

Опять же в зависимости от системы используемого поискового движка можно применять различные фильтры.

Какой-то локальный поиск, в пределах коллекции, можно осуществить и простыми фильтрами:

GET /api/users?q=some+users+to+find

Авторизация

Используйте, по возможности, последнюю версию OAuth — OAuth 2.0 — эта система хорошо известна разработчикам, и хорошо себя зарекомендовала. Зачем выдумывать велосипед?

Документация

Это один из самых важных аспектов хорошего API. Любой, кто, когда-либо сталкивался с написанием клиентских скриптов, со мной согласится. Часы, потраченные на хорошую документацию, с лихвой окупятся долгими месяцами работы службы поддержки. Фокус прост — опишите сжато и четко все получаемые и отдаваемые данные, а также назначение методов. Помните! Вы пишете для программистов. Не стоит описывать какие-то очевидные моменты. Приведите все отдаваемые статус коды; перечислите все принимаемые параметры опишите их, где необходимо; давайте ссылки на более подробный материал; приводите примеры получаемых данных, если это уместно, с их описанием.

Ссылки

Старайтесь отдавать в ответах ссылки на все связанные ресурсы, если хотите соответствовать принципу HATEOAS, и называться RESTful. За это Вас будут очень любить разработчики клиентских программ — им не придется самим генерировать эти ссылки.

Теперь самое главное!

Фасад Паттерн для API.

Разработку любого API следует начинать с детальной проработки интерфейса. Фактически к началу написания кода на руках должны быть все URI Вашего API с подробной документацией всех параметров каждого доступного для данного URI метода, со всеми возвращаемыми статус кодами и форматами возвращаемых данных. В идеале, этот интерфейс уже не должен меняться в ходе дальнейшей разработки. Такой подход в значительной степени облегчает и ускоряет работу над основным кодом API, и позволяет параллельно писать клиентское ПО уже на самых начальных этапах разработки.

Помните! Интерфейс API должен быть максимально простым и понятным, только так можно достичь счастья и гармонии.

P.S. Чтобы получать наши новые статьи раньше других или просто не пропустить новые публикации — подписывайтесь на нас в FacebookVKTwitterLiveJournal и LinkedIn

Сергій Харланчук
Senior Web Developer / Team Lead, SECL Group

Схожі публікації

Більше про нас?
Компанія
Більше кейсів?
Роботи
Є проект?
Контакти
Канада

240 Richmond Street W
Toronto ON M5V 1V6
+1 (647) 946-92-12

США

3524 Silverside Road
35B, Wilmington,
Delaware 19810-4929
+1 (929) 237-12-11

Україна

79039, м. Львів,
вул. Дмитра Бортнянського, 23
+380 (44) 389-90-39

Copyright © 2005 – 
2024
, ГК «SECL Group»