Comprender REST: verbos, códigos de error y autenticación

Estoy buscando una forma de ajustar las API en torno a las funciones predeterminadas en mis aplicaciones web basadas en PHP, bases de datos y CMS.

Miré alrededor y encontré varios esqueletos “esqueleto”. Además de las respuestas en mi pregunta, está Tonic , un marco REST que me gusta porque es muy liviano.

ME GUSTA REST lo mejor por su simplicidad y me gustaría crear una architecture de API basada en él. Estoy tratando de entender los principios básicos y aún no lo he entendido del todo. Por lo tanto, una serie de preguntas.

1. ¿Lo estoy entendiendo bien?

Digamos que tengo un recurso “usuarios”. Podría configurar varios URI como ese:

/api/users when called with GET, lists users /api/users when called with POST, creates user record /api/users/1 when called with GET, shows user record when called with PUT, updates user record when called with DELETE, deletes user record 

¿Es esta una representación correcta de una architecture RESTful hasta el momento?

2. Necesito más verbos

Crear, actualizar y eliminar puede ser suficiente en teoría, pero en la práctica tendré la necesidad de muchos más verbos. Me doy cuenta de que estos son elementos que podrían integrarse en una solicitud de actualización, pero son acciones específicas que pueden tener códigos de retorno específicos y no me gustaría incluirlos en una sola acción.

Algunos que vienen a la mente en el ejemplo del usuario son:

 activate_login deactivate_login change_password add_credit 

¿Cómo expressía acciones como las de una architecture RESTful URL?

Mi instinto sería hacer una llamada GET a una URL como

 /api/users/1/activate_login 

y esperar un código de estado de vuelta.

Sin embargo, eso se desvía de la idea de usar verbos HTTP. ¿Qué piensas?

3. Cómo devolver mensajes de error y códigos

Una gran parte de la belleza de REST proviene del uso de métodos HTTP estándar. En caso de error, emito un encabezado con un código de estado de error 3xx, 4xx o 5xx. Para una descripción detallada del error, puedo usar el cuerpo (¿verdad?). Hasta aquí todo bien. Pero, ¿cuál sería la forma de transmitir un código de error propietario que sea más detallado al describir lo que salió mal (por ejemplo, “no se pudo conectar a la base de datos”, o “error de inicio de sesión en la base de datos”)? Si lo pongo en el cuerpo junto con el mensaje, tengo que analizarlo después. ¿Hay un encabezado estándar para este tipo de cosas?

4. Cómo hacer la autenticación

  • ¿Qué aspecto tendría una autenticación basada en claves API según los principios de REST?
  • ¿Hay puntos fuertes contra el uso de sesiones al autenticar un cliente REST, aparte de eso, es una flagrante violación del principio REST? 🙂 (Es medio broma, la autenticación basada en sesiones funcionaría bien con mi infraestructura existente).

Noté esta pregunta un par de días tarde, pero siento que puedo agregar algo de información. Espero que esto pueda ser útil para su empresa RESTful.


Punto 1: ¿Lo estoy entendiendo bien?

Usted entendió bien. Esa es una representación correcta de una architecture RESTful. Puede encontrar la siguiente matriz de Wikipedia muy útil para definir sus sustantivos y verbos:


Cuando se trata de un URI de colección como: http://example.com/resources/

  • OBTENER : enumere los miembros de la colección, complete con sus URI de miembro para mayor navegación. Por ejemplo, enumere todos los autos en venta.

  • PUT : Significado definido como “reemplazar toda la colección con otra colección”.

  • POST : crea una nueva entrada en la colección donde el ID es asignado automáticamente por la colección. La ID creada generalmente se incluye como parte de los datos devueltos por esta operación.

  • BORRAR : Significado definido como “eliminar toda la colección”.


Cuando se trata de un URI de miembro como: http://example.com/resources/7HOU57Y

  • GET : recupera una representación del miembro direccionado de la colección expresada en un tipo MIME apropiado.

  • PUT : actualice el miembro direccionado de la colección o créelo con la ID especificada.

  • POST : trata el miembro direccionado como una colección por derecho propio y crea un nuevo subordinado de él.

  • ELIMINAR : elimina el miembro direccionado de la colección.


