Uso corretto dei VERBI HTTP nell'implementazione REST personalizzata

1

Ho un servizio lato server (utilizzando ASP.NET Core) che dovrebbe fornire un'API REST a vari client.

Dietro il servizio, utilizzo un server SQL per l'archiviazione dei dati.

Il controller ha il seguente attributo di percorso:

[Route("api/[controller]")]
[ApiController]
public class CustomDataController : ControllerBase
{…}

Esistono metodi di provider di dati:

[HttpGet(nameof(GetDataForGuest))]
public async Task<IQueryable<Specs>> GetDataForGuest(int skip, int take, Guid organizationID) => await dataProvider.GetDataAsync<Specs>(skip, take, organizationID);

Esistono metodi per creare o aggiornare dati sul server:

[HttpPost(nameof(SaveDataToServer))]
public async Task SaveDataToServer([FromBody] List<Specs> specs) => await dataProvider.SaveDataAsync<Specs>(specs, isNewData: true);

Secondo molti articoli (come questo ), GET serve per restituire alcune risorse, POST è per la creazione e PUT è per l'aggiornamento:

  • GET — For returning resources
  • POST — For creating a new resource
  • PUT — For updating a resource
  • PATCH — For updating a resource
  • DELETE — For deleting a resource

Tuttavia, come puoi vedere, i miei metodi sono solo facciate, i dati vengono salvati dal fornitore di dati e posso decidere in base a una variabile bool per inserire o aggiornare un record in entrata.

Come puoi anche intuire, non utilizzo gli URL REST tradizionali (come api/user/1 ), poiché ho bisogno di dati complessi, quindi i miei URL sono simili a questo:

https://192.168.0.101:8080/api/customdata/GetDataForGuest?skip=0&take=10&organizationID=58b77372-abbc-435e-9a5b-d77bc05129c7

Al momento ottengo dati con HttpPost sia per l'inserimento di nuovi record che per l'aggiornamento di quelli esistenti (e funziona normalmente). Le mie preoccupazioni riguardano le best practice: dovrei usare HttpPut quando voglio aggiornare un record esistente? Secondo le specifiche, l'utilizzo di PUT è idempontent per definizione mentre POST non lo è, quindi l'esecuzione della query non dovrebbe dipendere da quante volte è stata chiamata.

Sul lato client, utilizzo alcune query building (in base ai parametri) e chiamo il metodo con un'azione POST :

public async Task SaveDataToServer(string methodName, List<T> data, bool isNewData)
{
  var parameters = GetParameters(methodName, isNewData);
  var baseUri = new Uri(baseUriString, methodName);
  var targetUri = UriBuilding(baseUri, parameters).AbsoluteUri;
  var result = await httpClient.PostAsync<List<T>>(targetUri, data);
}

Quindi utilizzare solo POST è considerato una best practice? O dovrei separare le azioni di aggiornamento in un altro metodo contrassegnato con HttpPut ? Ha importanza considerando che la logica dietro i metodi decide cosa accadrà e non il verbo?

    
posta Nestor 22.11.2018 - 09:58
fonte

5 risposte

2

In base a questo ottimo tutorial , ci sono diversi problemi con il mio approccio iniziale.

  • Good: /users/12345
  • Poor: /api?type=user&id=23
  • POST Create
  • GET Read
  • PUT Update/Replace
  • PATCH Update/Modify
  • DELETE Delete

Quindi sembra che devo ridisegnare la mia API RESTless personalizzata, ma seguendo questi suggerimenti, sarà molto più simile a REST.

    
risposta data 22.11.2018 - 19:25
fonte
1

Se fornisci un client per la tua API, non importa.

"RESTfullness" implica per la maggior parte delle persone che mappi i diversi verbi alle tue operazioni.

Tuttavia, come si nota non è sempre l'approccio più pratico e l'asserzione è in qualche modo arbitraria.

Ma l'unica ragione per usare i verbi è che i consumatori dell'API possano creare i propri clienti seguendo le convenzioni così come li vedono.

Se si fornisce semplicemente un client già scritto per l'utilizzo da parte dei consumatori, non vedranno mai l'uso sottostante del protocollo. Puoi usare POST o anche DELETE per tutto, se lo desideri.

Inoltre. le "specifiche" per REST sono super vaga. L'idea è che semplicemente sfogliando l'API un utente sarebbe in grado di capire le operazioni. Tuttavia nella pratica questo non è davvero possibile. Per le API di qualsiasi complessità, l'utente consulta e segue la documentazione.

A quel punto puoi semplicemente dire "per questa operazione usa POST" l'utente non sarà confuso, il suo client non si romperà, faranno solo "tsk" se non sono d'accordo e scrivono "POST"

    
risposta data 22.11.2018 - 18:55
fonte
1

