Al implementar DDD, solemos chocar de frente con cómo se diseñan habitualmente las APIs REST. ¿Estamos haciendo algo mal?
Hemos debatido un poco sobre los puntos en los que choca la expresividad de nuestro dominio con el diseño de una API realmente RESTful (no RESTish).
Se han expuesto varias alternativas:
{"cmd": "approve", "invoiceId": 4}
Los comandos se añaden en recurso aparte, los recursos que representan entidades son de solo lectura.
Intentamos crear subrecursos y "Sustantivizar" las operaciones para señirnos al paradigma de documentos de REST, sacrificando los verbos del lenguaje ubicuo.
Cortar por lo sano y no usar REST sino RPC, sobre todo para disparar procesos de negocio, y respetando los verbos del lenguaje ubicuo. La lectura puede hacerse en recursos separados (si tenemos un read model, se puede exponer con REST)
{"cmd": "approve"}
Definir subrecursos que admitan añadir operaciones que exponen los verbos del lenguaje ubiquo. El estado expuesto en el recurso principal no se puede modificar (PUT/PATCH) directamente.
Al recuperar un recurso (con GET), los enlaces de hipermedia contienen el verbo (comando), aunque este no se utiliza al enviar la peticion de cambio.
El atributo rel
(de relation) suele equipararse al texto de un enlace HTML, como "Texto" en <a href="link">Texto</a>
.
Entonces nuestros controles de hipermedia quedarían así:
GET /toaster/3
{
"id": "toaster/3",
"state": "off",
"operations": [
{
"rel": "turnOn",
"method": "PUT",
"href": "/toaster/3",
"expects": {"state": "on"}
}
]
}
(aunque seguramente sería mejor utilizar otro campo o seguir un mediatype establecido)
Y luego para la operación:
PATCH /toaster/3
{
"state": "on"
}
Ej: Siren
Más RESTish que RESTful: Usar verbos en las URIs, y no reparar en la interfaz uniforme de REST. Un POST a /aprove
cambia el estado approved
de /invoice
.
Como conclusión hemos puesto sobre la mesa que hay un espectro continuo de soluciones, algunas más fieles al dominio y otras mas fieles a los principios RESTful. También hemos hablado de que es imporante reparar en el público (las desarrolladoras) que consumirán este código, ya que no es lo mismo una API interna, que una pública y abierta.