Cree una solicitud con POST, cuyos códigos de respuesta 200 o 201 y contenido


125

Supongamos que escribo un servicio REST cuya intención es agregar un nuevo elemento de datos a un sistema.

Planeo PUBLICAR en

http://myhost/serviceX/someResources

Supongamos que funciona, ¿qué código de respuesta debo usar? Y qué contenido podría devolver.

Estoy mirando las definiciones de los códigos de respuesta HTTP y veo estas posibilidades:

200: Devuelve una entidad que describe o contiene el resultado de la acción;

201: que significa CREADO. Significado * La solicitud se ha cumplido y se ha creado un nuevo recurso. El recurso recién creado puede ser referenciado por los URI devueltos en la entidad de la respuesta, con el URI más específico para el recurso dado por un campo de encabezado de Ubicación. La respuesta DEBE incluir una entidad que contenga una lista de características de recursos y ubicaciones de las cuales el usuario o agente de usuario puede elegir la más apropiada. El formato de entidad se especifica por el tipo de medio dado en el campo de encabezado Tipo de contenido. * *

Este último suena más en línea con la especificación Http, pero no estoy del todo claro qué

La respuesta DEBE incluir una entidad que contenga una lista de características y ubicaciones del recurso

medio.

Recomendaciones? Interpretaciones?

Respuestas:


77

La idea es que el cuerpo de respuesta te dé una página que te vincule a la cosa:

201 Creado

El código de estado 201 (Creado) indica que la solicitud se ha cumplido y se ha creado uno o más recursos nuevos. El recurso primario creado por la solicitud se identifica mediante un campo de encabezado de Ubicación en la respuesta o, si no se recibe ningún campo de Ubicación, mediante el URI de solicitud efectivo.

Esto significa que se incluiría una Locationen la respuesta de cabecera que da a la URL de donde se puede encontrar la recién creada cosa :

HTTP/1.1 201 Created
Date: Sat, 02 Apr 2016 12:22:40 GMT
Location: http://stackoverflow.com/a/36373586/12597

Cuerpo de respuesta

Luego mencionan lo que debe incluir en el cuerpo de respuesta :

La carga útil de 201 respuestas generalmente describe y enlaza a los recursos creados.

Para los humanos que usan el navegador, les das algo que pueden mirar y hacer clic para acceder a su recurso recién creado:

HTTP/1.1 201 Created
Date: Sat, 02 Apr 2016 12:22:40 GMT
Location: http://stackoverflow.com/a/36373586/12597
Content-Type: text/html

Your answer has been saved! 
Click <A href="https://stackoverflow.com/a/36373586/12597">here</A> to view it.

Si la página solo será utilizada por un robot, tiene sentido que la respuesta sea legible por computadora:

HTTP/1.1 201 Created
Date: Sat, 02 Apr 2016 12:22:40 GMT
Location: http://stackoverflow.com/a/36373586/12597
Content-Type: application/xml

<createdResources>
   <questionID>1860645</questionID>
   <answerID>36373586</answerID>
   <primary>/a/36373586/12597</primary>
   <additional>
      <resource>http://stackoverflow.com/questions/1860645/create-request-with-post-which-response-codes-200-or-201-and-content/36373586#36373586</resource>
      <resource>http://stackoverflow.com/a/1962757/12597</resource>
   </additional>
</createdResource>

O, si lo prefieres:

HTTP/1.1 201 Created
Date: Sat, 02 Apr 2016 12:22:40 GMT
Location: http://stackoverflow.com/a/36373586/12597
Content-Type: application/json

{ 
   "questionID": 1860645, 
   "answerID": 36373586,
   "primary": "/a/36373586/12597",
   "additional": [
      "http://stackoverflow.com/questions/1860645/create-request-with-post-which-response-codes-200-or-201-and-content/36373586#36373586",
      "http://stackoverflow.com/a/36373586/12597"
   ]
}

La respuesta es totalmente suya; es arbitrariamente lo que te gustaría.

Caché amigable

Finalmente, está la optimización de que puedo almacenar previamente en caché el recurso creado (porque ya tengo el contenido; lo acabo de cargar). El servidor puede devolver una fecha o ETag que puedo almacenar con el contenido que acabo de cargar:

Consulte la Sección 7.2 para una discusión sobre el significado y el propósito de los campos de encabezado del validador, como ETag y Last-Modified, en una respuesta 201.

HTTP/1.1 201 Created
Date: Sat, 02 Apr 2016 12:22:40 GMT
Location: http://stackoverflow.com/a/23704283/12597
Content-Type: text/html
ETag: JF2CA53BOMQGU5LTOQQGC3RAMV4GC3LQNRSS4
Last-Modified: Sat, 02 Apr 2016 12:22:39 GMT 