Punto 2: necesito más verbos

En general, cuando crees que necesitas más verbos, en realidad puede significar que tus recursos deben volver a identificarse. Recuerde que en REST siempre actúa sobre un recurso o sobre una colección de recursos. Lo que elijas como recurso es bastante importante para tu definición de API.

Activar / desactivar inicio de sesión : si está creando una nueva sesión, entonces puede considerar “la sesión” como el recurso. Para crear una nueva sesión, use POST para http://example.com/sessions/ con las credenciales en el cuerpo. Para caducar, use PUT o un DELETE (dependiendo de si tiene la intención de mantener un historial de la sesión) en http://example.com/sessions/SESSION_ID .

Cambiar contraseña: esta vez el recurso es “el usuario”. Necesitará un PUT para http://example.com/users/USER_ID con las contraseñas antiguas y nuevas en el cuerpo. Está actuando sobre el recurso “usuario” y una contraseña de cambio es simplemente una solicitud de actualización. Es bastante similar a la instrucción UPDATE en una base de datos relacional.

Mi instinto sería hacer una llamada GET a una URL como /api/users/1/activate_login

Esto va en contra de un principio fundamental de REST: el uso correcto de los verbos HTTP. Cualquier solicitud GET nunca debe dejar ningún efecto secundario.

Por ejemplo, una solicitud GET nunca debe crear una sesión en la base de datos, devolver una cookie con una nueva ID de sesión o dejar ningún residuo en el servidor. El verbo GET es como la instrucción SELECT en un motor de base de datos. Recuerde que la respuesta a cualquier solicitud con el verbo GET debe ser almacenable en caché cuando se solicite con los mismos parámetros, al igual que cuando solicita una página web estática.


Punto 3: Cómo devolver mensajes de error y códigos

Considere los códigos de estado HTTP 4xx o 5xx como categorías de error. Puedes elaborar el error en el cuerpo.

Error al conectarse a la base de datos: / Inicio de sesión incorrecto en la base de datos : en general, debe usar un error 500 para este tipo de errores. Este es un error del lado del servidor. El cliente no hizo nada mal. 500 errores normalmente se consideran “recuperables”. es decir, el cliente puede volver a intentar la misma solicitud exacta y esperar que tenga éxito una vez resueltos los problemas del servidor. Especifique los detalles en el cuerpo, para que el cliente pueda proporcionarnos un contexto a los humanos.

La otra categoría de errores sería la familia 4xx, que en general indica que el cliente hizo algo mal. En particular, esta categoría de errores normalmente indica al cliente que no es necesario volver a intentar la solicitud tal como está, porque continuará fallando permanentemente. es decir, el cliente necesita cambiar algo antes de volver a intentar esta solicitud. Por ejemplo, los errores “Recurso no encontrado” (HTTP 404) o “Solicitud mal formada” (HTTP 400) entrarían en esta categoría.


Punto 4: Cómo hacer la autenticación

Como se señaló en el punto 1, en lugar de autenticar a un usuario, es posible que desee pensar en crear una sesión. Se le devolverá una nueva “ID de sesión”, junto con el código de estado HTTP apropiado (200: Acceso otorgado o 403: Acceso denegado).

Luego le preguntará a su servidor RESTful: “¿PUEDE OBTENER el recurso para este ID de sesión?”.

No hay un modo autenticado – REST no tiene estado: usted crea una sesión, le pide al servidor que le proporcione recursos usando esta ID de sesión como parámetro, y al cerrar la sesión deja caer o expira la sesión.

En pocas palabras, estás haciendo esto completamente al revés.

No debería acercarse a esto desde qué URL debería usar. Las URL aparecerán “de forma gratuita” una vez que haya decidido qué recursos son necesarios para su sistema Y cómo representará esos recursos, y las interacciones entre los recursos y el estado de la aplicación.

Para citar a Roy Fielding

