Decisione di progettazione / struttura dell'API riposante

2

Attualmente sto creando la mia prima API riposante per una WebApp e sono al punto in cui non sono sicuro, come strutturarlo al meglio.

Informazioni di background

Sto sviluppando una piantatrice di feste per un'azienda. La compagnia è divisa in alcuni dipartimenti. Quindi alcuni utenti sono nel dipartimento A e altri in B per esempio. Le informazioni sul reparto sarebbero accessibili /department/ e gli utenti in /users/ .

Tutti gli utenti possono fare una richiesta di vacanza. Rimaniamo accessibile con /holiday/ . Per ogni dipartimento c'è una minStock degli utenti che deve rimanere nella compagnia, in modo tale che il nostro supporto per i prodotti sia ancora vivo ;) Come puoi vedere c'è una stretta relazione tra i dipartimenti, gli utenti e la richiesta / prenotazioni di vacanze confermate.

Possibile modo di farlo, o no?

A un certo punto devo visualizzare nella mia interfaccia utente quali utenti di un dipartimento specifico hanno già richiesto una festività, quindi potrebbe essere /holiday/department/:departmentID o /department/holiday/:departmentID . Probabilmente ho sbagliato completamente qui e lo avresti progettato completamente diverso.

Non voglio mettere troppe informazioni qui e sto semplicemente in questo semplice esempio. Sono entusiasta di sapere come lo faresti quando guardi queste informazioni.

Se mi sono perso qualcosa, chiedimi nei commenti e farò del mio meglio per fornirti tutto il necessario per aiutarmi!

Ovviamente a un certo punto della mia APP avrò bisogno di tutte le richieste di ferie senza filtrare per un dipartimento. Non sono sicuro che ciò influenzerà il design generale, voglio solo aggiungere questo qui.

    
posta el solo lobo 02.11.2016 - 14:58
fonte

3 risposte

2

Se stai cercando di essere il più possibile conforme a REST, ti suggerisco di tenere conto di questi 2 suggerimenti. (Finora, hanno funzionato bene per me):

  1. L'URI è una rappresentazione di una risorsa all'interno di una gerarchia (questa è una preferenza personale)

    Come @AilurusFulgens ha commentato nella mia risposta:

    URI should stay an identifier, not provide any meaning

    True. Tuttavia, vogliamo comunque che sia leggibile e alcune letture potrebbero sembrare innaturali dal nostro punto di vista. IMO, le gerarchie portano un po 'di leggibilità. Ma sono d'accordo sul fatto che possono portare a presupposti sbagliati e causare l'accoppiamento tra client-server .

    Raccomando di leggere i commenti qui sotto e di visitare la pagina che è stata condivisa. Chiarisce le cose intorno a questo argomento.

  2. I parametri URI (stringhe di query) devono essere utilizzati per modificare l'output. Ad esempio, filtraggio, impaginazione, ecc.

Eviterei:

GET /holidays/department/:departmentID
GET /department/holidays/:departmentID

Perché dovrei? Perché questi due mi sembrano meno leggibili.

La mia proposta

I. Dalla festività :

GET /holidays #all the holidays
GET /holidays?from=timestamp&to=timestamp&user.department=x
GET /holidays?from=timestamp&to=timestamp&status=confirmed&user.department=x

A causa di ciò che stiamo facendo è di recuperare le festività in base a determinate condizioni, poniamo queste condizioni all'interno della query invece che all'interno del percorso (Potrebbe interessare Schema URI )

II. Dalla sezione dipartimento :

GET /department/:departmentID/holidays?from=timestmap&to=timestmap
GET /department/:departmentID/holidays?from=timestmap&to=timestmap&status=confirmed

Qui / dipartimento /: departmentID è già in fase di festività

Infine, c'è un terzo modo.

Json-RPC - come un servizio simile.

GET /ws/holidays/getPlan

Il getPlan dovrebbe essere la procedura remota (funzione) e gli argomenti vanno nel corpo della richiesta. L'invio di un corpo di richiesta all'interno di una richiesta GET potrebbe sembrare un po 'inappropriato (non mi interessa). Ma è possibile .

Soluzioni al precedente "svantaggio":

I. Usa POST

II. Utilizza i parametri di richiesta

GET /ws/holidays/getPlan?from=timestamp&to=timestamp&department=x