Your answer has been saved! 
Click <A href="https://stackoverflow.com/a/36373586/12597">here</A> to view it.

Y ETags son valores puramente arbitrarios. Lo único que importa es que sean diferentes cuando un recurso cambia (y las memorias caché deben actualizarse). El ETag suele ser un hash (por ejemplo, SHA2). Pero puede ser una base de datos rowversiono un número de revisión incremental. Cualquier cosa que cambie cuando la cosa cambie.


Hasta ahora su respuesta parece más sensata. Estoy un poco ansioso por la ontología de la respuesta, pero aparte de eso, parece la interpretación más madura de la especificación. Tengo curiosidad por saber si hay algún tipo de forma liviana "receptiva" para manejar la salida humana / máquina. pero sobre todo estoy intrigado por su sugerencia de "almacenamiento en caché de su propia entrada". La mayoría de las aplicaciones web que conozco no van a crear una versión 1: 1 del recurso. Incluso si es algo trivial como normalizar la capitalización de una cadena. ¿No es un poco dudoso tratar la versión presentada como la versión con la que se creó el etag?
Anthony

1
@ Anthony, almacenamiento en caché: podría ser una especie de aplicación de almacenamiento de archivos 1: 1. Compare, por ejemplo, WebDAV PUT & POST. Enormes archivos para ser manejados.
kxr

@ Anthony Depende de usted si desea devolver un ETag al cliente. Si el contenido que el cliente acaba de cargar no es lo que guardó, no devuelva el ETag. Es tu flexibilidad y tu elección.
Ian Boyd

¿Por qué a sus respuestas les falta la longitud del contenido?
Vinnie Falco

1
@VinnieFalco Esta es una respuesta sobre el código de respuesta 201. Content-Length se ha elidido con fines expositivos.
Ian Boyd el

91

Creo que la API REST de atompub es un gran ejemplo de un servicio tranquilo. Vea el fragmento a continuación de la especificación atompub:

POST /edit/ HTTP/1.1
Host: example.org
User-Agent: Thingio/1.0
Authorization: Basic ZGFmZnk6c2VjZXJldA==
Content-Type: application/atom+xml;type=entry
Content-Length: nnn
Slug: First Post

<?xml version="1.0"?>
<entry xmlns="http://www.w3.org/2005/Atom">
  <title>Atom-Powered Robots Run Amok</title>
  <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  <updated>2003-12-13T18:30:02Z</updated>
  <author><name>John Doe</name></author>
  <content>Some text.</content>
</entry>

El servidor señala una creación exitosa con un código de estado de 201. La respuesta incluye un encabezado de ubicación que indica el URI de entrada de miembro de la entrada de átomo y una representación de esa entrada en el cuerpo de la respuesta.

HTTP/1.1 201 Created
Date: Fri, 7 Oct 2005 17:17:11 GMT
Content-Length: nnn
Content-Type: application/atom+xml;type=entry;charset="utf-8"
Location: http://example.org/edit/first-post.atom
ETag: "c180de84f991g8"  

<?xml version="1.0"?>
<entry xmlns="http://www.w3.org/2005/Atom">
  <title>Atom-Powered Robots Run Amok</title>
  <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  <updated>2003-12-13T18:30:02Z</updated>
  <author><name>John Doe</name></author>
  <content>Some text.</content>
  <link rel="edit"
      href="http://example.org/edit/first-post.atom"/>
</entry>

Es posible que la Entrada creada y devuelta por la Colección no coincida con la Entrada PUBLICADA por el cliente. Un servidor PUEDE cambiar los valores de varios elementos en la Entrada, como los valores atom: id, atom: updated y atom: author, y PUEDE elegir eliminar o agregar otros elementos y atributos, o cambiar el contenido del elemento y los valores de los atributos.


9
Devolver el recurso creado puede ser un poco demasiado, si el recurso está en la magnitud de gigabytes ...
Tor Valamo

10
¡Convenido! Esa es la optimización de la necesidad, pero no desea hacerlo prematuramente. Es importante diseñar con espíritu tranquilo y hacer excepciones solo cuando sea necesario.
Chandra Patni

3
@ChandraPatni, Atom está muerto . Necesito mejores ejemplos.
Pacerier

16
Atom puede estar muerto, pero el espíritu del ejemplo sigue siendo acertado.
Ashimema