Una API REST debería dedicar casi todo su esfuerzo descriptivo a definir los tipos de medios utilizados para representar los recursos y dirigir el estado de las aplicaciones, o al definir nombres de relaciones extendidas y / o márgenes habilitados para hipertexto para los tipos de medios estándar existentes. Cualquier esfuerzo dedicado describiendo qué métodos usar en qué URI de interés debería estar completamente definido dentro del scope de las reglas de procesamiento para un tipo de medio (y, en la mayoría de los casos, ya definido por los tipos de medios existentes). [La falla aquí implica que la información fuera de banda genera interacción en lugar de hipertexto.]

Las personas siempre comienzan con los URI y piensan que esta es la solución, y luego tienden a perder un concepto clave en la architecture REST, notablemente, como se mencionó anteriormente, “El fracaso aquí implica que la información fuera de banda está impulsando la interacción en lugar del hipertexto. ”

Para ser honesto, muchos ven un montón de URI y algunos GET y PUT y POST y piensan que REST es fácil. RESTO no es fácil. RPC a través de HTTP es fácil, es fácil mover bloques de datos de un lado a otro a través de cargas HTTP. REST, sin embargo, va más allá de eso. REST es un protocolo agnóstico. HTTP es muy popular y apto para sistemas REST.

REST vive en los tipos de medios, sus definiciones y cómo la aplicación dirige las acciones disponibles a esos recursos a través de hipertexto (enlaces, efectivamente).

Hay diferentes puntos de vista acerca de los tipos de medios en los sistemas REST. Algunos favorecen las cargas útiles específicas de la aplicación, mientras que otros prefieren elevar los tipos de medios existentes a los roles que son apropiados para la aplicación. Por ejemplo, por un lado, tiene esquemas XML específicos diseñados para su aplicación, en lugar de usar algo como XHTML como representación, tal vez a través de microformatos y otros mecanismos.

Ambos enfoques tienen su lugar, creo, el XHTML funciona muy bien en escenarios que se superponen tanto a la web impulsada por humanos como a la máquina, mientras que los primeros tipos de datos más específicos me hacen sentir mejor facilitando las interacciones de máquina a máquina. Considero que la mejora de los formatos de los productos básicos puede dificultar la negociación de los contenidos. “application / xml + yourresource” es mucho más específico como tipo de medio que “application / xhtml + xml”, ya que este último se puede aplicar a muchas cargas que pueden o no ser algo que a un cliente de máquina realmente le interese, ni puede determinar sin introspección.

Sin embargo, XHTML funciona muy bien (obviamente) en la web humana donde los navegadores web y el renderizado son muy importantes.

Su aplicación lo guiará en ese tipo de decisiones.

Parte del proceso de diseño de un sistema REST es descubrir los recursos de primera clase en su sistema, junto con los recursos de apoyo derivados necesarios para respaldar las operaciones en los recursos primarios. Una vez que se descubren los recursos, entonces la representación de esos recursos, así como los diagtwigs de estado que muestran el flujo de recursos a través del hipertexto dentro de las representaciones, porque el próximo desafío.

Recuerde que cada representación de un recurso, en un sistema de hipertexto, combina la representación del recurso real junto con las transiciones de estado disponibles para el recurso. Considere cada recurso como un nodo en un gráfico, con los enlaces como las líneas que salen de ese nodo a otros estados. Estos enlaces informan a los clientes no solo lo que se puede hacer, sino también lo que se requiere para que se realicen (ya que un buen enlace combina el URI y el tipo de medio requerido).

Por ejemplo, puede tener:

   

Su documentación hablará sobre el campo rel llamado “users” y el tipo de medio de “application / xml + youruser”.

Estos enlaces pueden parecer redundantes, todos están hablando con el mismo URI, más o menos. Pero no lo son.

Esto se debe a que para la relación “usuarios”, ese enlace se refiere a la colección de usuarios, y puede usar la interfaz uniforme para trabajar con la colección (GET para recuperarlos todos, BORRAR para eliminarlos todos, etc.)

