Виммельбух, 2, перетяжка
Виммельбух, 2, перетяжка
Виммельбух, 2, перетяжка

Основы REST: теория и практика

Автор простыми словами объясняет основы REST, а также на конкретном примере показывает возможные решения для разработки системы.

100К открытий109К показов

REST, Representational State Transfer, является архитектурным стилем для обеспечения стандартов между компьютерными системами в сети, что облегчает для систем обмен данными друг с другом. Системы, отвечающие требованиям REST и часто называемые RESTful, характеризуются тем, что не имеют сохранения состояния и разделяют интересы клиента и сервера. Мы рассмотрим, что означают эти термины и почему они являются полезными для услуг в Интернете.

Разделение клиента и сервера

В архитектурном стиле REST реализация клиента и реализация сервера могут быть выполнены независимо друг от друга. Это означает, что код на стороне клиента может быть изменён в любое время без ущерба для работы сервера, а код на стороне сервера может быть изменён без влияния на работу клиента.

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

Используя интерфейс REST, различные клиенты попадают в одни и те же конечные точки REST, выполняют те же действия и получают одинаковые ответы.

Отсутствие сохранения состояния

Системы, которые следуют парадигме REST, не имеют сохранения состояния, что означает, что серверу не нужно знать о состоянии клиента и наоборот. Таким образом, и сервер, и клиент могут понять любое полученное сообщение, даже не увидев предыдущих сообщений. Это отсутствие сохранения состояния обеспечивается за счёт использования ресурсов, а не команд. Они описывают любые объекты, документы или вещи, которые могут потребоваться для хранения или отправки в другие службы.

Эти ограничения помогают RESTful-приложениям достигать надёжности, быстрой производительности и расширяемости, как компонентам, которые могут быть управляемы, обновлены и повторно использованы, не затрагивая систему в целом даже во время её работы.

Теперь мы изучим, как на самом деле происходит взаимодействие между клиентом и сервером, когда мы внедряем RESTful-интерфейс.

Взаимодействие между клиентом и сервером

В архитектуре REST клиенты отправляют запросы на поиск или изменение ресурсов, а серверы отправляют ответы на эти запросы. Давайте рассмотрим стандартные способы направления запросов и ответов.

Отправка запросов

REST требует, чтобы клиент сделал запрос на сервер для получения или изменения данных на сервере. Запрос обычно состоит из:

  • НТТР-метода, который определяет вид операции;
  • заголовка, который позволяет клиенту передавать информацию о запросе;
  • пути к ресурсу;
  • необязательного тела сообщения, содержащего данные.

Существует 4 основных метода НТТР, которые мы используем в запросах для взаимодействия с ресурсами в системе REST:

  • GET — получение конкретного ресурса (по id) или коллекцию ресурсов;
  • POST — создание нового ресурса;
  • PUT — обновление конкретного ресурса (по id);
  • DELETE — удаление конкретного ресурса по id;

В заголовке запроса клиент отправляет тип контента, который он может получить с сервера. Это поле называется Accept. Оно обеспечивает, что сервер не посылает данные, которые не могут быть поняты или обработаны клиентом. Параметры типов контента — это типы MIME (или Multipurpose Internet Mail Extensions, о которых вы можете прочитать больше в MDN Web Docs).

Типы MIME, используемые для указания типов контента в поле Accept, состоят из типа и подтипа. Они разделены слэшем (/).

Например, текстовый файл, содержащий HTML, будет указан с типом text/html. Если этот текстовый файл содержит CSS, то он будет указан как text/css. Общий текстовый файл будет обозначаться как text/plain. Однако это значение по умолчанию, text/plain, не является исчерпывающим. Если клиент ожидает text/css, а получает text/plain, он не сможет распознать содержание.

Другие типы и часто используемые подтипы:

  • image — image/png, image/jpeg, image/gif;
  • audio — audio/wav, audio/mpeg;
  • video — video/mp4, video/ogg;
  • application — application/json, application/pdf, application/xml, application/octet-stream.

Например, клиент, имеющий доступ к ресурсу с идентификатором 123 в ресурсе статей на сервере, может отправить запрос GET следующим образом:

			GET/news/123
Accept: text/html, application/xhtml
		

В этом случае поле заголовка Accept говорит, что клиент примет содержание в text/html или application/xhtml.

Запросы должны содержать путь к ресурсу, на котором должна выполняться операция. В RESTful API пути должны быть разработаны так, чтобы помочь клиенту понять, что происходит. Обычно первая часть пути должна быть множественной формой ресурса. Это позволяет легко читать и понимать вложенные пути.

Пути должны содержать информацию, необходимую для определения местоположения ресурса с необходимой степенью конкретности. При ссылке на список или коллекцию ресурсов не всегда необходимо добавлять идентификатор. Например, запрос POST на путь somesite.com/persons не будет нуждаться в дополнительном идентификаторе, так как сервер генерирует идентификатор для нового объекта.

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

Например, клиент получает доступ к ресурсу с идентификатором 123 в разделе статей с этим запросом GET:

			GET /news/123 HTTP/1.1
Accept: text/html, application/xhtml
		

Сервер должен отправить обратно контент с заголовком ответа:

			HTTP/1.1 200 (OK)