2
Mi interpretación original de la respuesta 201 fue más como "oye, querías crear un recurso, pero según el contexto, o no estabas interesado en el resultado final, o tenías acceso de escritura pero no acceso de lectura a este recurso. caso, todo lo que necesita antes de regresar a la colección principal es la URL del recurso creado. Como evidencia de que se creó ". Cualquier cosa más allá de eso parece una respuesta de 200, esencialmente. A menos que el RFC tuviera algo más en mente.
Anthony

50

En pocas palabras:

  • 200 cuando se crea y devuelve un objeto
  • 201 cuando se crea un objeto pero solo se devuelve su referencia (como un ID o un enlace)

¿Fuente para esto?
sudo soul


3
Después de leer tools.ietf.org/html/rfc7231#section-6.3.1 , estoy de acuerdo con este entendimiento. Supongo que estaba preguntando más cómo llegaste a él. Pero ahora en mi entendimiento ... 200 = recurso creado y devuelto | 201 = recurso creado y se devuelve la referencia | 204 = recurso creado y no se devuelve ninguna carga útil
sudo soul

34

Consulte HTTP: Definiciones de métodos: POST .

La acción realizada por el método POST podría no dar como resultado un recurso que pueda ser identificado por un URI. En este caso, 200 (OK) o 204 (Sin contenido) es el estado de respuesta apropiado, dependiendo de si la respuesta incluye o no una entidad que describa el resultado.

Si se creó un recurso en el servidor de origen, la respuesta DEBERÍA ser 201 (Creado) y contener una entidad que describa el estado de la solicitud y se refiera al nuevo recurso, y un encabezado de Ubicación (ver sección 14.30).


18

http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.19

Es solo un valor clave delimitado por dos puntos.

ETag: "xyzzy"

Puede ser cualquier tipo de datos de texto: generalmente incluyo una cadena JSON con el identificador del elemento creado. La facilidad de las pruebas solo hace que valga la pena incluirlo.

ETag: "{ id: 1234, uri: 'http://domain.com/comments/1234', type: 'comment' }"

En este ejemplo, el identificador, la uri y el tipo del elemento creado son las "características y ubicación del recurso".


3
Está diciendo que un ETag corresponde a una entidad que contiene una lista de características de recursos y ubicaciones . Puedo ver que su sugerencia es buena, estoy muy de acuerdo con su punto sobre las pruebas. Sin embargo, no veo cómo encaja esto con "una lista de características y ubicaciones de recursos".
djna

La "lista de características y ubicaciones de los recursos" sería el contenido de cualquier estructura de datos proporcionada. Una implementación más estricta sería que la estructura JSON incluya el recurso uri y tal vez el tipo de recurso que se creó. Ajustaré la respuesta como tal.
tempire

77
Especifique los problemas para que las personas puedan aprender. De lo contrario, el comentario solo se agita a mano.
tempire

@SimonGibbs ¿Qué problemas?
MEMark

2
Si bien es estrictamente correcto según las especificaciones, recomienda una opción de implementación altamente inusual. Además, en realidad no responde la pregunta en la parte superior de la página (o lo hace mezclando las palabras ETag y entidad). La respuesta con 43 votos es probablemente mejor.
Simon Gibbs

1

La salida depende realmente del tipo de contenido que se solicita. Sin embargo, como mínimo, debe colocar el recurso que se creó en Ubicación. Al igual que el patrón Post-Redirect-Get.

En mi caso, lo dejo en blanco hasta que se solicite lo contrario. Dado que ese es el comportamiento de JAX-RS cuando se utiliza Response.created ().

Sin embargo, solo tenga en cuenta que los navegadores y marcos como Angular no siguen los 201 automáticamente. He notado el comportamiento en http://www.trajano.net/2013/05/201-created-with-angular-resource/


-2

Otra respuesta que tendría para esto sería adoptar un enfoque pragmático y mantener su contrato REST API simple. En mi caso, había refactorizado mi API REST para hacer que las cosas sean más comprobables sin recurrir a JavaScript o XHR, solo simples formularios y enlaces HTML.

Entonces, para ser más específico en su pregunta anterior, simplemente usaría el código de retorno 200y hacer que el mensaje devuelto contenga un mensaje JSON que su aplicación pueda entender. Dependiendo de sus necesidades, puede requerir la identificación del objeto que se acaba de crear para que la aplicación web pueda obtener los datos en otra llamada.

Una nota, en mi contrato API refactorizado, las respuestas POST no deben contener ningún dato almacenable en caché ya que los POST no son realmente almacenables en caché, así que limítelo a ID que se pueden solicitar y almacenar en caché utilizando una solicitud GET.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.