2009-05-08 14 views
43

Per il sito su cui sto lavorando, stiamo migliorando i nostri URL per un tipo di risorsa, in particolare spostando gli ID numerici verso stringhe univoche e descrittive. Un esempio simile potrebbe essere il passaggio dall'identificazione degli utenti tramite l'ID numerico del database all'identificazione per nome utente (non il caso specifico, ma analogo). Quindi un URL per accedere alle informazioni di un utente utilizzato per assomigliare:REST - supporto di più identificatori possibili

/users/48573 

Ed ora sembra che

/users/thisisausername. 

L'unico problema è che abbiamo ancora bisogno di essere in grado di prendere loro attraverso gli ID numerici in qualche modo , per i clienti legacy dell'API. Non abbiamo bisogno gli URL riposarsi per reindirizzare (ad esempio /users/48573 non dovrebbe reindirizzare a /users/thisisausername), abbiamo solo bisogno di un metodo per ottenere i dati corretti utilizzando il vecchio identificativo. La soluzione dovrebbe fornire un modo alternativo di accedere alle informazioni dell'utente (che include comodamente il nuovo identificativo, nome utente) per ID o di accedere solo al nome utente per ID. Alcune possibili soluzioni potrebbero essere:

  • Utilizzare un nodo per specificare un metodo alternativo di identificazione, ad es. /users/byid/48573
  • Utilizzando un parametro di query per specificare un metodo alternativo di identificazione, ad esempio /users/48573?fetchby=id o /users/48573?byid=true
  • Trattamento nome utente-by-id come un'altra risorsa, ad esempio /identifiers/username/48573

Quale di questi (se presente) è più vicino al REST corretto? Come affronteresti il ​​problema?

+4

ho finito per implementare l'accesso tramite campi non-principale-identificatore come una ricerca. Questa soluzione consente di recuperare più tipi di risorse tramite più campi, pur mantenendo solo uno come identificativo principale. Per coerenza, le API di "ricerca" restituiscono gli elenchi. Quindi il modo ufficiale per accedere a un utente è: /user/thisisausername e per l'accesso da parte ID, abbiamo:? /utenti id = 48573 Allo stesso modo, si potrebbe cercare una serie di campi diversi , come in: /users? firstName = Kelly L'ispirazione era da: http://jwyseur.blogspot.com/2008/12/uri-design-for-rest.html (vedi "cercare una risorsa") –

+0

Quindi hai puntato sul caching? Ho lo stesso problema che hai, ma non posso risolverli con i parametri di query che rimuovono uno dei principali vantaggi di un'API REST. Mi piace il tuo primo suggerimento puntato ... – HDave

risposta

10

La prima opzione è probabilmente il migliore.

Ricerca di utenti da ID:

/users/id/48573 

Ricerca per gli utenti per nome breve:

/users/name/thisisausername 

Se lasciano che il parametro percorso, si può sempre di default per il vostro nuovo formato nome utente breve.

Un'altra opzione che ho visto un bel po 'è quello di utilizzare parametri di query come la seguente:

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

Credo che il primo sembra un po' più pulito e più leggibile.

+0

breve e perfetto, perfetto! –

-3

mi piacerebbe prendere in considerazione le qualifiche la stringa con un suffisso opzionale:

/users/48573/id 

/users/48573/name 

Se si riceve una stringa senza il suffisso:

/users/48573 

quindi di controllare la stringa e vedere se si tratta di un ID o nome.

Se si ottiene solo un documento d'identità valido, ma non un nome, allora si tratta di un recupero per ID equivalente a:

/users/48573/id 

Se si ottiene solo un nome allora si tratta di un recupero per nome equivalente a:

/users/48573/name 

Se è possibile recuperare il valore per ID o il nome, allora si restituisce un errore 300 di risposta e ritorni collegamenti per entrambi possiblities al client:

/users/48573/id 

/users/48573/name 

I clienti legacy continuano a funzionare "così come sono" tranne che per il verificarsi occasionale di coppie ID/nome duplicate in cui ricevono il nuovo 300 errore di risposta.

+7

Questo non è affatto REST. Questo è solo RPC. – aehlke

-3

L'API non è RESTful se questo è un problema. A quote Roy Fielding:

Un'API REST non deve definire nomi di risorse fisse o gerarchie (un accoppiamento ovvio di client e server). I server devono avere la libertà di controllare il proprio spazio dei nomi. Invece, consentire ai server di istruire i clienti su come costruire URI appropriati, come avviene nei moduli HTML e nei modelli URI, definendo tali istruzioni all'interno dei tipi di media e delle relazioni di collegamento. [L'insuccesso qui implica che i clienti stiano assumendo una struttura di risorse a causa di informazioni fuori banda, come uno standard specifico del dominio, che è l'equivalente orientato ai dati dell'accoppiamento funzionale di RPC].

Un'API REST deve essere immessa senza alcuna conoscenza preliminare oltre l'URI iniziale (segnalibro) e un insieme di tipi di supporti standardizzati appropriati per il pubblico previsto (vale a dire, è previsto che vengano compresi da qualsiasi client che potrebbe utilizzare l'API) . Da quel momento in poi, tutte le transizioni dello stato dell'applicazione devono essere guidate dalla selezione dei client delle scelte fornite dal server presenti nelle rappresentazioni ricevute o implicite dalla manipolazione dell'utente di tali rappresentazioni. Le transizioni possono essere determinate (o limitate dalla) conoscenza da parte del cliente dei tipi di media e dei meccanismi di comunicazione delle risorse, entrambi possono essere migliorati al volo (ad esempio, code-on-demand). [Il fallimento qui implica che le informazioni fuori banda stanno guidando l'interazione invece dell'ipertesto.]

+1

Questa non è una risposta alla sua domanda. Un'API REST può supportare HATEOAS tutto il giorno, eppure gli sviluppatori del server devono ancora preoccuparsi dei problemi di progettazione degli URI. – HDave

28

Penso che aggiungere un segmento segmento/prefisso sia la risposta migliore. Poiché si tratta di chiavi secondarie univoche, non è la stessa cosa della ricerca (che restituisce un insieme di elementi), quindi l'utilizzo dei parametri di query (che non sono memorizzati nella cache) non sembra la scelta migliore.

Personalmente, ho intenzione di utilizzare un prefisso segmento di percorso delimitato da "=", come "name =" o "email =":

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

Questo è funzionalmente equivalente ad aggiungere un segmento di percorso (ad esempio " user/name/john.doe "), ma mi sembra come se fosse più vicino al modello concettuale. Ovviamente, questo è un dettaglio insignificante, poiché le API RESTful non dovrebbero comunque specificare una struttura URI fissa.

Non utilizzando parametri di query consente anche sotto-risorse a cui accedere, naturalmente:

user/name=john.doe/inbox/df87bhJXrg63 

Framework come di Java JAX-RS supportano utilizzando qualsiasi delimitatore che vuoi:

@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

Questo è un approccio interessante che non ho mai visto prima. Risolve bene il problema, ma non riesco a superare il fatto che vedere il segno di uguale fuori dai parametri di ricerca sembra causare confusione ... – HDave

+4

Inoltre, non è molto riposante. che cosa, esattamente, è il nome della raccolta = john.doe? Per me dovrebbe essere un parametro matrix: utente; name = john.doe/inbox/df87 ... http://blog.2partsmagic.com/restful-uri-design/ – Maladon

+0

@Maladon Penso che tu sia manca il punto. 'name = john.doe' non dovrebbe essere una collezione, dato che' name' è un identificatore univoco. Stiamo cercando esattamente un oggetto o un errore. 'user; name = john.doe' sembra una ricerca. Mi aspetterei che restituisca la stessa rappresentazione di 'utente', che è una collezione. –

0

Piuttosto una vecchia questione, ma Ho avuto lo stesso e finnaly trovato la soluzione: usa regex nel tuo percorso param.

Ecco come ho codificato questo caso l'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

Cosa succede se il nome dell'utente è numerico? Se un utente può scegliere liberamente il suo nome e decide di utilizzare solo un numero, il tuo approccio fallisce. –

+0

fallisce o no. È necessario effettuare controlli sulla richiesta di creazione (POST) e rifiutare il solo nome numerico. – Javathought

+0

@@ POST pubblica risposta creare (utente utente @Valid) e annotare il modello con convalida del bean. Esempio: deve iniziare con una lettera maiuscola, 50 caratteri max @@ Pattern (regexp = "[AZ] [a-zA-Z_0-9-] {0,49}", message = "nome non valido") private Nome della stringa; – Javathought

Problemi correlati