Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Gestione CRUD delle risorse

Associare ai metodi HTTP le classiche operazioni Create, Read, Update e Delete, da applicare alle risorse
Associare ai metodi HTTP le classiche operazioni Create, Read, Update e Delete, da applicare alle risorse
Link copiato negli appunti

Finora abbiamo esaminato l'accesso in lettura ad una singola risorsa o ad un elenco di risorse del nostro glossario. Seguendo i principi dell'architettura REST, l'accesso in lettura alle risorse è associato al metodo HTTP GET. Spesso però è necessario prevedere un accesso anche in scrittura per poter creare, modificare o eliminare risorse. Si tratta in sostanza di implementare le classiche operazioni CRUD: Create, Read, Update, Delete.

L'approccio REST prevede che queste quattro operazioni corrispondano rispettivamente ai quattro metodi principali del protocollo HTTP, come riepilogato dalla seguente tabella:

Metodo HTTP Operazione Schema URI risorsa
POST Create /api/items
GET Read /api/items?category=XXX
/api/items/XXX
PUT Update /api/items/XXX
DELETE Delete /api/items/XXX

A ciascuna operazione abbiamo associato lo schema di URI della risorsa su cui andremo ad applicarla.

Inserimento: POST

Vediamo ora come integrare il nostro progetto con le operazioni mancanti. Partiamo dall'operazione di inserimento di una nuova definizione nel glossario che, in base alla tabella precedente, corrisponde all'invio da parte del cliente di una richiesta con metodo POST verso l'URI /api/items.

Seguendo la convenzione illustrata prima, la gestione di questa richiesta viene implementata creando un metodo per la classe ItemsController il cui nome inizia con Post:

public HttpResponseMessage PostItem(Item myItem)
{
	HttpResponseMessage response;
	string uri;
	items.Add(myItem);
	response = Request.CreateResponse(HttpStatusCode.Created, myItem);
	uri = Url.Link("DefaultApi", new { id = myItem.term });
	response.Headers.Location = new Uri(uri);
	return response;
}

Analizziamo il codice per comprenderne il funzionamento. Innanziatutto notiamo che il metodo restituisce un oggetto di tipo HttpResponseMessage. Avremmo potuto far restituire un oggetto di tipo Item ma questa soluzione, seppur funzionante, avrebbe violato due regole delle linee guida REST:

  • l'invio del codice di stato 201 (Created)
  • l'indicazione dell'URI della nuova risorsa appena creata

Infatti, senza nessun particolare accorgimento il framework avrebbe inviato automaticamente una risposta con codice di stato 200 (OK) e la risorsa serializzata nel corpo della risposta. Il nostro codice invece, dopo aver aggiunto la nuova risorsa nella lista interna, crea una risposta contenente la risorsa serializzata ed il codice di stato corretto (HttpStatusCode.Created). Aggiunge poi l'URI della risorsa appena creata tra le intestazioni HTTP della risposta.

Richiamiamo ancora una volta l'attenzione sullo scopo didattico dell'esempio e facciamo notare come l'aggiunta di una nuova risorsa alla lista interna non ha praticamente nessun effetto tangibile. In altre parole, dal momento che ciascuna richiesta all'API è stateless, cioè non vi è alcun mantenimento di stato tra una richiesta HTTP e la successiva, ad ogni nuova richiesta sarà ricreata la lista delle definizioni, perdendo di fatto eventuali aggiunte e/o modifiche.

Come accennato in precedenza, nei casi reali la lista andrebbe memorizzata su un database.

Modifica: PUT

La modifica di una definzione del glossario corrisponde all'esecuzione del metodo PUT su un URI della forma /api/items/xxx, dove xxx rappresenta il termine da modificare.

Seguendo la convenzione predefinita, in questo caso creeremo un metodo per la classe ItemsController il cui nome inizia con "Put":

public void PutItem(string id, Item myItem)
{
	int i;
	i = items.FindIndex(p => p.term == myItem.term);
	if (i != -1)
	{
		items[i] = myItem;
	}
	else
	{
		throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.NotFound));
	}
}

Il metodo riceve come parametri l'identificatore della risorsa, che nel nostro caso corrisponde al termine della voce del glossario, e la risorsa modificata dal client. Si assicura quindi che la risorsa esista nella lista delle definizioni e in caso positivo la sotituisce con quella fornita dal client.

Se la risorsa non esiste invia al client una risposta HTTP con codice di stato 404, Not Found.

Da notare che, sebbene non venga inviato esplicitamente alcun codice di stato in caso di successo della modifica, il framework si occupa di comunicare automaticamente al client il codice di stato 200, OK.

Cancellazione: DELETE

Infine, per quanto riguarda l'eliminazione di una voce dal nostro glossario, dobbiamo gestire il metodo DELETE su un URI della forma /api/items/xxx, dove xxx rappresenta il termine da eliminare.

Implementiamo pertanto un metodo il cui nome inizia con "Delete":

public HttpResponseMessage DeleteItem(string id)
{
	int i;
	i = items.FindIndex(p => p.term == id);
	if (i != -1)
	{
		items.RemoveAt(i);
	}
	return new HttpResponseMessage(HttpStatusCode.NoContent);
}

Il metodo verifica se la risorsa esiste ed in caso positivo rimuove la voce dalla lista. Il codice di stato restituito è in ogni caso 204 (No Content) scelta motivata dal fatto di attenersi alle specifiche HTTP che prevedono che il metodo DELETE sia idempotente, cioè che abbia lo stesso effetto anche se viene eseguito più volte. Questo vuol dire, in termini pratici, che il client non ha nessuna segnalazione in caso di eliminazione di una risorsa già eliminata in precedenza.

Sempre secondo le specifiche HTTP, il metodo DELETE può prevedere una risposta con codice di stato 200 (OK) o 204 (Non Content) oppure 202 (Accepted). Mentre i primi due casi possono essere considerati equivalenti, il terzo caso andrebbe applicato quando la richiesta viene accettata dal server ma non immediatamente eseguita, ad esempio quando la richiesta viene inserita in una coda di elaborazione batch.

Ti consigliamo anche