Content-Type: text/html
		

Это означает, что запрашиваемый контент возвращается в тело ответа с text/html — типом контента, который клиент будет в состоянии принять.

Коды ответов

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

Для каждого метода НТТР ожидаются коды статуса, которые сервер должен вернуть в случае успеха:

  • GET — return 200 (OK)
  • POST — return 201 (CREATED)
  • PUT — return 200 (OK)
  • DELETE — return 204 (NO CONTENT)

Если операция не работает, вернётся наиболее конкретный код состояния, соответствующий возникшей проблеме.

Предположим, у нас есть приложение, которое позволяет вам просматривать, создавать, редактировать и удалять клиентов и заказы для небольшого магазина одежды, размещённого на сайте fashionboutique.com. Мы можем создать НТТР API, который позволит клиенту выполнять следующие функции.

Если бы мы хотели увидеть всех клиентов, запрос выглядел бы так:

			GET http://somesite.com/persons
Accept: application/json
		

Возможный заголовок ответа будет выглядеть следующим образом:

			Status Code: 200 (OK)
Content-type: application/json
		

Затем следуют данные клиентов, запрошенные в формате application/json.

Создание нового клиента путем размещения данных:

POST http://somesite.com/persons

			Body:
{
  “person”: {
    “name” = “oleg Melnic”,
    “email” = “oleg.melnic@gmail.com”
  }
}
		

Затем сервер генерирует идентификатор этого объекта и возвращает его клиенту с таким заголовком:

			201 (CREATED)
Content-type: application/json
		

Для просмотра одного клиента мы используем метод GET, указывая идентификатор этого клиента:

			GET http://somesite.com/persons/123
Accept: application/json
		

Возможный заголовок ответа будет выглядеть следующим образом:

			Status Code: 200 (OK)
Content-type: application/json
		

Затем следуют данные ресурса клиента с идентификатором 123 в формате application/json.

Мы можем обновить этого клиента, вставив новые данные с помощью метода PUT:

PUT http://somesite.com/persons/123

			Body:
{
  “person”: {
    “name” = “Oleg Melnic”,
    “email” = “olegmelnic1@gmail.com”
  }
}
		

Возможный заголовок ответа будет иметь Status Code: 200 (OK), чтобы сообщить клиенту, что элемент с идентификатором 123 был изменен.

Мы также можем УДАЛИТЬ этого клиента, указав его идентификатор:

DELETE http://somesite.com/persons/123

Ответ будет иметь заголовок, содержащий Status Code: 204 (NO CONTENT), уведомляющий клиента о том, что объект с идентификатором 123 был удалён и ничего в теле не осталось.

Практика с REST

Давайте представим, что мы создаём сайт для сбора фотографий. Мы хотим сделать API, чтобы отслеживать пользователей, места проведения и фотографии этих мест. Этот сайт имеет index.html и style.css. Каждый пользователь имеет имя пользователя и пароль. Каждая фотография имеет место проведения и владельца (т.е. пользователя, который сделал фотографию). Каждое место имеет название и адрес. Можете ли вы разработать систему REST, которая будет учитывать:

  • хранение пользователей, фотографий и мест проведения;
  • доступ к определённым местам и доступ к некоторым фотографиям определённого места проведения?

Для начала опишите:

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

Возможные решения — модели

			{
  “user”: {
    "id": <Integer>,
    “username”: <String>,
    “password”:  <String>
  }
}
{
  “photo”: {
    "id": <Integer>,
    “address_id”: <Integer>,
    “user_id”: <Integer>
  }
}
{
  “address”: {
    "id": <Integer>,
    “name”: <String>,
    “value”: <String>
  }
}
		

Возможное решение — запросы / ответы

GET-запросы

Request

			GET /index.html
Accept: text/html
		

Response

			200 (OK)
Content-type: text/html
		

Request

			GET /style.css
Accept: text/css
		

Response

			200 (OK)
Content-type: text/css
		

Request

			GET /addresses
Accept: application/json
		

Response

			200 (OK)
Content-type: application/json
		

Request

			GET /addresses/:id
Accept: application/json
		

Response

			200 (OK)
Content-type: application/json
		

Request

			GET /addresses/:id /photos/:id
Accept: application/json
		

Response

			200 (OK)
Content-type: image/png
		

POST-запросы

Request

			POST /users
		

Response

			201 (CREATED)
Content-type: application/json
		

Request

			POST /addresses
		

Response

			201 (CREATED)
Content-type: application/json
		

Request

			POST /addresses/:id /photos
		

Response

			201 (CREATED)
Content-type: application/json
		

PUT-запросы

Request

			PUT /users/:id
		

Response

			200 (OK)
		

Request

			PUT /addresses/:id
		

Response

			200 (OK)
		

Request

			PUT /addresses/:id /photos/:id
		

Response

			200 (OK)
		

DELETE-запросы

Request

			DELETE /addresses/:id
		

Response

			204 (NO CONTENT)
		

Request

			DELETE /addresses/:id/ photos/:id
		

Response

			204 (NO CONTENT)
		

Посмотрите также статью про лучшие практики разработки REST API. 20 советов помогут вам создавать понятные API.

Следите за новыми постами
Следите за новыми постами по любимым темам
100К открытий109К показов