Si publica POST en esta URL, deberá pasar un documento “application / xml + usercollection”, que probablemente solo contenga una única instancia de usuario dentro del documento para que pueda agregarlo o no, tal vez, para agregar varias a una vez. Tal vez su documentación sugiera que simplemente puede pasar un tipo de usuario único, en lugar de la colección.

Puede ver lo que la aplicación requiere para realizar una búsqueda, tal como se define en el enlace de “búsqueda” y su tipo de medios. La documentación para el tipo de medio de búsqueda le dirá cómo se comporta y qué esperar como resultado.

El punto de partida aquí, sin embargo, es que los URI en sí mismos son básicamente sin importancia. La aplicación tiene el control de los URI, no de los clientes. Más allá de unos pocos “puntos de entrada”, sus clientes deben confiar en los URI proporcionados por la aplicación para su trabajo.

El cliente necesita saber cómo manipular e interpretar los tipos de medios, pero no necesita preocuparse de dónde va.

Estos dos enlaces son semánticamente idénticos en los ojos de los clientes:

   

Por lo tanto, concéntrese en sus recursos. Concéntrese en las transiciones de estado en la aplicación y cómo se logra mejor.

re 1 : Esto se ve bien hasta ahora. Recuerde devolver el URI del usuario recién creado en un encabezado “Ubicación:” como parte de la respuesta a POST, junto con un código de estado “201 Creado”.

re 2 : la activación a través de GET es una mala idea, e incluir el verbo en el URI es un olor de diseño. Es posible que desee considerar devolver un formulario en un GET. En una aplicación web, esto sería un formulario HTML con un botón de enviar; en el caso de uso de API, es posible que desee devolver una representación que contenga un URI para PUT a para activar la cuenta. Por supuesto, también puede incluir este URI en la respuesta en POST a / users. El uso de PUT garantizará que su solicitud sea idempotente, es decir, que pueda enviarse nuevamente de manera segura si el cliente no está seguro de que tenga éxito. En general, piense en qué recursos puede convertir sus verbos (tipo de “sustantivización de verbos”). Pregúntese con qué método está más estrechamente alineada su acción específica. Por ejemplo, change_password -> PUT; desactivar -> probablemente DELETE; add_credit -> posiblemente POST o PUT. Señale al cliente los URI apropiados incluyéndolos en sus representaciones.

re 3. No invente nuevos códigos de estado, a menos que crea que son tan generics que merecen ser estandarizados globalmente. Intente utilizar el código de estado más apropiado disponible (lea sobre todos ellos en RFC 2616). Incluye información adicional en el cuerpo de respuesta. Si realmente, realmente estás seguro de que quieres inventar un nuevo código de estado, piénsalo de nuevo; si aún así lo cree, asegúrese de elegir al menos la categoría correcta (1xx -> OK, 2xx -> informativo, 3xx -> redirección; 4xx-> error de cliente, 5xx -> error de servidor). ¿Mencioné que inventar nuevos códigos de estado es una mala idea?

re 4. Si de alguna manera es posible, use el marco de autenticación integrado en HTTP. Consulte la forma en que Google realiza la autenticación en GData. En general, no coloque claves de API en sus URI. Intente evitar las sesiones para mejorar la escalabilidad y admitir el almacenamiento en caché: si la respuesta a una solicitud difiere debido a algo que sucedió anteriormente, por lo general se ha vinculado a una instancia específica del proceso del servidor. Es mucho mejor convertir el estado de la sesión en un estado de cliente (por ejemplo, hacer que forme parte de solicitudes posteriores) o hacerlo explícito convirtiéndolo en un estado de recurso (servidor), es decir, darle su propio URI.

1. Tienes la idea correcta sobre cómo diseñar tus recursos, en mi humilde opinión. No cambiaría nada.

2. En lugar de tratar de extender HTTP con más verbos, considere a qué se pueden reducir los verbos propuestos en términos de los métodos y recursos básicos de HTTP. Por ejemplo, en lugar de un verbo activate_login , puede configurar recursos como: /api/users/1/login/active que es un booleano simple. Para activar un inicio de sesión, simplemente PUT allí un documento que diga ‘verdadero’ o 1 o lo que sea. Para desactivar, PUT un documento que esté vacío o diga 0 o falso.

