#api #rest
#API #rest
Вопрос:
В настоящее время мы пытаемся разработать некоторый REST api для наших веб-сервисов. У нас есть два ресурса: «запись» и «экспедиция». Насколько нам известно, запись может быть связана с несколькими экспедициями, а экспедиция может быть связана с одной записью (но не обязательно).
Когда мы создаем expedition и хотим «прикрепить» его к записи, мы пришли к двум решениям :
POST /expeditions?recordId=xxx
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
.