GET /ws/holidays/getPlan?from=timestamp&to=timestamp& status=confirmed&department=x

Questo approccio offre un vantaggio interessante. La risposta. Non è associato a nessuna risorsa. Non è né utente , festività dipartimento . Può essere un mix o qualcosa di più complesso, con molti altri dettagli (come "minStock" del dipartimento, punti vuoti, ecc.)

    
risposta data 02.11.2016 - 23:01
fonte
4

Benvenuto nello strano mondo del middleware!

Un api RESTful vuole rendere le cose piacevoli, specialmente se altri sviluppatori lo stanno usando. In generale, ogni risorsa dovrebbe puntare su un oggetto particolare, discreto, quasi il 100% delle volte un nome.

Quindi, sei effettivamente sulla strada giusta. GET /v1/holiday/ dovrebbe ottenere un elenco di festività dall'intero sistema mentre GET /v1/holiday/134 dovrebbe ottenere la festività con l'ID 134. Ciò che ho trovato utile in passato è creare una tabella con ogni risorsa a sinistra, e i diversi verbi tu voglio usare in alto. Quindi, riempire le celle con ciò che dovrebbe fare la combinazione di Verb e Noun. Va bene anche per tagliare le cose in questa fase, ad esempio se vuoi evitare che un utente elimini cose come le risorse utente.

Un'altra nota che se hai una relazione HAS-A, dovresti annidarli. Nel tuo esempio, una particolare richiesta di ferie è di proprietà di un utente, quindi la richiesta dovrebbe probabilmente vivere a GET /v1/user/901/request/123 .

Questo è un ottimo post sul blog sulle API pragmatiche, e in generale il modello I segui quando ne implementa uno nuovo.

L'unica altra cosa che noterò è che sono un grande fan dell'API di versioning. In questo modo, posso mettere insieme la versione v1 a https://yourdomain.com/v1/resources e poi se ci sono problemi o dobbiamo fare un sacco di cambiamenti, possiamo successivamente spingere https://yourdomain.com/v2/resources e non influenzare le implementazioni esistenti.

Buona fortuna!

    
risposta data 02.11.2016 - 15:39
fonte
1

Un po 'di nomi potrebbe aiutare. Puoi avere una tabella per le vacanze ma ci sono alcune risorse REST diverse:

user
department
holiday-request
holiday (not a real table in first example, there is just on holidays table)

Ad esempio, puoi scegliere:

GET /v1/holiday-requests -> List of all requests
GET /v1/holiday-requests/{requestId} -> {id: 123, status: pending}

GET /v1/users/{userId}/holiday-requests -> List of all requests for this user
GET /v1/users/{userId}/holidays -> List of all booked holidays

GET /v1/departments/{depId}/holiday-requests -> All requests for this holiday
GET /v1/departments/{depId}/holidays -> All booked holidays for department

POST /v1/holiday-requests {userId: 123, date: 2016-11-02}
  Possible results:
    201 created -> Request ok
    401 conflict -> Trying to request holiday which is not possible anymore because limit is reached.

PATCH /v1/holiday-requests/{requestId} {status: accepted} -> Make it a real holiday, and so count agains minStock. 
So now a new resource becomes available: /v1/holidays/{requestId}

GET /v1/holiday-requests/{requestId} -> {id: 123, status: accepted}

Puoi anche dare vacanze e vacanze-richieste separate da id. Ciò offre maggiore flessibilità, quindi puoi fare:

PATCH /v1/holiday-requests/{requestId} {accepted: true} 
  -> Make it a real holiday, and so count agains minStock. 
Internally you could do a post agains: /v1/holidays {requestId: {requestId}, date: .... }
So now a new resource becomes available: /v1/holidays/{holidayId}

GET /v1/holiday-requests/{requestId} -> {id: 123, status: accepted, holiday: /v1/holidays/{holidayId}

La cosa più semplice è leggere di più su cosa sia una risorsa in REST. Ciò fornisce molte idee su dove è possibile creare risorse più piccole.

Modifica: come vedi, aggiungo un url alla risorsa correlata. Si chiama HAETOAS, ad esempio qui: link su come funziona quel processo di pensiero.

    
risposta data 02.11.2016 - 17:45
fonte

Leggi altre domande sui tag