Del mismo modo, para cambiar o establecer contraseñas, simplemente haga PUT a /api/users/1/password .

Siempre que necesite agregar algo (como un crédito) piense en términos de POST s. Por ejemplo, podría hacer una POST a un recurso como /api/users/1/credits con un cuerpo que contenga la cantidad de créditos para agregar. Se podría usar un PUT en el mismo recurso para sobrescribir el valor en lugar de agregarlo. Un POST con un número negativo en el cuerpo restaría, y así sucesivamente.

3. Recomiendo encarecidamente no extender los códigos básicos de estado HTTP. Si no puede encontrar uno que coincida exactamente con su situación, elija el más cercano y ponga los detalles del error en el cuerpo de la respuesta. Además, recuerde que los encabezados HTTP son extensibles; su aplicación puede definir todos los encabezados personalizados que desee. Una aplicación en la que trabajé, por ejemplo, podría devolver un 404 Not Found en múltiples circunstancias. En lugar de hacer que el cliente analice el cuerpo de respuesta por el motivo, simplemente agregamos un nuevo encabezado, X-Status-Extended , que contenía nuestras extensiones de código de estado propietarias. Por lo tanto, es posible que vea una respuesta como:

 HTTP/1.1 404 Not Found X-Status-Extended: 404.3 More Specific Error Here 

De esta forma, un cliente HTTP como un navegador web sabrá qué hacer con el código 404 normal, y un cliente HTTP más sofisticado puede elegir mirar el encabezado X-Status-Extended para obtener información más específica.

4. Para la autenticación, recomiendo usar la autenticación HTTP si puede. Pero en mi humilde opinión, no hay nada de malo con el uso de la autenticación basada en cookies si es más fácil para usted.

REST Básicos

REST tiene una restricción de interfaz uniforme, que establece que el cliente REST debe basarse en estándares en lugar de detalles específicos de la aplicación del servicio REST real, por lo que el cliente REST no se romperá por cambios menores, y probablemente será reutilizable.

Entonces, hay un contrato entre el cliente REST y el servicio REST. Si usa HTTP como protocolo subyacente, los siguientes estándares son parte del contrato:

  • HTTP 1.1
    • definiciones de métodos
    • definiciones del código de estado
    • encabezados de control de caché
    • aceptar y encabezados de tipo de contenido
    • encabezados de autenticación
  • IRI (utf8 URI )
  • cuerpo (elija uno)
    • tipo de MIME específico de la aplicación registrada, por ejemplo, laberinto + xml
    • tipo MIME específico del vendedor, p. ej. vnd.github + json
    • tipo MIME genérico con
      • vocabulario RDF específico de la aplicación, por ej. ld + json & hydra , schema.org
      • perfil específico de la aplicación, por ejemplo, hal + json y param del enlace de perfil (supongo)
  • hipervínculos
    • qué debería contenerlos (elegir uno)
      • enviando encabezados de enlace
      • enviar una respuesta hipermedia, por ej. html, atom + xml, hal + json, ld + json & hydra, etc …
    • semántica
      • usar relaciones de enlace IANA y probablemente relaciones de enlace personalizado
      • utilizar un vocabulario RDF específico de la aplicación

REST tiene una restricción sin estado, que declara que la comunicación entre el servicio REST y el cliente debe ser sin estado. Esto significa que el servicio REST no puede mantener los estados del cliente, por lo que no puede tener un almacenamiento de sesión del lado del servidor. Tienes que autenticar cada solicitud individual. Entonces, por ejemplo, HTTP basic auth (parte del estándar HTTP) está bien, porque envía el nombre de usuario y la contraseña con cada solicitud.

