Принципы разработки REST: ссылки на связанные объекты против вложенных объектов - PullRequest
0 голосов
/ 22 марта 2019

Мы с моей командой проводим рефакторинг REST-API, и у меня возник вопрос. Для краткости предположим, что у нас есть база данных SQL с 4 таблицами: учителя, студенты, курсы и классные комнаты. Прямо сейчас все отношения между элементами представлены в REST-API посредством ссылки на URL соответствующего элемента. Например, для курса у нас может быть следующее

{ "id":"Course1", "teacher": "http://server.com/teacher1", ... }

Кроме того, если спросить список курсов, на которые звонил GET позвонить на /courses, я получу список ссылок, как показано ниже:

{
   ... //pagination details
  "items": [
   {"href": "http://server1.com/course1"},
   {"href": "http://server1.com/course2"}...
 ]
}

Все это красиво и чисто, но если мне нужен список всех названий курсов с именами учителей, и у меня 2000 курсов и 500 учителей, я должен сделать следующее:

  • Приблизительно 2500 запросов только для чтения данных.
  • Осуществить объединение преподавателей и курсов
  • Оптимизация с кэшированием и т. Д., Чтобы я делал это как можно быстрее.

Моя проблема в том, что этот метод создает большой сетевой трафик с тысячами вызовов REST-API, и что мне нужно повторно реализовать естественное объединение, чтобы база данных работала более эффективно. Коллеги говорят, что такой подход является стандартным способом реализации REST-API, но тогда относительно простой запрос становится большой проблемой.

Поэтому мой вопрос: 1. Это неправильно, если мы вкладываем информацию учителя в курсы. 2. Если список товаров, например, GET /courses вернуть список литературы или список предметов?

Edit: После некоторых исследований я бы сказал, что модель, которую я имею в виду, в основном соответствует модели, показанной в jsonapi.org . Это хороший подход?

Ответы [ 3 ]

1 голос
/ 23 марта 2019

Моя проблема в том, что этот метод создает большой сетевой трафик с тысячами вызовов REST-API, и что мне нужно повторно реализовать естественное объединение, чтобы база данных работала более эффективно. Коллеги говорят, что такой подход является стандартным способом реализации REST-API, но тогда относительно простой запрос становится большой проблемой.

Ваши коллеги потеряли сюжет.

Вот ваша эвристика - как бы вы поддержали этот вариант использования на веб-сайте?

Вы, вероятно, сделаете это, определив новую веб-страницу, которая создаст нужный вам отчет. Вы бы запустили запрос, вы получили набор результатов, чтобы сгенерировать кучу HTML, и та-да! У клиента есть информация, которая ему нужна в стандартизированном представлении.

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

Создание новых ресурсов для обработки новых вариантов использования - это нормальный подход к REST.

0 голосов
/ 23 марта 2019

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

Вы действительно измерили накладные расходы, генерируемые каждым запросом?Если нет, откуда вы знаете, что накладные расходы будут слишком интенсивными?С точки зрения объектно-ориентированных программистов может показаться плохим выполнять каждый вызов самостоятельно, однако вашему дизайну не хватает одного важного актива, который помог бы Интернету вырасти до его нынешнего размера: кэширование.

Кэширование может происходитьна нескольких уровнях.Вы можете сделать это на уровне API, или клиент может что-то сделать, или сервер-посредник может сделать это.Fielding даже безумный это ограничение отдыхаИтак, если вы хотите соответствовать философии архитектуры REST, вам также следует поддерживать кэширование ответов.Кэширование помогает сократить количество запросов, которые должны рассчитываться или даже обрабатываться одним сервером.С помощью связи без сохранения состояния вы можете даже представить множество серверов, которые все выполняют вычисления для миллиардов запросов, которые действуют как единая система для клиента.Промежуточный кэш может также помочь значительно сократить количество запросов, которые фактически достигают сервера.

URI в целом (включая любой путь, матрицу или параметры запроса) фактически является ключом для кэша.После получения запроса GET, т. Е. Приложение проверяет, содержит ли его текущий кэш уже сохраненный ответ для этого URI, и возвращает сохраненный ответ от имени сервера непосредственно клиенту, если сохраненные данные являются «достаточно свежими».Если сохраненные данные уже превысили порог свежести, они отбросят сохраненные данные и направят запрос к следующему переходу в строке (может быть фактическим сервером, может быть дополнительным посредником).

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

В то время как некоторые типы носителей, такие как HAL JSON , jsonapi, ... позволяют встраивать контент, полученный из связанных ресурсов, в ответ, встраивание контента имеет некоторые потенциальные недостатки, такие как:

  • Использование кэша может быть низким из-за смешивания данных, которыебыстро меняется с более статичными данными
  • Сервер может рассчитывать данные, которые не нужны клиенту
  • Один сервер вычисляет весь ответ

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

  1. Это неправильно, еслимы вкладываем информацию учителя в курсы.

Это не так, но, возможно, не идеально, как описано выше

Должен ли список предметов, например, GET / курсы, возвращать список литературы или список предметов?

Зависит.Там нет правильного или неправильного.

Поскольку REST - это просто обобщение модели взаимодействия, используемой в сети, в основном те же понятия применимы и к REST.В зависимости от размера «элемента» может быть полезно вернуть краткую сводку содержимого элементов и добавить ссылку на элемент.Подобные вещи делаются и в Интернете.Для списка студентов, зачисленных на курс, это может быть имя и номер его зачисления, и ссылку могут запросить дополнительные сведения об этом студенте, сопровождаемые именем отношения ссылки, которые дают фактической ссылке некоторый семантический контекст, который может использовать клиент.чтобы решить, имеет ли смысл использовать такой URI или нет.

Такие имена отношений ссылок либо стандартизированы с помощью IANA , таких распространенных подходов, как Dublin Core или schema.org или пользовательские расширения, определенные в RFC 8288 (Web Linking) .Для вышеупомянутого списка студентов, зачисленных на курс, вы можете, например, использовать имя отношения about, чтобы намекнуть клиенту, что дополнительную информацию о текущем элементе можно найти, перейдя по ссылке.Если вы хотите включить разбиение на страницы, можно использовать first, next, prev и last, а также, вероятно, следует их использовать и т. Д.

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

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

0 голосов
/ 22 марта 2019

Да, я полностью думаю, что вы должны разработать что-то похожее на jsonapi.org.Как правило, я бы сказал, что «предпочитаю решение, которое требует меньше сетевых вызовов».Это особенно верно, если количество сетевых вызовов будет меньше на порядок.Конечно, это не устраняет необходимость ограничения размера запроса / ответа, если это становится необоснованным.

Реальные решения должны иметь надлежащий баланс.Чистый API хорош, пока он работает.

Так что в вашем случае я бы что-то вроде:

GET /courses?include=teachers

Или

GET /courses?includeTeacher=true

Или

GET /courses?includeTeacher=brief|full

В последнем ответе может быть указан только идентификатор учителя для brief и полная информация об учителе для full.

...