2009-05-08 16 views
43

Para el sitio en el que estoy trabajando, estamos en el proceso de mejorar nuestras URL para un tipo de recurso, específicamente, alejándonos de los ID numéricos hacia cadenas descriptivas únicas. Un ejemplo similar sería pasar de identificar usuarios por ID de base de datos numérica a identificarlos por nombre de usuario (no es nuestro caso específico, sino análogo). Por lo tanto una URL para acceder a la información de un usuario que se utiliza para parecerse a:REST - compatible con múltiples identificadores posibles

/users/48573 

Y ahora parece que

/users/thisisausername. 

El único problema es que todavía tenemos que ser capaces de ir a buscar a través de identificadores numéricos de alguna manera , para los consumidores heredados de la API. No necesitamos las URL REST mismas para redirigir (por ejemplo, /users/48573 no debe redirigirse a /users/thisisausername), solo necesitamos un método para obtener los datos correctos utilizando el identificador antiguo. La solución debe proporcionar una forma alternativa de acceder a la información del usuario (que incluye convenientemente el nuevo identificador, nombre de usuario) por ID, o de acceder solo al nombre de usuario por ID. Algunas soluciones posibles podrían ser:

  • Utilizando un nodo para especificar algún método de identificación alternativo, p. /users/byid/48573
  • Utilizando un parámetro de consulta para especificar algún método de identificación alternativo, p. /users/48573?fetchby=id o /users/48573?byid=true
  • Tratamiento de nombre de usuario por ID como otro recurso, p. /identifiers/username/48573

¿Cuál de estos (si los hay) está más cerca del RESTO adecuado? ¿Cómo lidiarías con el problema?

+4

Terminé la implementación de acceso a través de los campos no-principal identificador como una búsqueda. Esta solución permite buscar múltiples tipos de recursos a través de múltiples campos, manteniendo solo uno como el identificador primario. Por consistencia, las listas de devolución de API de "búsqueda". Así que la forma oficial para tener acceso a un usuario es: /usuario/thisisausername y para el acceso de Identificación, tenemos:? /usuarios de id = 48573 Del mismo modo, se podría buscar en un número de diferentes campos , como en: /users? firstName = Kelly La inspiración era de: http://jwyseur.blogspot.com/2008/12/uri-design-for-rest.html (ver "buscar un recurso") –

+0

¿Entonces te pegaron en el almacenamiento en caché? Tengo el mismo problema que tú, pero no puedo resolver el problema a través de los parámetros de consulta que eliminan uno de los principales beneficios de una API REST. Me gusta tu primera sugerencia con viñetas ... – HDave

Respuesta

10

Su primera opción es probablemente la mejor.

Buscar usuarios por ID:

/users/id/48573 

Buscar usuarios por nombre corto:

/users/name/thisisausername 

Si dejan que parámetro de ruta, siempre se puede por defecto en su nuevo formato de nombre de usuario corto.

Otra opción que he visto un poco es el uso de parámetros de consulta como la siguiente:

/users?id=48573 
/users?name=thisisausername 

Creo que la primera se ve un poco más limpio y más fácil de leer.

+0

corto y al grano, ¡perfecto! –

-3

me gustaría considerar la calificación de la cadena con un sufijo opcional:

/users/48573/id 

/users/48573/name 

Si recibe una cadena sin el sufijo:

/users/48573 

entonces se comprueba la cuerda y ver si es un ID o nombre

Si usted consigue solamente una identificación válida, pero no un nombre, entonces es una recuperación por ID equivalente a:

/users/48573/id 

Si usted consigue solamente un nombre en aquel entonces una recuperación por Nombre equivalente a:

/users/48573/name 

Si se puede recuperar el valor de ID o el nombre, devuelve un error 300 de respuesta y enlaces a ambas posibilidades se devuelven al cliente:

/users/48573/id 

/users/48573/name 

Los consumidores heredados continúan trabajando 'como están', excepto por la aparición ocasional de pares duplicados de ID/nombre, donde reciben el nuevo error de respuesta 300.

+7

Esto no es REST en absoluto. Esto es solo RPC. – aehlke

-3

Su API no es RESTful si esto es un problema. Para quote Roy Fielding:

Una API REST no debe definir nombres de recursos fijos o jerarquías (un acoplamiento obvio de cliente y servidor). Los servidores deben tener la libertad de controlar su propio espacio de nombres. En su lugar, permita que los servidores instruyan a los clientes sobre cómo construir URIs apropiados, como se hace en formularios HTML y plantillas URI, definiendo esas instrucciones dentro de los tipos de medios y las relaciones de enlace. [La falla aquí implica que los clientes están asumiendo una estructura de recursos debido a la información fuera de banda, como un estándar específico de dominio, que es el equivalente a datos orientado al acoplamiento funcional de RPC].