Para responderte preguntas

  1. Si puede ser.

    Solo para mencionar, los clientes no se preocupan por la estructura IRI, se preocupan por la semántica, porque siguen enlaces que tienen relaciones de enlace o atributos de datos vinculados (RDF).

    Lo único importante sobre los IRI es que un solo IRI debe identificar solo un recurso. Se permite que un solo recurso, como un usuario, tenga muchos IRI diferentes.

    Es bastante simple por qué utilizamos IRI agradables como /users/123/password ; es mucho más fácil escribir la lógica de enrutamiento en el servidor cuando comprendes el IRI simplemente leyéndolo.

  2. Tiene más verbos, como PUT, PATCH, OPTIONS y aún más, pero no necesita más de ellos … En lugar de agregar verbos nuevos, debe aprender a agregar nuevos recursos.

    activate_login -> PUT /login/active true deactivate_login -> PUT /login/active false change_password -> PUT /user/xy/password "newpass" add_credit -> POST /credit/raise {details: {}}

    (El inicio de sesión no tiene sentido desde la perspectiva de REST, debido a la restricción sin estado).

  3. A sus usuarios no les importa por qué existe el problema. Quieren saber solo si hay éxito o error, y probablemente un mensaje de error que puedan entender, por ejemplo: “Lo sentimos, pero no pudimos guardar su publicación”, etc.

    Los encabezados de estado HTTP son sus encabezados estándar. Todo lo demás debería estar en el cuerpo, creo. Un solo encabezado no es suficiente para describir, por ejemplo, mensajes de error multilingües detallados.

  4. La restricción sin estado (junto con la caché y las restricciones del sistema en capas) garantiza que el servicio se adapte bien. Seguramente no desea mantener millones de sesiones en el servidor, cuando puede hacer lo mismo con los clientes …

    El cliente externo obtiene un token de acceso si el usuario le concede acceso usando el cliente principal. Después de eso, el cliente externo envía el token de acceso con cada solicitud. Hay soluciones más complicadas, por ejemplo, puede firmar todas las solicitudes, etc. Para más detalles, consulte el manual de OAuth.

Literatura relacionada

  • Estilos arquitectónicos y el diseño de architectures de software basadas en red
    Disertación de Roy Thomas Fielding (autor de REST)
    2000, Universidad de California, Irvine
  • Web API de tercera generación: cerrar la brecha entre el REST y los datos vinculados
    Disertación de Markus Lanthaler (coautor de JSON-LD y autor de Hydra)
    2014, Universidad de Tecnología de Graz, Austria

Para los ejemplos que indicó, usaría lo siguiente:

activate_login

POST /users/1/activation

deactivate_login

DELETE /users/1/activation

Cambia la contraseña

PUT /passwords (esto supone que el usuario está autenticado)

añadir crédito

POST /credits (esto supone que el usuario está autenticado)

Para los errores, debe devolver el error en el cuerpo en el formato en el que recibió la solicitud, de modo que si recibe:

DELETE /users/1.xml

Enviarías la respuesta en XML, lo mismo sería cierto para JSON, etc.

Para la autenticación, debe usar la autenticación http.

  1. Use la publicación cuando no sepa cómo se vería el nuevo URI de recursos (usted crea un nuevo usuario, la aplicación asignaría al nuevo usuario su identificación), PONGA para actualizar o crear recursos que sepa cómo se representarán (ejemplo : PUT /myfiles/thisismynewfile.txt)
  2. devolver la descripción del error en el cuerpo del mensaje
  3. Puede usar la autenticación HTTP (si es suficiente) Los servicios web deben ser stateles

Sugeriría (como primer paso) que PUT solo debería usarse para actualizar entidades existentes. POST debe usarse para crear nuevos. es decir

 /api/users when called with PUT, creates user record 

no se siente bien conmigo Sin embargo, el rest de la primera sección (ver el uso del verbo) parece lógico.

Verboso, pero copiado de la especificación del método HTTP 1.1 en http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html

9.3 GET

El método GET significa recuperar cualquier información (en forma de una entidad) identificada por Request-URI. Si el URI de solicitud se refiere a un proceso de producción de datos, son los datos producidos los que se devolverán como la entidad en la respuesta y no el texto fuente del proceso, a menos que ese texto sea el resultado del proceso.

