Cuándo usar recursos anidados en una API RESTful

16

Tengo dos recursos: usuarios y enlaces.

Los usuarios pueden tener varios enlaces asociados con ellos. He diseñado mi API RESTful para que pueda acceder a los enlaces asociados con un usuario en el siguiente URI:

/users/:id/links

Sin embargo, siempre necesito tener un URI solo para enlaces, a veces podría querer todos los enlaces, independientemente del usuario.

Para esto tengo:

/links

¿Suena bien? ¿Tienes dos URI para enlaces?

Me pregunto si debería alcanzar los enlaces para un usuario con un URI como:

/links/user/:id o /links/?user=:id

De esta manera, solo tengo un recurso para enlaces.

Oliver Joseph Ash
fuente
3
hmm .. Este parece más elegante:/links/user/:id
theMarceloR
77
@theMarceloR: Ese es el único ejemplo de los tres que no encuentro particularmente claro. ¿Es el recurso para un enlace o un usuario? El URI es mucho menos ambiguo utilizando el método de recurso anidado ( /users/:id/links) o el método de cadena de consulta ( /links/?user=:id) ya que de hecho es una consulta. /links/user/:idpuede verse bien y / o ser más fácil de enrutar en algunos marcos, pero en realidad es bastante confuso.
Aaronaught

Respuestas:

16

No, no hay nada de malo en tener múltiples recursos para la misma "cosa", en este caso listas de enlaces.

Recientemente estábamos luchando con el mismo problema. Nuestra decisión fue tener todos los recursos donde no existe una propiedad estricta para no anidar. En otras palabras, los enlaces se modelarían bajo

/links -- all links
/links/:linkid -- a particular link

Luego, los filtros en la colección de enlaces se expresan como parámetros de consulta. Entonces, para obtener los enlaces de un determinado usuario, usaría:

/links?user=/users/:userid

Esto también permite una composición más fácil de los filtros:

/links?user=/users/10&since=2013-01-01

Y es fácil de entender conceptualmente: tiene una colección de artículos y le agrega filtros.

Dicho esto, no hay nada más "RESTful" sobre este enfoque que cualquier otro esquema de nombres de URI. Es solo una convención que nos pareció legible y fácil de entender para los desarrolladores. A REST no le importa lo que pones en tus identificadores de recursos.

Waxwing
fuente
1
"Todos los recursos donde no hay una propiedad estricta para no anidar" parece una buena regla. Gracias un montón.
Oliver Joseph Ash
55
Yo diría que no es algo malo en tener múltiples recursos para la misma entidad física, pero eso no es realmente lo que se trata. Cada enlace individual tiene una URL canónica (enlaces /: id), mientras que cada uno de los recursos anteriores son, de hecho, un solo recurso (/ enlaces) con filtros aplicados. Además, me extraña ?user=users/:useridla cadena de consulta; ¿Qué está mal con solo ?userid=:userid?
Aaronaught
2
@Aaronaught: la razón para apegarse a los identificadores de uri en lugar de identificadores es para que los clientes puedan tratar todos los identificadores de recursos por igual, es decir, un cliente solo necesita saber que 'este usuario está identificado por "/*******"; donde los *'s son opacos. pero ese mismo identificador siempre se puede utilizar para referirse a ese recurso (como en, con enlaces), para obtener la versión más actual de ese recurso, etc. el contenido de esa uri solo lo entiende el servidor de origen. Esto también significa que si los identificadores necesitan cambiar, por ejemplo /realm/:businessid/users/:id, el cliente no cambia en absoluto.
SingleNegationElimination
@TokenMacGuy: Lo siento, no entiendo ninguna parte de tu comentario. ¿Cuál es la diferencia práctica entre /users/:userid/linksy /links?userid=:userid? En ambos casos, los identificadores no cambian, obtienen la versión actual de ese recurso y el cliente los trata de la misma manera. No existe una URL canónica para esto porque no es un recurso, es una consulta, por lo que estos son solo dos tipos diferentes de sintaxis de consulta. Tampoco tengo claro cómo el cliente no necesitaría cambiar si cambia la estructura de la URL; eso se considera un cambio importante en REST a menos que se establezca un 301.
Aaronaught
1
@Aaronaught: Podría haber entendido mal su preocupación. Suponiendo que /linksadmite una interfaz de consulta, /links?user=/users/123permite un enfoque de recuadro negro para los identificadores de recursos en clientes que /links?userid=123no lo hace. esto último requiere que el cliente entienda qué es un ID de usuario y cómo obtenerlo, presumiblemente del recurso que obtuvo de /users/123o /links/456/user. El primero significa que el cliente puede usar la uri sin modificaciones; suponiendo que /links/.../userda una respuesta hipermedia (por ejemplo, con Location:encabezados).
SingleNegationElimination
1

Entonces, mi preocupación es: / users /: userid / links devuelve "links", PERO si el user_id no está identificado, esto debería devolver un 404.

sin embargo

/ links? userid =: userid potencialmente devolvería una lista vacía (esencialmente un 200) que en realidad es probablemente un error. Y muy posible.

Aunque ambos funcionan, la anidación le brinda una funcionalidad adicional que luego puede utilizar.

Richard Browne
fuente