Подтвердить что ты не робот

REST - поместить идентификаторы в тело или нет?

Скажем, я хочу иметь ресурс RESTful для людей, где клиент может назначить идентификатор.

Человек выглядит так: {"id": <UUID>, "name": "Jimmy"}

Теперь, как клиент должен сохранить (или "PUT" )?

  • PUT /person/UUID {"id": <UUID>, "name": "Jimmy"} - теперь у нас есть это неприятное дублирование, которое мы должны проверять все время: соответствует ли идентификатор в теле тем, что находится в пути?
  • Асимметричное представление:
    • PUT /person/UUID {"name": "Jimmy"}
    • GET /person/UUID возвращает {"id": <UUID>, "name": "Jimmy"}
  • Нет идентификаторов в теле - ID только в местоположении:
    • PUT /person/UUID {"name": "Jimmy"}
    • GET /person/UUID возвращает {"name": "Jimmy"}
  • Никакой тип POST не кажется хорошей идеей, так как идентификатор создается клиентом.

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

4b9b3361

Ответ 1

Нет ничего плохого в том, что у меня разные модели чтения/записи: клиент может написать одно представление ресурса, где после того, как сервер может вернуть другое представление с добавленными/вычисленными элементами в нем (или даже совершенно другим представлением - нет ничего в spec против этого, единственным требованием является то, что PUT должен создать или заменить ресурс).

Итак, я пошел бы на асимметричное решение в (2) и избегал "неприятной проверки дублирования" на стороне сервера при написании:

PUT /person/UUID {"name": "Jimmy"}

GET /person/UUID returns {"id": <UUID>, "name": "Jimmy"}

Ответ 2

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

Под этим я подразумеваю, что вы должны поддерживать как 1, так и 2. Я согласен, что 3 не имеет смысла.

Способ поддержки как 1, так и 2 состоит в том, чтобы получить идентификатор из URL-адреса, если в тело запроса не указано ни одного, и если он находится в теле запроса, проверьте, соответствует ли он идентификатору в URL-адресе. Если эти два не совпадают, верните ответ 400 Bad Request.

При возврате ресурса человека быть консервативным и всегда включать id в json, даже если он не является обязательным в put.

Я не хочу быть педантичным, так что это последнее, что вы совершенно можете игнорировать, но некоторые люди хотят, чтобы их сказали, если их грамматика ошибочна. Если вы этого не сделаете, я извиняюсь перед вами. "люди" - это множественное число "человек", а не "лица". Таким образом, URL-адрес коллекции должен быть ~/people

Ответ 3

Одним из решений этой проблемы является несколько запутанная концепция "Hypertext As Engine of Application State" или "HATEOAS". Это означает, что ответ REST содержит доступные ресурсы или действия, которые должны выполняться как гиперссылки. Используя этот метод, который был частью первоначальной концепции REST, уникальные идентификаторы/идентификаторы ресурсов сами являются гиперссылками. Так, например, у вас может быть что-то вроде:

GET /person/<UUID> {"person": {"location": "/person/<UUID>", "data": { "name": "Jimmy"}}}

Затем, если вы хотите обновить этот ресурс, вы можете сделать (псевдокод):

updatedPerson = person.data
updatedPerson.name = "Timmy"
PUT(URI: response.resource, data: updatedPerson)

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

GET /people
{ "people": [
    "/person/1",
    "/person/2"
  ]
}

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

С помощью этого метода вы считаете, что ваши объекты больше с точки зрения ресурсов и местоположений, и меньше с точки зрения идентификатора. Внутреннее представление уникального идентификатора, таким образом, отделено от вашей клиентской логики. Это был оригинальный стимул для REST: создать архитектуры клиент-сервер, которые более слабо связаны, чем системы RPC, существовавшие до этого, с использованием функций HTTP. Для получения дополнительной информации о HATEOAS, посмотрите статью Википедии, а также short статья.

Ответ 4

Это было задано раньше - обсуждение стоит посмотреть:

Должен ли ответ RESTful GET вернуть идентификатор ресурса?

Это один из тех вопросов, где легко увязнуть в дискуссии вокруг что такое и не является "RESTful" .

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

Ответ 5

Возможно, вам придется искать типы запросов PATCH/PUT.

Запросы PATCH используются для обновления ресурса частично, тогда как в запросах PUT вам необходимо отправить весь ресурс, где он будет переопределен на сервере.

Что касается наличия идентификатора в URL-адресе, я думаю, вы всегда должны иметь его, поскольку стандартная практика заключается в определении ресурса. Даже API-интерфейс Stripe работает именно так.

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

Ответ 6

Я смотрю на это с JSON-LD/точки семантической сети, потому что это хороший способ достичь реального REST как я описал в эти слайды. Рассматривая это с этой точки зрения, нет необходимости искать вариант (1.), поскольку идентификатор (IRI) веб-ресурса всегда должен быть равен URL-адресу, который я могу использовать для поиска/разыменования ресурса. Я считаю, что проверка на самом деле не очень сложна, и она не интенсивно вычисляется; поэтому я не считаю это действительной причиной для перехода с опцией (2.). Я думаю, что вариант (3.) на самом деле не вариант, поскольку POST (create new) имеет другую семантику, чем PUT (update/replace).

Ответ 7

Недавно я искал веб-службы Rest и установил шаблоны, и этот веб-сайт должен помочь.

Ответ 8

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

 PUT /person/UUID {"name": "Jimmy"}

 GET /person/UUID returns {"id": <UUID>, "name": "Jimmy"}

в основном используется таким образом , даже инфраструктура сущности использует этот метод, когда объект добавляется в dbContext, класс без сгенерированного идентификатора - это идентификатор, сгенерированный по ссылке в Entity Framework.

Ответ 9

Вставить вам не нужно добавлять идентификатор в URL. Таким образом, если вы отправите идентификатор в PUT, вы можете интерпретировать его как UPDATE для изменения первичного ключа.

  • ВСТАВИТЬ:

    PUT /persons/ 
      {"id": 1, "name": "Jimmy"}
    HTTP/1.1 201 Created     
      {"id": 1, "name": "Jimmy", "other_field"="filled_by_server"}
    
    GET /persons/1
    
    HTTP/1.1 200 OK
      {"id": 1, "name": "Jimmy", "other_field"="filled_by_server"}  
    
  • UPDATE

    PUT /persons/1 
         {"id": "2", "name": "Jimmy Jr"} - 
    HTTP/1.1 200 OK
         {"id": "2", "name": "Jimmy Jr", "other_field"="filled_by_server"}
    
    GET /persons/2 
    
    HTTP/1.1 200 OK
         {"id": "2", "name": "Jimmy Jr", "other_field"="updated_by_server"}
    

JSON API использует этот стандарт и решает некоторые проблемы, возвращающие вставленный или обновленный объект со ссылкой на новый объект. Некоторые обновления или вставки могут включать некоторую бизнес-логику, которая изменит дополнительные поля

Вы также увидите, что вы можете избежать получения после вставки и обновления.