web services - tutorial - Entendiendo REST: Verbos, códigos de error y autenticación
tutorial api rest (10)
Estoy buscando una manera de envolver las API alrededor de las funciones predeterminadas en mis aplicaciones web, bases de datos y CMS basados en PHP.
He mirado a mi alrededor y he encontrado varios marcos "esqueleto". Además de las respuestas en mi pregunta, hay Tonic , un marco REST que me gusta porque es muy liviano.
Me gusta REST por su simplicidad, y me gustaría crear una arquitectura de API basada en ella. Estoy tratando de entender los principios básicos y aún no lo he entendido completamente. Por lo tanto, una serie de preguntas.
1. ¿Lo estoy entendiendo bien?
Digamos que tengo un recurso "usuarios". Podría configurar una serie de URI como tal:
/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 arquitectura RESTful hasta ahora?
2. necesito mas verbos
Crear, actualizar y eliminar puede ser suficiente en teoría, pero en la práctica necesitaré muchos más verbos. Me doy cuenta de que estas son cosas que podrían incluirse 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 de los que vienen a la mente en el ejemplo del usuario son:
activate_login
deactivate_login
change_password
add_credit
¿Cómo expresaría acciones como las de una arquitectura de URL RESTful?
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 nuevo.
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 radica en el uso de métodos HTTP estándar. En un 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 (¿correcto?). Hasta ahora tan bueno. Pero, ¿cuál sería la forma de transmitir un código de error patentado que sea más detallado al describir qué salió mal (por ejemplo, "no se pudo conectar a la base de datos" o "inicio de sesión de base de datos incorrecto")? 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?
- ¿Cómo sería una autenticación basada en clave API siguiendo los principios REST?
- ¿Hay puntos fuertes en contra del uso de sesiones al autenticar un cliente REST, aparte de que es una violación flagrante del principio REST? :) (sólo la mitad bromeo aquí, la autenticación basada en sesión funcionaría bien con mi infraestructura existente.)
Fundamentos de descanso
REST tiene una restricción de interfaz uniforme, que establece que el cliente REST debe confiar en los estándares en lugar de los detalles específicos de la aplicación del servicio REST real, por lo que el cliente REST no se romperá con cambios menores, y probablemente será reutilizable.
Así que hay un contrato entre el cliente REST y el servicio REST. Si utiliza HTTP como protocolo subyacente, los siguientes estándares forman parte del contrato:
- HTTP 1.1
- definiciones de métodos
- definiciones de códigos de estado
- cabeceras de control de caché
- aceptar y encabezados de tipo de contenido
- encabezados de autenticación
- IRI (utf8 URI )
- cuerpo (elige uno)
- Tipo MIME específico de la aplicación registrada, por ejemplo, maze+xml
- tipo MIME específico del proveedor, por ejemplo, vnd.github+json
- tipo MIME genérico con
- aplicación específica de vocabulario RDF, por ejemplo, ld+json & hydra , schema.org
- perfil específico de la aplicación, por ejemplo, hal+json y perfil enlace de perfil (supongo)
- hipervínculos
- lo que debería contenerlos (elige uno)
- enviando encabezados de enlace
- enviando una respuesta hipermedia, por ejemplo, html, atom + xml, hal + json, ld + json y hydra, etc.
- semántica
- usar relaciones de enlace de la IANA y probablemente relaciones de enlace personalizadas
- utilizar una aplicación específica de vocabulario RDF
- lo que debería contenerlos (elige uno)
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, la autenticación HTTP básica (parte del estándar HTTP) está bien, ya que envía el nombre de usuario y la contraseña con cada solicitud.
Para responder a tus preguntas
Si puede ser.
Solo por mencionar, a los clientes no les importa la estructura IRI, les importa la semántica, porque siguen enlaces que tienen relaciones de enlace o atributos de datos vinculados (RDF).
Lo único importante acerca de los IRI es que un solo IRI debe identificar un solo recurso. Se permite que un solo recurso, como un usuario, tenga muchos IRI diferentes.
Es bastante simple por qué usamos buenos IRI como
/users/123/password
; es mucho más fácil escribir la lógica de enrutamiento en el servidor cuando comprende el IRI simplemente leyéndolo.Tiene más verbos, como PUT, PATCH, OPTIONS, e incluso más, pero no necesita más de ellos ... En lugar de agregar nuevos verbos, 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 REST, debido a la restricción sin estado).
A tus usuarios no les importa por qué existe el problema. Solo desean saber si hay éxito o error, y probablemente un mensaje de error que puedan entender, por ejemplo: "Lo sentimos, pero no pudimos guardar tu 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.
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 querrá mantener millones de sesiones en el servidor, cuando puede hacer lo mismo en los clientes ...
El cliente de terceros obtiene un token de acceso si el usuario le otorga acceso mediante el cliente principal. Después de eso, el cliente de terceros envía el token de acceso con cada solicitud. Hay soluciones más complicadas, por ejemplo, puede firmar cada solicitud, etc. Para más detalles, consulte el manual de OAuth.
Literatura relacionada
- Estilos arquitectónicos y el diseño de arquitecturas de software basadas en red
Disertación de Roy Thomas Fielding (autor de REST)
2000, Universidad de California, Irvine - API web de tercera generación: uniendo la brecha entre 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
- Use la publicación cuando no sepa cómo se vería el nuevo URI del recurso (usted crea un nuevo usuario, la aplicación le asignará al nuevo usuario su ID), PUT para actualizar o crear recursos que sepa cómo se representarán (ejemplo : PUT /myfiles/thisismynewfile.txt)
- devuelve la descripción del error en el cuerpo del mensaje
- Puede usar la autenticación HTTP (si es suficiente) los servicios web deben ser stateles
En pocas palabras, estás haciendo esto completamente hacia atrás.
No debes acercarte a esto desde qué URL debes usar. Las URL vendrán efectivamente "gratis" 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 debe dedicar casi todo su esfuerzo descriptivo a definir los tipos de medios utilizados para representar los recursos y dirigir el estado de la aplicación, o definir nombres de relaciones extendidas y / o marcado de hipertexto para los tipos de medios estándar existentes. Cualquier esfuerzo dedicado a describir qué métodos usar en qué URI de interés se deben definir completamente dentro del alcance de las reglas de procesamiento para un tipo de medio (y, en la mayoría de los casos, ya está definido por los tipos de medios existentes). [El error aquí implica que la información fuera de banda está impulsando la interacción en lugar del hipertexto.]
La gente siempre comienza con los URI y piensa que esta es la solución, y luego tienden a pasar por alto un concepto clave en la arquitectura REST, en particular, como se mencionó anteriormente, "la falla 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 URIs y algunos GETs y PUTs y POSTs y piensan que REST es fácil. REST no es fácil. RPC a través de HTTP es fácil, mover blobs de datos de un lado a otro a través de cargas útiles HTTP es fácil. REST, sin embargo, va más allá de eso. REST es un protocolo agnóstico. HTTP es simplemente muy popular y apto para sistemas REST.
REST vive en los tipos de medios, sus definiciones y cómo la aplicación impulsa las acciones disponibles para esos recursos a través de hipertexto (enlaces, efectivamente).
Hay diferentes vistas sobre 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 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 su representación, tal vez a través de microformatos y otros mecanismos.
Creo que ambos enfoques tienen su lugar. El XHTML funciona muy bien en escenarios que se superponen tanto a la web impulsada por humanos como a las máquinas, mientras que los tipos de datos más antiguos y específicos me parece más fácil facilitar las interacciones máquina a máquina. Me parece que la elevación de los formatos de los productos básicos puede hacer que la negociación del contenido sea potencialmente difícil. "application / xml + yourresource" es mucho más específico como tipo de medio que "application / xhtml + xml", ya que este último puede aplicarse a muchas cargas útiles que pueden o no ser algo en lo que un cliente de máquina está realmente interesado, ni puede Determinar sin introspección.
Sin embargo, XHTML funciona muy bien (obviamente) en la web humana donde los navegadores web y la representación son muy importantes.
Tu aplicación te 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 el derivado, los recursos de soporte 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 diagramas de estado que muestran el flujo de recursos a través del hipertexto dentro de las representaciones, es el próximo desafío.
Recuerde que cada representación de un recurso, en un sistema de hipertexto, combina la representación real del recurso 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 hagan (como un buen enlace combina la URI y el tipo de medio requerido).
Por ejemplo, puede tener:
<link href="http://example.com/users" rel="users" type="application/xml+usercollection"/>
<link href="http://example.com/users?search" rel="search" type="application/xml+usersearchcriteria"/>
Su documentación hablará sobre el campo rel llamado "usuarios" y el tipo de medio de "aplicación / xml + suusuario".
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 de "usuarios", ese enlace habla de 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 envía POST a esta URL, deberá pasar un documento "application / xml + usercollection", que probablemente solo contenga una instancia de usuario única dentro del documento para que pueda agregar al usuario, o tal vez, para agregar varios en una vez. Tal vez su documentación sugiera que simplemente puede pasar un solo tipo de usuario, en lugar de la colección.
Puede ver lo que requiere la aplicación para realizar una búsqueda, como se define en el enlace "buscar" y su tipo de medio. La documentación para el tipo de medio de búsqueda le dirá cómo se comporta esto y qué esperar como resultado.
Sin embargo, la conclusión aquí es que las URI en sí mismas son básicamente poco importantes. La aplicación está en 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 tiene por qué preocuparse por dónde va.
Estos dos enlaces son semánticamente idénticos a los ojos de los clientes:
<link href="http://example.com/users?search" rel="search" type="application/xml+usersearchcriteria"/>
<link href="http://example.com/AW163FH87SGV" rel="search" type="application/xml+usersearchcriteria"/>
Entonces, concéntrate en tus recursos. Concéntrese en sus transiciones de estado en la aplicación y la mejor manera de lograrlo.
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?
Has entendido bien. Esa es una representación correcta de una arquitectura RESTful. Puede encontrar la siguiente matriz de Wikipedia muy útil para definir sus nombres y verbos:
Cuando se trata de un URI de colección como: http://example.com/resources/
GET : Enumere los miembros de la colección, junto con sus URIs de miembros para una mayor navegación. Por ejemplo, liste todos los autos en venta.
PUT : Significado definido como "reemplazar toda la colección con otra colección".
POST : cree una nueva entrada en la colección donde la ID asigna automáticamente la ID. El ID creado generalmente se incluye como parte de los datos devueltos por esta operación.
ELIMINAR : el significado se define como "eliminar toda la colección".
Al tratar con un URI de miembro como: http://example.com/resources/7HOU57Y
GET : recupera una representación del miembro direccionado de la colección expresado en un tipo MIME apropiado.
PUT : Actualice el miembro direccionado de la colección o créelo con la ID especificada.
POST : trata al miembro tratado como una colección por derecho propio y crea un nuevo subordinado de él.
ELIMINAR : Eliminar el miembro direccionado de la colección.
Punto 2: necesito más verbos
En general, cuando cree que necesita más verbos, en realidad puede significar que sus recursos deben ser re-identificados. Recuerde que en REST siempre está actuando en un recurso o en una colección de recursos. Lo que elija como recurso es bastante importante para su definición de API.
Activar / Desactivar inicio de sesión : si está creando una nueva sesión, es posible que desee considerar "la sesión" como el recurso. Para crear una nueva sesión, utilice POST para http://example.com/sessions/
con las credenciales en el cuerpo. Para caducar, use PUT o DELETE (tal vez dependiendo de si desea mantener un historial de sesiones) para http://example.com/sessions/SESSION_ID
.
Cambiar contraseña: esta vez el recurso es "el usuario". Necesitaría un PUT para http://example.com/users/USER_ID
con las contraseñas antiguas y nuevas en el cuerpo. Usted está actuando en el recurso "el 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 REST muy básico: 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 un nuevo 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 poder guardarse en la memoria 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 a la base de datos : en general, debe usar un error 500 para estos tipos de errores. Este es un error del lado del servidor. El cliente no hizo nada malo. Los errores 500 normalmente se consideran "reintentables". es decir, el cliente puede volver a intentar la misma solicitud exacta y esperar que tenga éxito una vez que se resuelvan los problemas del servidor. Especifique los detalles en el cuerpo, para que el cliente pueda proporcionarnos algún contexto a los seres 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 hay necesidad de 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 de "Recurso no encontrado" (HTTP 404) o "Solicitud con formato incorrecto" (HTTP 400) caerí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, puede pensar en crear una sesión. Se le devolverá un nuevo "ID de sesión", junto con el código de estado HTTP apropiado (200: acceso concedido o 403: acceso denegado).
Luego le preguntará a su servidor RESTful: "¿Me PUEDE OBTENER el recurso para esta ID de sesión?".
No hay un modo autenticado. REST no tiene estado: crea una sesión, le pide al servidor que le brinde recursos usando este ID de sesión como un parámetro y al cerrar la sesión abandona o expira la sesión.
Para los ejemplos que dijiste, usaría lo siguiente:
activar_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, devolvería el error en el cuerpo en el formato en el que recibió la solicitud, por lo que si recibe:
DELETE /users/1.xml
Enviaría la respuesta de nuevo en XML, lo mismo sería cierto para JSON, etc.
Para la autenticación debe utilizar la autenticación http.
Verbose, pero copiado de la especificación del método HTTP 1.1 en http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
9.3 OBTENER
El método GET significa recuperar cualquier información (en forma de una entidad) identificada por el URI de solicitud. Si la Solicitud-URI 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 de origen del proceso, a menos que ese texto sea la salida 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 del encabezado condicional. El método GET condicional está destinado a reducir el uso innecesario de la red al permitir que las entidades almacenadas 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 de rango. Un GET parcial solicita que solo una parte de la entidad sea transferida, como se describe en la sección 14.35. El método GET parcial está destinado a reducir el uso innecesario de la red al permitir que se completen las entidades recuperadas parcialmente sin transferir los datos que ya posee el cliente.
La respuesta a una solicitud GET se puede almacenar en caché si y solo si cumple con los requisitos para el almacenamiento en caché HTTP descritos en la sección 13.
Vea 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 de la Solicitud-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 en el que está publicado o un registro está subordinado a una base de datos.
La acción realizada por el método POST puede no resultar en un recurso que puede ser identificado por un URI. En este caso, 200 (OK) o 204 (Sin contenido) es el estado de respuesta adecuado, dependiendo de si la respuesta incluye o no una entidad que describe 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 se refiera al nuevo recurso, y un encabezado de ubicación (consulte la sección 14.30).
Las respuestas a este método no se pueden almacenar en la memoria caché, a menos que la respuesta incluya los campos de encabezado Cache-Control o Expires apropiados. Sin embargo, la respuesta 303 (ver Otro) puede usarse 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.
Vea la sección 15.1.3 para consideraciones de seguridad.
9.6 PONER
El método PUT solicita que la entidad adjunta se almacene bajo el URI de solicitud suministrado. Si la Solicitud-URI se refiere a un recurso ya existente, la entidad adjunta 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 agente de usuario solicitante puede definir el URI como un nuevo recurso, 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, DEBEN enviarse los códigos de respuesta 200 (OK) o 204 (Sin contenido) para indicar la finalización exitosa de la solicitud. Si el recurso no pudo crearse o modificarse con el URI de solicitud, se DEBE dar una respuesta de error adecuada que refleje la naturaleza del problema. El destinatario de la entidad NO DEBE ignorar los encabezados de Contenido * (por ejemplo, Rango de Contenido) que no comprende o implementa, y DEBE devolver una respuesta 501 (No Implementado) 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 DEBEN ser tratadas como obsoletas. Las respuestas a este método no son cacheables.
La diferencia fundamental entre las solicitudes POST y PUT se refleja en el significado diferente de la solicitud-URI. El URI en una solicitud POST identifica el recurso que manejará la entidad adjunta. Ese recurso podría ser un proceso de aceptación de datos, una puerta de enlace a algún otro protocolo o una entidad separada que acepte anotaciones. En contraste, el URI en una solicitud PUT identifica la entidad incluida en la solicitud: el agente de usuario sabe a qué se destina el URI y el servidor NO DEBE intentar aplicar la solicitud a algún otro recurso. Si el servidor desea que la solicitud se aplique a un URI diferente,
DEBE enviar una respuesta 301 (Movida permanentemente); El agente de usuario PUEDE entonces tomar su propia decisión sobre si redirigir o no la solicitud.
Un solo recurso PUEDE ser identificado por muchos URI diferentes.Por ejemplo, un artículo puede tener un URI para identificar "la versión actual" que es independiente del URI que identifica cada versión en particular. En este caso, una solicitud PUT en un URI general puede dar como resultado que el servidor de origen defina otros URI.
HTTP / 1.1 no define cómo un método PUT afecta el estado de un servidor de origen.
Las solicitudes PUT DEBEN obedecer los requisitos de transmisión de mensajes establecidos en la sección 8.2.
A menos que se especifique lo contrario para un encabezado de entidad particular, los encabezados de entidad en la solicitud PUT DEBERÍAN aplicarse al recurso creado o modificado por el PUT.
9.7 BORRAR
El método DELETE solicita que el servidor de origen elimine el recurso identificado por el URI de solicitud. 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 de la respuesta, intente eliminar el recurso o moverlo a una ubicación inaccesible.
Una respuesta exitosa DEBE ser 200 (OK) si la respuesta incluye una entidad que describe el estado, 202 (Aceptada) 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 DEBEN ser tratadas como obsoletas. Las respuestas a este método no son cacheables.
Yo sugeriría (como primer paso) que el PUT
solo se use para actualizar las entidades existentes. POST
debe utilizarse para crear nuevos. es decir
/api/users when called with PUT, creates user record
no me parece bien Sin embargo, el resto de su primera sección (uso del verbo) parece lógico.
1. Tienes la idea correcta sobre cómo diseñar tus recursos, IMHO. Yo no cambiaría nada.
2. En lugar de intentar extender HTTP con más verbos, considere a qué se pueden reducir sus verbos propuestos en términos de los métodos y recursos básicos de HTTP. Por ejemplo, en lugar de un verbo enable_login, puede configurar recursos como: /api/users/1/login/active
que es un simple booleano. Para activar un inicio de sesión, solo PUT
un documento que diga ''verdadero'' o 1 o lo que sea. Para desactivar, PUT
un documento que esté vacío o que diga 0 o falso.
De manera similar, para cambiar o establecer contraseñas, solo haga PUT
s 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 un POST
a un recurso como /api/users/1/credits
con un cuerpo que contenga el número de créditos que agregar. Un PUT
en el mismo recurso podría usarse para sobrescribir el valor en lugar de agregarlo. Un POST
con un número negativo en el cuerpo se restaría, y así sucesivamente.
3. Recomiendo encarecidamente que no se extiendan los códigos de estado HTTP básicos. Si no puede encontrar uno que coincida exactamente con su situación, elija el más cercano y coloque 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 la respuesta por la razón, simplemente agregamos un nuevo encabezado, X-Status-Extended
, que contenía nuestras extensiones de código de estado de propiedad. Entonces podrías ver una respuesta como:
HTTP/1.1 404 Not Found
X-Status-Extended: 404.3 More Specific Error Here
De esa manera, un cliente HTTP como un navegador web todavía sabrá qué hacer con el código 404 normal, y un cliente HTTP más sofisticado puede elegir ver el encabezado X-Status-Extended
para obtener información más específica.
4. Para la autenticación, te recomiendo usar la autenticación HTTP si puedes. Pero en mi humilde opinión no hay nada de malo en usar la autenticación basada en cookies si es más fácil para usted.
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 la URI es un olor a 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 envío; en el caso de uso de API, es posible que desee devolver una representación que contenga un URI a PUT para activar la cuenta. Por supuesto, también puede incluir este URI en la respuesta en POST para / usuarios. El uso de PUT asegurará que su solicitud sea idempotente, es decir, puede enviarse de nuevo de manera segura si el cliente no está seguro de su éxito. En general, piense en qué recursos puede convertir sus verbos (tipo de "nounification de verbos"). Pregúntese con qué método está más estrechamente alineada su acción específica. Ej. Change_password -> PUT; desactivar -> probablemente BORRAR; add_credit -> posiblemente POST o PUT. Dirija al cliente a los URI apropiados incluyéndolos en sus representaciones.
re 3. No invente nuevos códigos de estado, a menos que crea que son tan genéricos que merecen ser estandarizados globalmente. Intente usar el código de estado más apropiado disponible (lea sobre todos ellos en RFC 2616). Incluir información adicional en el cuerpo de respuesta. Si realmente está seguro de que desea inventar un nuevo código de estado, piénselo nuevamente; si todavía cree que sí, asegúrese de al menos elegir la categoría correcta (1xx -> OK, 2xx -> informativo, 3xx -> redirección; 4xx-> error del cliente, 5xx -> error del 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. Compruebe la forma en que Google realiza la autenticación en GData. En general, no coloque claves API en sus URI. Intente evitar las sesiones para mejorar la escalabilidad y el almacenamiento en caché de soporte: si la respuesta a una solicitud difiere debido a algo que sucedió antes, generalmente se vincula con una instancia de proceso de servidor específica. Es mucho mejor convertir el estado de la sesión en cualquiera de los estados del cliente (por ejemplo, hacer que forme parte de las solicitudes posteriores) o hacerlo explícito convirtiéndolo en el estado del recurso (servidor), es decir, asignarle su propio URI.
Acerca de los códigos de retorno REST: es incorrecto mezclar códigos de protocolo HTTP y resultados REST.
Sin embargo, vi muchas implementaciones mezclándolas y muchos desarrolladores pueden no estar de acuerdo conmigo.
Los códigos de retorno HTTP están relacionados con la HTTP Request
sí. Una llamada REST se realiza mediante una solicitud de Protocolo de transferencia de hipertexto y funciona a un nivel más bajo que el propio método REST invocado. REST es un concepto / enfoque, y su salida es un resultado comercial / lógico , mientras que el código de resultado HTTP es uno de transporte .
Por ejemplo, devolver "404 No encontrado" cuando llama / users / es confuso, porque puede significar:
- URI está mal (HTTP)
- No se encontraron usuarios (REST)
"403 Prohibido / Acceso denegado" puede significar:
- Se necesita un permiso especial. Los navegadores pueden manejarlo preguntando al usuario / contraseña. (HTTP)
- Permisos de acceso erróneos configurados en el servidor. (HTTP)
- Necesitas estar autenticado (REST)
Y la lista puede continuar con ''500 Error de servidor "(un error de lanzamiento de Apache / Nginx HTTP o un error de restricción empresarial en REST) u otros errores de HTTP, etc.
Desde el código, es difícil entender cuál fue el motivo del error, un error HTTP (transporte) o un error REST (lógico).
Si la solicitud HTTP se realizó físicamente con éxito, siempre debería devolver el código 200, independientemente de si se encontraron los registros o no. Debido a que el recurso URI se encuentra y fue manejado por el servidor http. Sí, puede devolver un conjunto vacío. ¿Es posible recibir una página web vacía con 200 como resultado de http, verdad?
En lugar de esto, puede devolver 200 códigos HTTP y simplemente un JSON con una matriz / objeto vacío, o usar un indicador de resultado / éxito bool para informar sobre el estado de la operación realizada.
Además, algunos proveedores de Internet pueden interceptar sus solicitudes y devolverle un código HTTP 404. Esto no significa que no se encuentren sus datos, pero es algo incorrecto en el nivel de transporte.
De Wiki :
En julio de 2004, el proveedor de telecomunicaciones del Reino Unido BT Group implementó el sistema de bloqueo de contenido Cleanfeed, que devuelve un error 404 a cualquier solicitud de contenido identificado como potencialmente ilegal por Internet Watch Foundation. Otros ISP devuelven un error "prohibido" de HTTP 403 en las mismas circunstancias. La práctica de emplear errores 404 falsos como un medio para ocultar la censura también se ha informado en Tailandia y Túnez. En Túnez, donde la censura era severa antes de la revolución de 2011, la gente se dio cuenta de la naturaleza de los errores falsos 404 y creó un personaje imaginario llamado "Ammar 404" que representa "el censor invisible".