Se debe ingresar una API REST sin conocimiento previo más allá del URI inicial (marcador) y un conjunto de tipos de medios estandarizados apropiados para la audiencia prevista (es decir, que cualquier cliente que pueda usar la API entienda) . A partir de ese punto, todas las transiciones de estado de la aplicación deben ser impulsadas por la selección del cliente de las elecciones provistas por el servidor que están presentes en las representaciones recibidas o implícitas por la manipulación del usuario de esas representaciones. Las transiciones pueden determinarse (o limitarse por) el conocimiento del cliente de los tipos de medios y los mecanismos de comunicación de recursos, los cuales pueden mejorarse sobre la marcha (por ejemplo, código bajo demanda). [El error aquí implica que la información fuera de banda genera interacción en lugar de hipertexto.]

+1

Esta no es una respuesta a su pregunta. Una API REST puede admitir HATEOAS todo el día y, sin embargo, los desarrolladores de servidores aún deben preocuparse por los problemas del diseño de URI. – HDave

28

Creo que agregar un segmento de ruta/prefijo es la mejor respuesta. Dado que estas son claves secundarias únicas, esto no es lo mismo que la búsqueda (que devuelve un conjunto de elementos), por lo que el uso de parámetros de consulta (que no están en caché) no parece ser la mejor opción.

Personalmente, plan para usar un prefijo de segmento de trayectoria delimitada por "=", como "name =" o "email =":

user/123456 
user/name=john.doe 
user/[email protected] 

Este es funcionalmente equivalente a la adición de un segmento de trayectoria (por ejemplo, " usuario/nombre/john.doe "), pero me parece que se aproxima más al modelo conceptual. Por supuesto, esto es un detalle insignificante, ya que las API RESTful no deberían especificar una estructura URI fija de todos modos.

No usar parámetros de consulta también permite sub-recursos para acceder de forma natural:

user/name=john.doe/inbox/df87bhJXrg63 

marcos como JAX-RS de ayuda JAVA utilizando cualquier delimitador que desee:

@GET 
@Path("user/{id}") 
User getUser(@PathParam("id") UUID id); 

@GET 
@Path("user/name={name}") 
User getUserByName(@PathParam("name") String name); 

@GET 
@Path("user/email={email}") 
User getUserByEmail(@PathParam("email") String email); 
+2

Este es un enfoque interesante que no he visto antes. Resuelve el problema muy bien, pero no puedo pasar el hecho de que ver el signo igual fuera de los parámetros de consulta parece causar confusión ... – HDave

+4

Además, no es muy tranquilo. ¿Cuál es exactamente el nombre de la colección = john.doe? Para mí, debe ser un parámetro de matriz: usuario; nombre = john.doe/inbox/df87 ... http://blog.2partsmagic.com/restful-uri-design/ – Maladon

+0

@Maladon Creo que eres perdiendo el punto. 'name = john.doe' no debe ser una colección, ya que' name' es un identificador único. Estamos buscando exactamente un objeto o un error. 'user; name = john.doe' parece una búsqueda. Esperaría que devuelva la misma representación que 'user', que es una colección. –

0

Es toda una cuestión de edad, sino Tuve el mismo y finalmente encontré la solución: usa la expresión regular en tu camino param.

Así es como codifiqué ese caso el uso

@GET 
@Path("/{id : \\d+}") 
@Produces(APPLICATION_JSON) 
public Response getById(@PathParam("id") long id) { 
<<your code>> 
} 

@GET 
@Path("/{name}") 
@Produces(APPLICATION_JSON) 
public Response getByName(@PathParam("name") String name) { 
<<your code>> 
} 
+1

¿Qué sucede si el nombre del usuario es numérico? Si un usuario puede elegir su nombre libremente y decide usar solo un número, su enfoque falla. –

+0

falla o no. Debe realizar controles en la solicitud de creación (POST) y puede rechazar el nombre numérico solo. – Javathought

+0

@@ POST public Response create (@Valid User user) y anota tu modelo con la validación de bean. Ejemplo: debe comenzar con una letra en mayúscula, 50 caracteres máx. @@ Patrón (regexp = "[AZ] [a-zA-Z_0-9-] {0,49}", mensaje = "nombre inválido") privado Nombre de cadena; – Javathought

Cuestiones relacionadas