Проектирование REST приложений

preview

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

Так как большую часть веб-приложения занимает не бизнес-составляющая, а инфраструктура, возникает задача управления над корректной передачей состояния бизнес-логики. Чтобы использовать все преимущества распределенных систем, был придуман архитектурный стиль REST, а его адаптация на веб-приложения стала называться RESTful. Говоря про REST-прилоежния чаще всего имеются в виду именно RESTful приложения.

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

Основы

Duration: 7

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

Ограничения следующие:

  • Модель клиент сервер - принцип черного ящика у клиента и сервера;
  • Отсутствие состояния - каждый запрос самодостаточен;
  • Кэширование - идентификация ресурса должна позволять кэшировать результат когда это нужно;
  • Единообразие интерфейсов
    • Идентификация ресурсов;
    • Манипуляция ресурсами через представление;
    • «Самоописываемые» сообщения;
    • Гипермедиа как средство изменения состояния приложения;
  • Слои - разделение абстракций и обязанностей по слоям - сетевые системы являются многослойными, т.е. сервер может быть только прокси к другим серверам;
  • Код по требованию - функциональность клиента может быть расширена через поставку кода с сервера.

Ресурсы

Duration: 10

  • Все ресурсы - структуры
  • URN развертывается в представление данных
  • Ресурс с типом сущность неделим
  • {...} - структура обозначает тип "сущность"
  • [...] - структура обозначает тип "коллекция"
  • (a,b) - структура обозначает "связь"
  • косой чертой (/) - обозначается бинарное отношение между структурами разных типов
  • "связь" имеет специальный смысл и всегда должна находиться в служебном подмножестве "связи"
  • идентификаторы могут быть составными и результат получается путем свертки (слева направо) и применению правила развертывания в представление.

Все ресурсы структуры

Идентификатор

Duration: 5

  • Идентификатор - не отражает структуру хранения ресурсов
  • Идентификатор не обязаны быть составным сотсавной:/users/:id/orders/:id несоставной: /userorders/:userid
  • Идентификатор не определяет представление ресурса - /users/:id/orders и /books/:id/orders могут содержать одинаковые заказы, но мы не знаем получены они через ссылку или через копирование значения
  • URL должен поддерживать простые правила расширения

Представление

Duration: 10

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

  • Разработчик сам определяет представление ресурсов
  • Варианты представления:
    • неупорядоченное глобальное множество мапится на ID
    • множество множеств находящихся в отношении "связь"
    • множество вложенных множеств в отношении "содержит"
    • множество комбинация все предыдущих способов
    • любой другой способ
  • Идемпотентность запросов

Получение данных, маппинг на HTTP

Duration: 5

REST приложения не обязаны основываться на HTTP протоколе, но практические реализации REST реализованы в веб-приложениях, работающих на HTTP. Поэтому на практике REST представлен RESTful.

HTTP запросы можно взаимооднозначно отобразить на функции: - GET /users/:id => getusersid(id) - GET /users/:id => get(usersid) - GET /users/:id?status=active => getuser_id(id, status = 'active')

Временные коллекции

Duration: 5

В предложенной реализации REST есть возможность объединять в рамках одного запроса несколько действий: GET(/users/:id/posts/2022) POST(/users/:id/posts, []) = 2022 # обновляется алиас, но предыдущие коллекции остаются по их URN PUT(2022, GET(users/:id/posts, params: {filter: {year = 2022}})) GET(/users/:id/posts/2022) # возвращает результат значит является представлением и должно примениться правило развертывания Но мы можем сократить лишние действия и получить REST, который будет работать в рамках предложенных ограничений: ` GET(/users/:id/posts/2022) => GET(users/:id/posts, params: {filter: {year = 2022}}))

`

временная коллекция, которую можно получить путем фильтрации

Коды ответов или ошибки в  JSON

Duration: 7

  • Бизнес ошибки
  • Инфраструктурные ошибки