La semántica del método GET cambia a un “GET condicional” si el mensaje de solicitud incluye un campo de encabezado If-Modified-Since, If-Unmodified-Since, If-Match, If-None-Match o If-Range. Un método GET condicional solicita que la entidad se transfiera solo en las circunstancias descritas por los campos de encabezado condicional (es). El método condicional GET tiene como objective reducir el uso innecesario de la red al permitir que las entidades en caché se actualicen sin requerir múltiples solicitudes o transferir datos que ya posee el cliente.

La semántica del método GET cambia a un “GET parcial” si el mensaje de solicitud incluye un campo de encabezado Rango. Un GET parcial solicita que solo se transfiera parte de la entidad, como se describe en la sección 14.35. El método parcial GET tiene la intención de reducir el uso innecesario de la red al permitir que entidades parcialmente recuperadas se completen sin transferir datos que ya posee el cliente.

La respuesta a una solicitud GET es almacenable en caché solo si cumple con los requisitos para el almacenamiento en caché HTTP descrito en la sección 13.

Consulte la sección 15.1.3 para consideraciones de seguridad cuando se usa para formularios.

9.5 POST

El método POST se utiliza para solicitar que el servidor de origen acepte la entidad incluida en la solicitud como un nuevo subordinado del recurso identificado por el URI de solicitud en la línea de solicitud. POST está diseñado para permitir un método uniforme para cubrir las siguientes funciones:

  - Annotation of existing resources; - Posting a message to a bulletin board, newsgroup, mailing list, or similar group of articles; - Providing a block of data, such as the result of submitting a form, to a data-handling process; - Extending a database through an append operation. 

La función real realizada por el método POST está determinada por el servidor y generalmente depende del Request-URI. La entidad publicada está subordinada a ese URI de la misma manera que un archivo está subordinado a un directorio que lo contiene, un artículo de noticias está subordinado a un grupo de noticias al que se publica, o un registro está subordinado a una base de datos.

La acción realizada por el método POST podría no dar como resultado un recurso que pueda identificarse mediante 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 ha creado 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 haga referencia al nuevo recurso, y un encabezado de Ubicación (ver sección 14.30).

Las respuestas a este método no se pueden almacenar en caché, a menos que la respuesta incluya los campos de encabezado Cache-Control o Expires apropiados. Sin embargo, la respuesta 303 (Ver Otro) se puede usar para dirigir al agente de usuario a recuperar un recurso almacenable en caché.

Las solicitudes POST DEBEN obedecer los requisitos de transmisión de mensajes establecidos en la sección 8.2.

Ver la sección 15.1.3 para consideraciones de seguridad.

9.6 PUT

El método PUT solicita que la entidad adjunta se almacene bajo el URI de solicitud proporcionado. Si el URI de solicitud se refiere a un recurso ya existente, la entidad adjuntada DEBERÍA considerarse como una versión modificada de la que reside en el servidor de origen. Si el URI de solicitud no apunta a un recurso existente, y ese URI puede definirse como un recurso nuevo por el agente de usuario solicitante, el servidor de origen puede crear el recurso con ese URI. Si se crea un nuevo recurso, el servidor de origen DEBE informar al agente de usuario a través de la respuesta 201 (Creado). Si se modifica un recurso existente, se DEBERÁN enviar los códigos de respuesta 200 (OK) o 204 (Sin contenido) para indicar que se completó con éxito la solicitud. Si el recurso no se pudo crear o modificar con el URI de solicitud, se DEBERÍA dar una respuesta de error apropiada que refleje la naturaleza del problema. El destinatario de la entidad NO DEBE ignorar ningún encabezado de contenido * (por ejemplo, rango de contenido) que no comprenda o implemente, y DEBE devolver una respuesta 501 (no implementada) en tales casos.

Si la solicitud pasa a través de un caché y el URI de solicitud identifica una o más entidades actualmente en caché, esas entradas DEBERÍAN tratarse como obsoletas. Las respuestas a este método no son guardables.