According to many articles (like this one), GET is for returning some resource, POST is for creating and PUT is for updating:

Sì, ci sono molti articoli che lo dicono.

C'è un problema di coerenza in quella posizione. Il world wide web dipende strongmente da HTTP. I client HTTP più familiari sono i browser Web; applicazioni in cui il caso d'uso principale è il rendering HTML. E HTML include solo il supporto nativo per GET e POST .

Quindi quando chiedi:

only POST is considered as best practice?

La mia risposta: ha funzionato nei browser web per più di 20 anni.

Se vuoi capire cosa significano i metodi HTTP, allora devi leggere la specifica appropriata. Per i metodi "standard", significa sezione 4.3 di RFC 7231 . Per altri metodi, puoi cercarli nel registro dei metodi HTTP e seguire il collegamenti forniti lì alle fonti autorevoli.

I metodi HTTP non descrivono cosa il server , ma invece quali componenti generici sono autorizzati a assumere ; vincolano la semantica delle richieste, non le implementazioni.

    
risposta data 26.11.2018 - 01:34
fonte
1

Magari usi una più semplice API in stile RPC? Dove tutto è un POST ed come JSON. Alcune aziende si sono spostate usando quella invece di REST. Come l'API di Dropbox v2 link

Anche la nostra azienda è passata dalle API in stile REST a quelle RPC ed è eccezionale.

Modifica: nel nostro download di file binari dell'API viene ancora utilizzato GET e il caricamento binario continua a utilizzare il normale caricamento del file di modulo HTTP.

    
risposta data 03.12.2018 - 18:15
fonte
0

Ci sono alcune cose qui che penso siano (comuni) fraintendimenti della semantica HTTP e / o REST. Come notato nelle risposte / commenti, REST e HTTP sono distinti ma i concetti di REST derivano da come il web e l'HTTP funzionano (e in misura molto minore, cosa non ha funzionato così bene) quindi la distinzione non è così importante , solo qualcosa da archiviare nella parte posteriore della mente.

PUT — For updating a resource

Questo è probabilmente il malinteso più comune sui verbi HTTP. Sì, PUT può e viene utilizzato per aggiornare le risorse. Può anche, tuttavia, essere utilizzato per creare risorse. L'unico requisito è che sia idempotente. In termini semplici è una scrittura. Se ci fosse qualcosa in un dato URI prima di fare un PUT su di esso è irrilevante. L'unica cosa che importa è come appare dopo aver scritto. POST crea anche risorse ma la distinzione e PUT (da una prospettiva REST) è che con POST , il server controlla quale sia l'URI per quella risorsa. Con "PUT" il client lo controlla. POST è anche non idempotente. È un affare one-shot ed è per questo che a volte ricevi errori in un browser che ti dice che stai tentando di inviare nuovamente una richiesta di POST . In sostanza, stai dicendo che potresti creare una seconda risorsa che potrebbe essere negativa se la risorsa creata rappresenta un acquisto, ad esempio. Se hai bisogno di PUT o POST creare semantica (o entrambi) dipende dalle tue esigenze specifiche.

A un livello base, se hai bisogno di centralizzare il controllo di come vengono creati gli URI (ad es. evitare collisioni URI tra client) e applicare regole "una sola volta", probabilmente dovresti usare POST . L'altra situazione comune in cui POST è una buona misura è quando si ha un requisito asincrono. Hai il problema del client a POST e restituisci l'URI in cui i risultati saranno disponibili. In questo modo il cliente ottiene una conferma immediata che la richiesta è stata ricevuta e ha un riferimento che può utilizzare per chiedere al server la richiesta. Spesso le risorse generate in questo modo sono disponibili solo per un determinato periodo di tempo.

As you can also guess, I don't use traditional REST URLs (like api/user/1), as I need complex data, so my URLs look like this: ...

Questo è un altro malinteso comune. Gli URI REST non hanno bisogno di apparire come qualcosa in particolare. Un sacco di gente sosterrà che un URI leggibile dall'uomo non è affatto RESTful. Ci sono dei buoni argomenti sul perché questo sia il caso, ma direi che non è richiesto. Può essere molto utile avere URI leggibili dall'uomo, ma non dovresti sentirti costretto. Se / quando utilizzare i parametri di query è una buona pratica è discutibile, ma non c'è nulla di intrinsecamente non-RESTful su questo. La semantica di REST può ancora essere seguita. Si tratta di aspettative .

    
risposta data 03.12.2018 - 23:37
fonte

Leggi altre domande sui tag