¿Cómo diseñar una API REST para manejar operaciones que no sean CRUD?

11

Estoy tratando de convertir un conjunto de servicios basados ​​en SOAP a una API RESTful.

Comencé identificando recursos analizando los nombres de las operaciones y obtuve el recurso Subscription.

Cuando necesito actualizar el estado de la suscripción, no puedo simplemente enviar una POSTsolicitud al servidor, porque no tengo acceso directo a los recursos, pero necesito llamar a algunas operaciones de estilo RPC para actualizar sus propiedades. Además, solo y solo si estoy cambiando el estado de la suscripción a "activo", se requiere una llamada adicional a un servicio externo.

En estos casos, ¿cuál es la mejor práctica para manejar las operaciones subyacentes?

La solución que se me ocurrió es usar parámetros de consulta, de modo que si necesito llamar al servicio de activación, puedo usar algo como:

POST /subscriptions/{subscriptionid}/?activate=true

Teniendo en cuenta que no puedo actualizar directamente mis campos de objeto de suscripción, ¿existe alguna práctica recomendada para manejar este tipo de conversión?

Actualización 1:

Puedo poner algunos valores en el cuerpo de mi solicitud POST, por ejemplo "estado": "activo"

y verifique dentro de mi servicio las operaciones adecuadas que se activarán.

Vektor88
fuente
La asignación de comandos de REST a los verbos HTTP falla con operaciones complejas. Usted está en mejor situación sólo haciendo una llamada de estilo RPC POSTAL activateSubscription / {id} nadie va a ser confundido por ella
Ewan
@Ewan No estoy seguro de que esto cumpla con el modelo RESTful, pero se me ocurrió otra solución: en mi código puedo llamar a la operación de estilo RPC adecuada de acuerdo con la carga útil de entrada (puedo pasar el estado = activo en el cuerpo de mi solicitud de publicación, el código llamará al código de activación)
Vektor88
1
Una actualización de un recurso existente como este debería ser un PATCH, y el cuerpo de la consulta es entonces un modelo parcial de lo que está cambiando. Se supone que una POST es una solicitud que crea un recurso. Esta distinción, además de ser más clara para el usuario, facilitará que su código sepa cuándo está ocurriendo esta operación en lugar de una publicación de recursos.
Sr. Cochese
1
@ Vektor88 Típicamente, pero esas son operaciones idempotentes en las que debe pasar la representación completa del estado de los recursos. Este caso de uso se parece mucho más a una actualización parcial, que se ajusta muy bien a un PATCH.
Sr. Cochese
1
@MrCochese POST no es idempotente.
JimmyJames

Respuestas:

8

Necesitas ver esta charla de Jim Webber.

Cuando necesito actualizar el estado de la suscripción, no puedo simplemente enviar una solicitud POST al servidor, porque no tengo acceso directo a los recursos, pero necesito llamar a algunas operaciones de estilo RPC para actualizar sus propiedades. Además, solo y solo si estoy cambiando el estado de la suscripción a "activo", se requiere una llamada adicional a un servicio externo.

Piensa en "mensajes"; envíe un mensaje a su dominio, describiendo lo que desea que suceda. El efecto secundario del mensaje es que su modelo de dominio en realidad cambia su estado. El "recurso" es la cola de mensajes.

POST /subscriptions/{subscriptionid}/?activate=true

La ortografía del nombre del recurso no es importante para las máquinas; pero la gente tiende a ponerse quisquillosa cuando los identificadores que usa rompen la convención de que los recursos son "sustantivos".

Además, estamos hablando de un recurso que está subordinado /subscriptions/{subscriptionid}, por lo que la convención (ver RFC 3986 ) requiere expresar esa relación con un segmento de ruta, en lugar de usar la parte de consulta.

Entonces estas ortografías pueden ser razonables

POST /subscriptions/{subscriptionid}/messages
POST /subscriptions/{subscriptionid}/activations
VoiceOfUnreason
fuente
1
La charla de Jim Webber está disponible en youtube.com/watch?v=aQVSzMV8DWc
user674669
0

Si es una bandera booleana para activar / desactivar cosas, diría que el valor predeterminado es usar JSON:

POST /subscriptions/{subscriptionid}/
{
    format: 0,
    subscription: 
    {
        active: false
    }
}

Esto se extiende fácilmente si desea admitir más propiedades. Otro enfoque es darle su propio punto final:

POST /subscriptions/{subscriptionid}/active/
DELETE /subscriptions/{subscriptionid}/active/

Personalmente, solo usaría esto si el activeestado de este evento necesita / tiene propiedades que luego puede pasar / obtener en JSON, como una ID de usuario o configuración.

Si no es un valor booleano, sino solo una acción que debe desencadenar, pero no necesita / tiene ningún comentario de estado (excepto un 200 OK inmediato), usaría un punto final como este para desencadenarlo como un RPC:

POST /subscriptions/{subscriptionid}/activate/

En caso de duda, lea esto: http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api#restful (consulte "¿Qué pasa con las acciones que no encajan en el mundo de las operaciones CRUD? ")

Barry Staes
fuente
0

REST no es funcional. Activatees un verbo y no puede ser un estado, Activees un estado.

Debido a que RESTful no es funcional, no puede decirle a un servicio RESTful qué hacer, pero puede agregar trabajo para la cola de un servicio.

Mira esto:

PUT /subscriptionQueue
subscriptionId={subscriptionId}
active=true

Esta solicitud es RESTful y admite todos los beneficios de RESTful (como rendimiento, ácido ...)

Peter Rader
fuente