Рекомендации по проектированию отношений REST api

#api #rest

#API #rest

Вопрос:

В настоящее время мы пытаемся разработать некоторый REST api для наших веб-сервисов. У нас есть два ресурса: «запись» и «экспедиция». Насколько нам известно, запись может быть связана с несколькими экспедициями, а экспедиция может быть связана с одной записью (но не обязательно).

Когда мы создаем expedition и хотим «прикрепить» его к записи, мы пришли к двум решениям :

  1. POST /expeditions?recordId=xxx
  2. POST /records/xxx/expeditions и POST /expeditions WS для независимого создания экспедиций.

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

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

Спасибо.

Ответ №1:

Какие соображения могут помочь нам выбрать ?

Подумайте о недействительности кэша.

HTTP касается передачи документов. Мы получаем информацию от сервера, запрашивая копию документа; этот запрос может быть обработан самим сервером, или он может быть обработан кэшем, в котором есть действительная копия документа.

Мы отправляем информацию на сервер, предлагая изменения в документах — POST является наиболее распространенным методом, используемым для этого (через HTML-формы).

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

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

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

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

(Да, это означает, что если мы собираемся вносить разные изменения в документ, все разные изменения будут использовать один и тот же целевой uri, и мы устраняем неоднозначность редактирования, просматривая другие части запроса — например, анализируя тело.)


POST /records/xxx/expeditions и POST /expeditions WS для независимого создания экспедиций.

Это не обязательно — серверу разрешено применять изменения к нескольким документам; HTTP ограничивает значение запроса, но не ограничивает эффекты.

Тем не менее, кэши общего назначения не будут волшебным образом знать, что оба документа были отредактированы. В какой-то степени часть того, что вы выбираете в своем дизайне, заключается в том, какой документ необходимо обновить сейчас, а какие из них могут устареть на какое-то время (обычно до тех пор, пока кэшированное представление не достигнет своего максимального возраста).).


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

 POST /foo/bar

...
 
 200 OK
Content-Location: /foo
 

В этой последовательности заголовки общего назначения аннулируют свои кэшированные копии обоих /foo и /foo/bar .

(конечно, все еще есть проблемы, поскольку у нас нет механизма для возврата как обновленной копии, так /foo и обновленной копии /bar в одном ответе. Поэтому вместо этого нам нужно рассмотреть другие идеи, такие как server push).

Ответ №2:

Спроектируйте пути URL таким образом, чтобы ресурсы можно было легко получить.

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

Второй подход, возможно, это сработает, поскольку вы создаете экспедицию под связанной записью xxx, т.Е. /records/xxx/expeditions . Но это может стать сложной задачей в сценарии, когда экспедиция не связана ни с какой записью.

Другая альтернативная мысль здесь заключается в том, чтобы связать экспедицию и запись через полезную нагрузку, т.Е. Иметь идентификатор записи XXX в полезной нагрузке POST во время создания ресурса «экспедиции». POST /expedition => Эта операция вернет вам идентификатор экспедиции в ответ при новом создании ресурса. Затем для извлечения данных вы можете использовать GET /expedition/XXX/record где XXX — идентификатор экспедиции, и вы извлекаете запись, соответствующую XXX. В этом случае вам не нужно указывать идентификатор записи. Вы либо получаете связанную запись, либо нет (в случае, если нет записи, привязанной к экспедиции). Чтобы получить саму экспедицию, URL-адрес может быть GET /expedition/XXX .