verbos tutorial tag sobre servicios responder raras preguntas para nomenclatura metodos lista hacer espaƱol ejemplo cosas consejos con completar amigos rest

tutorial - REST-poner ID en el cuerpo o no?



tags para responder (9)

En una inserción, no necesita agregar la identificación en la URL. De esta manera, si envía una ID en un PUT, puede interpretarlo como una ACTUALIZACIÓN para cambiar la clave principal.

  1. INSERTAR:

    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"}

  2. ACTUALIZAR

    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"}

La API JSON utiliza este estándar y resuelve algunos problemas al devolver el objeto insertado o actualizado con un enlace al nuevo objeto. Algunas actualizaciones o inserciones pueden incluir cierta lógica empresarial que cambiará campos adicionales

También verá que puede evitar la obtención después de la inserción y actualización.

Digamos que quiero tener un recurso RESTful para personas, donde el cliente pueda asignar ID.

Una persona se ve así: {"id": <UUID>, "name": "Jimmy"}

Ahora, ¿cómo debe guardarlo el cliente (o "PUT")?

  1. PUT /person/UUID {"id": <UUID>, "name": "Jimmy"} - ahora tenemos esta desagradable duplicación que tenemos que verificar todo el tiempo: ¿La ID en el cuerpo coincide con la de la ruta?
  2. Representación asimétrica:
    • PUT /person/UUID {"name": "Jimmy"}
    • GET /person/UUID devuelve {"id": <UUID>, "name": "Jimmy"}
  3. Sin ID en el cuerpo: ID solo en la ubicación:
    • PUT /person/UUID {"name": "Jimmy"}
    • GET /person/UUID devuelve {"name": "Jimmy"}
  4. Ningún tipo de POST parece una buena idea ya que el ID genera el ID.

¿Cuáles son los patrones comunes y las formas de resolverlo? Las identificaciones solo en la ubicación parecen la forma más dogmática correcta, pero también dificulta la implementación práctica.


Es posible que deba analizar los tipos de solicitud PATCH / PUT.

Las solicitudes PATCH se usan para actualizar un recurso parcialmente, mientras que en las solicitudes PUT, debe enviar todo el recurso donde se anula en el servidor.

En cuanto a tener una ID en la URL, creo que siempre debe tenerla, ya que es una práctica estándar identificar un recurso. Incluso la API Stripe funciona de esa manera.

Puede usar una solicitud PATCH para actualizar un recurso en el servidor con ID para identificarlo, pero no actualice la ID real.



Estoy mirando esto desde el punto de vista de JSON-LD / Semantic Web porque esa es una buena manera de lograr una verdadera conformidad REST como lo he descrito en estas diapositivas . Mirándolo desde esa perspectiva, no hay duda de ir a la opción (1.) ya que la ID (IRI) de un recurso web siempre debe ser igual a la URL que puedo usar para buscar / desreferenciar el recurso. Creo que la verificación no es realmente difícil de implementar ni computacionalmente intensa; así que no considero que esta sea una razón válida para ir con la opción (2.). Creo que la opción (3.) no es realmente una opción ya que POST (crear nuevo) tiene una semántica diferente a PUT (actualizar / reemplazar).


No hay nada de malo en tener diferentes modelos de lectura / escritura: el cliente puede escribir una representación de recursos donde después del servidor puede devolver otra representación con elementos agregados / calculados (o incluso una representación completamente diferente; no hay nada en ninguna especificación en contra de eso , el único requisito es que PUT debe crear o reemplazar el recurso).

Así que iría por la solución asimétrica en (2) y evitaría la "verificación de duplicación desagradable" en el lado del servidor al escribir:

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


No hay nada malo en usar diferentes enfoques. pero creo que la mejor manera es la solución con 2nd .

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

se usa principalmente de esta manera, incluso el marco de la entidad usa esta técnica cuando la entidad se agrega en dbContext, la clase sin el ID generado es ID generado por referencia en Entity Framework.


Si bien está bien tener diferentes representaciones para diferentes operaciones, una recomendación general para PUT es contener TODA la carga útil . Eso significa que la id debería estar allí. De lo contrario, debe usar PATCH.

Dicho esto, creo que PUT debe utilizarse principalmente para actualizaciones y la id siempre debe pasarse en la URL también. Como resultado de eso, usar PUT para actualizar el identificador de recursos es una mala idea. Nos deja en una situación indeseable cuando la id en la URL puede ser diferente de la id en el cuerpo.

Entonces, ¿cómo resolvemos tal conflicto? Básicamente tenemos 2 opciones:

  • lanzar una excepción 4XX
  • agregue un encabezado de Warning ( X-API-Warn etc.).

Eso es lo más cerca que puedo llegar a responder esta pregunta porque el tema en general es una cuestión de opinión.


Si se trata de una API pública, debe ser conservador cuando responda, pero aceptar generosamente.

Con eso quiero decir, debes apoyar tanto 1 como 2. Estoy de acuerdo en que 3 no tiene sentido.

La forma de admitir tanto 1 como 2 es obtener el ID de la url si no se proporciona ninguno en el cuerpo de la solicitud, y si está en el cuerpo de la solicitud, valide que coincida con el ID en la url. Si los dos no coinciden, devuelva una respuesta de 400 Solicitud incorrecta.

Cuando devuelva un recurso de persona, sea conservador e incluya siempre la identificación en el json, aunque sea opcional en el put.


Una solución a este problema involucra el concepto algo confuso de "Hipertexto como el motor del estado de la aplicación" o "HATEOAS". Esto significa que una respuesta REST contiene los recursos o acciones disponibles para realizar como hipervínculos. Usando este método, que era parte de la concepción original de REST, los identificadores / ID únicos de los recursos son en sí mismos hipervínculos. Entonces, por ejemplo, podrías tener algo como:

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

Luego, si desea actualizar ese recurso, puede hacer (pseudocódigo):

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

Una ventaja de esto es que el cliente no tiene que tener ninguna idea sobre la representación interna de ID de usuario del servidor. Las ID podrían cambiar, e incluso las URL mismas podrían cambiar, siempre que el cliente tenga una forma de descubrirlas. Por ejemplo, al obtener una colección de personas, puede devolver una respuesta como esta:

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

(Por supuesto, también puede devolver el objeto de persona completa para cada persona, según las necesidades de la aplicación).

Con este método, piensa en sus objetos más en términos de recursos y ubicaciones, y menos en términos de ID. La representación interna del identificador único se desacopla de la lógica de su cliente. Este fue el ímpetu original detrás de REST: crear arquitecturas cliente-servidor que están más libremente acopladas que los sistemas RPC que existían antes, mediante el uso de las características de HTTP. Para obtener más información sobre HATEOAS, consulte el artículo de Wikipedia y este breve artículo .