La diferencia fundamental entre las solicitudes POST y PUT se refleja en el significado diferente de Request-URI. El URI en una solicitud POST identifica el recurso que manejará la entidad adjunta. Ese recurso puede ser un proceso de aceptación de datos, una puerta de enlace a algún otro protocolo o una entidad separada que acepta anotaciones. In contrast, the URI in a PUT request identifies the entity enclosed with the request — the user agent knows what URI is intended and the server MUST NOT attempt to apply the request to some other resource. If the server desires that the request be applied to a different URI,

it MUST send a 301 (Moved Permanently) response; the user agent MAY then make its own decision regarding whether or not to redirect the request.

A single resource MAY be identified by many different URIs. For example, an article might have a URI for identifying “the current version” which is separate from the URI identifying each particular version. In this case, a PUT request on a general URI might result in several other URIs being defined by the origin server.

HTTP/1.1 does not define how a PUT method affects the state of an origin server.

PUT requests MUST obey the message transmission requirements set out in section 8.2.

Unless otherwise specified for a particular entity-header, the entity-headers in the PUT request SHOULD be applied to the resource created or modified by the PUT.

9.7 DELETE

El método DELETE solicita que el servidor de origen elimine el recurso identificado por Request-URI. Este método PUEDE ser anulado por intervención humana (u otros medios) en el servidor de origen. No se puede garantizar al cliente que la operación se haya llevado a cabo, incluso si el código de estado devuelto por el servidor de origen indica que la acción se ha completado con éxito. Sin embargo, el servidor NO DEBE indicar el éxito a menos que, en el momento en que se dé la respuesta, intente eliminar el recurso o moverlo a una ubicación inaccesible.

Una respuesta exitosa DEBERÍA ser 200 (OK) si la respuesta incluye una entidad que describe el estado, 202 (Aceptado) si la acción aún no se ha promulgado, o 204 (Sin contenido) si la acción se ha promulgado pero la respuesta no incluye una entidad.

Si la solicitud pasa a través de un caché y el URI de solicitud identifica una o más entidades actualmente en caché, esas entradas DEBERÍAN tratarse como obsoletas. Responses to this method are not cacheable.

About REST return codes: it is wrong to mix HTTP protocol codes and REST results.

However, I saw many implementations mixing them, and many developers may not agree with me.

HTTP return codes are related to the HTTP Request itself. A REST call is done using a Hypertext Transfer Protocol request and it works at a lower level than invoked REST method itself. REST is a concept/approach, and its output is a business/logical result, while HTTP result code is a transport one.

For example, returning “404 Not found” when you call /users/ is confuse, because it may mean:

  • URI is wrong (HTTP)
  • No users are found (REST)

“403 Forbidden/Access Denied” may mean:

  • Special permission needed. Browsers can handle it by asking the user/password. (HTTP)
  • Wrong access permissions configured on the server. (HTTP)
  • You need to be authenticated (REST)

And the list may continue with ‘500 Server error” (an Apache/Nginx HTTP thrown error or a business constraint error in REST) or other HTTP errors etc…

From the code, it’s hard to understand what was the failure reason, a HTTP (transport) failure or a REST (logical) failure.

If the HTTP request physically was performed successfully it should always return 200 code, regardless is the record(s) found or not. Because URI resource is found and was handled by the http server. Yes, it may return an empty set. Is it possible to receive an empty web-page with 200 as http result, right?

Instead of this you may return 200 HTTP code and simply a JSON with an empty array/object, or to use a bool result/success flag to inform about the performed operation status.

Also, some internet providers may intercept your requests and return you a 404 http code. This does not means that your data are not found, but it’s something wrong at transport level.

From Wiki :

In July 2004, the UK telecom provider BT Group deployed the Cleanfeed content blocking system, which returns a 404 error to any request for content identified as potentially illegal by the Internet Watch Foundation. Other ISPs return a HTTP 403 “forbidden” error in the same circumstances. The practice of employing fake 404 errors as a means to conceal censorship has also been reported in Thailand and Tunisia. In Tunisia, where censorship was severe before the 2011 revolution, people became aware of the nature of the fake 404 errors and created an imaginary character named “Ammar 404” who represents “the invisible censor”.