Metodi standard

Questo capitolo definisce il concetto di metodi standard, ovvero List, Get, Create, Update e Delete. I metodi standard riducono la complessità e aumentano la coerenza. Oltre il 70% dei metodi API nel repository delle API di Google sono standard, il che li rende molto più facili da imparare e utilizzare.

La tabella seguente descrive come mappare i metodi standard ai metodi HTTP:

Metodo standard Mappatura HTTP Corpo della richiesta HTTP Corpo risposta HTTP
List GET <collection URL> N/A Elenco delle risorse*
Get GET <resource URL> N/A Risorsa*
Create POST <collection URL> Risorsa Risorsa*
Update PUT or PATCH <resource URL> Risorsa Risorsa*
Delete DELETE <resource URL> N/A google.protobuf.Empty**

*La risorsa restituita dai metodi List, Get, Create e Update potrebbe contenere dati parziali se i metodi supportano le maschere dei campi di risposta, che specificano un sottoinsieme di campi da restituire. In alcuni casi, la piattaforma API supporta in modo nativo le maschere di campo per tutti i metodi.

**La risposta restituita da un metodo Delete che non rimuove immediatamente la risorsa (ad esempio l'aggiornamento di un flag o la creazione di un'operazione di eliminazione a lunga esecuzione) deve contenere l'operazione a lunga esecuzione o la risorsa modificata.

Un metodo standard può restituire anche un'operazione a lunga esecuzione per le richieste che non vengono completate nell'intervallo di tempo della singola chiamata API.

Le seguenti sezioni descrivono in dettaglio ogni metodo standard. Gli esempi mostrano i metodi definiti nei file .proto con annotazioni speciali per le mappature HTTP. Puoi trovare molti esempi che utilizzano i metodi standard nel repository delle API di Google.

Elenco

Il metodo List prende il nome della raccolta e zero o più parametri come input e restituisce un elenco di risorse che corrispondono all'input.

List è comunemente utilizzato per cercare risorse. List è adatto ai dati di una singola raccolta con dimensioni limitate e non memorizzata nella cache. Per casi più generici, dovrebbe utilizzare il metodo personalizzato Search.

Un recupero batch (ad esempio un metodo che accetta più ID risorsa e restituisce un oggetto per ciascuno di questi ID) deve essere implementato come metodo BatchGet personalizzato anziché come List. Tuttavia, se hai già un metodo List che offre la stessa funzionalità, puoi riutilizzare il metodo List per questo scopo. Se utilizzi un metodo BatchGet personalizzato, questo dovrebbe essere mappato a HTTP GET.

Pattern comuni applicabili: paginazione, ordinamento dei risultati.

Convenzioni di denominazione applicabili: campo filtro, campo risultati

Mappatura HTTP:

  • Il metodo List deve utilizzare un verbo HTTP GET.
  • I campi del messaggio di richiesta che ricevono il nome della raccolta le cui risorse sono elencate devono essere mappati al percorso dell'URL. Se il nome della raccolta viene mappato al percorso dell'URL, l'ultimo segmento del modello di URL (l'ID raccolta) deve essere letterale.
  • Tutti i restanti campi del messaggio di richiesta saranno mappati ai parametri di ricerca dell'URL.
  • Non esiste un corpo della richiesta; la configurazione API non deve dichiarare una clausola body.
  • Il corpo della risposta deve contenere un elenco di risorse insieme a metadati facoltativi.

Esempio:

// Lists books in a shelf.
rpc ListBooks(ListBooksRequest) returns (ListBooksResponse) {
  // List method maps to HTTP GET.
  option (google.api.http) = {
    // The `parent` captures the parent resource name, such as "shelves/shelf1".
    get: "/v1/{parent=shelves/*}/books"
  };
}

message ListBooksRequest {
  // The parent resource name, for example, "shelves/shelf1".
  string parent = 1;

  // The maximum number of items to return.
  int32 page_size = 2;

  // The next_page_token value returned from a previous List request, if any.
  string page_token = 3;
}

message ListBooksResponse {
  // The field name should match the noun "books" in the method name.  There
  // will be a maximum number of items returned based on the page_size field
  // in the request.
  repeated Book books = 1;

  // Token to retrieve the next page of results, or empty if there are no
  // more results in the list.
  string next_page_token = 2;
}

Get

Il metodo Get prende un nome di risorsa, zero o più parametri e restituisce la risorsa specificata.

Mappatura HTTP:

  • Il metodo Get deve utilizzare un verbo HTTP GET.
  • I campi del messaggio di richiesta che ricevono il nome della risorsa devono essere mappati al percorso dell'URL.
  • Tutti i restanti campi del messaggio di richiesta saranno mappati ai parametri di ricerca dell'URL.
  • Non esiste un corpo della richiesta; la configurazione API non deve dichiarare una clausola body.
  • La risorsa restituita deve essere mappata all'intero corpo della risposta.

Esempio:

// Gets a book.
rpc GetBook(GetBookRequest) returns (Book) {
  // Get maps to HTTP GET. Resource name is mapped to the URL. No body.
  option (google.api.http) = {
    // Note the URL template variable which captures the multi-segment resource
    // name of the requested book, such as "shelves/shelf1/books/book2"
    get: "/v1/{name=shelves/*/books/*}"
  };
}

message GetBookRequest {
  // The field will contain name of the resource requested, for example:
  // "shelves/shelf1/books/book2"
  string name = 1;
}

Crea

Il metodo Create utilizza un nome risorsa padre, una risorsa e zero o più parametri. Crea una nuova risorsa sotto l'elemento padre specificato e restituisce la risorsa appena creata.

Se un'API supporta la creazione di risorse, deve avere un metodo Create per ogni tipo di risorsa creabile.

Mappatura HTTP:

  • Il metodo Create deve utilizzare un verbo HTTP POST.
  • Il messaggio di richiesta deve contenere un campo parent che specifica il nome della risorsa padre in cui deve essere creata la risorsa.
  • Il campo del messaggio della richiesta contenente la risorsa deve essere mappato al corpo della richiesta HTTP. Se per il metodo Create viene utilizzata l'annotazione google.api.http, deve essere usato il modulo body: "<resource_field>".
  • La richiesta può contenere un campo denominato <resource>_id per consentire ai chiamanti di selezionare un ID assegnato dal client. Questo campo potrebbe trovarsi all'interno della risorsa.
  • Tutti i restanti campi del messaggio di richiesta saranno mappati ai parametri di query dell'URL.
  • La risorsa restituita deve essere mappata all'intero corpo della risposta HTTP.

Se il metodo Create supporta il nome della risorsa assegnato dal client e la risorsa esiste già, la richiesta dovrebbe avere esito negativo con codice di errore ALREADY_EXISTS o utilizzare un nome di risorsa assegnato dal server diverso e la documentazione deve indicare chiaramente che il nome della risorsa creata potrebbe essere diverso da quello trasmesso.

Il metodo Create deve prendere una risorsa di input in modo che, quando lo schema della risorsa cambia, non sia necessario aggiornare sia lo schema delle richieste sia lo schema delle risorse. Per i campi delle risorse che non possono essere impostati dai client, devono essere documentati come campi "Solo output".

Esempio:

// Creates a book in a shelf.
rpc CreateBook(CreateBookRequest) returns (Book) {
  // Create maps to HTTP POST. URL path as the collection name.
  // HTTP request body contains the resource.
  option (google.api.http) = {
    // The `parent` captures the parent resource name, such as "shelves/1".
    post: "/v1/{parent=shelves/*}/books"
    body: "book"
  };
}

message CreateBookRequest {
  // The parent resource name where the book is to be created.
  string parent = 1;

  // The book id to use for this book.
  string book_id = 3;

  // The book resource to create.
  // The field name should match the Noun in the method name.
  Book book = 2;
}

rpc CreateShelf(CreateShelfRequest) returns (Shelf) {
  option (google.api.http) = {
    post: "/v1/shelves"
    body: "shelf"
  };
}

message CreateShelfRequest {
  Shelf shelf = 1;
}

Aggiorna

Il metodo Update accetta un messaggio di richiesta contenente una risorsa e zero o più parametri. Aggiorna la risorsa specificata e le sue proprietà e restituisce la risorsa aggiornata.

Le proprietà delle risorse modificabili devono essere modificabili dal metodo Update, ad eccezione delle proprietà che contengono il nome o l'elemento padre della risorsa. Qualsiasi funzionalità per rinominare o spostare una risorsa non deve avvenire nel metodo Update e dovrà essere gestita da un metodo personalizzato.

Mappatura HTTP:

  • Il metodo Update standard deve supportare l'aggiornamento parziale delle risorse e utilizzare il verbo HTTP PATCH con un campo FieldMask denominato update_mask. I campi di output forniti dal client come input devono essere ignorati.
  • Un metodo Update che richiede una semantica di applicazione patch più avanzata, ad esempio l'aggiunta a un campo ripetuto, deve essere reso disponibile con un metodo personalizzato.
  • Se il metodo Update supporta solo l'aggiornamento completo delle risorse, deve utilizzare il verbo HTTP PUT. Tuttavia, l'aggiornamento completo è sconsigliato perché presenta problemi di compatibilità con le versioni precedenti durante l'aggiunta di nuovi campi delle risorse.
  • Il campo del messaggio che riceve il nome della risorsa deve essere mappato al percorso dell'URL. Il campo potrebbe essere presente nel messaggio della risorsa stesso.
  • Il campo del messaggio della richiesta contenente la risorsa deve essere mappato al corpo della richiesta.
  • Tutti i restanti campi del messaggio di richiesta devono essere mappati ai parametri di query dell'URL.
  • Il messaggio di risposta deve corrispondere alla risorsa aggiornata.

Se l'API accetta nomi di risorse assegnati dal client, il server potrebbe consentire al client di specificare un nome di risorsa inesistente e di crearne una nuova. In caso contrario, il metodo Update dovrebbe avere esito negativo con un nome risorsa inesistente. Il codice di errore NOT_FOUND deve essere utilizzato se è l'unica condizione di errore.

Un'API con un metodo Update che supporta la creazione di risorse dovrebbe fornire anche un metodo Create. La motivazione è che non è chiaro come creare risorse se il metodo Update è l'unico modo per farlo.

Esempio:

// Updates a book.
rpc UpdateBook(UpdateBookRequest) returns (Book) {
  // Update maps to HTTP PATCH. Resource name is mapped to a URL path.
  // Resource is contained in the HTTP request body.
  option (google.api.http) = {
    // Note the URL template variable which captures the resource name of the
    // book to update.
    patch: "/v1/{book.name=shelves/*/books/*}"
    body: "book"
  };
}

message UpdateBookRequest {
  // The book resource which replaces the resource on the server.
  Book book = 1;

  // The update mask applies to the resource. For the `FieldMask` definition,
  // see https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#fieldmask
  FieldMask update_mask = 2;
}

Elimina

Il metodo Delete prende un nome di risorsa e zero o più parametri ed elimina o pianifica l'eliminazione della risorsa specificata. Il metodo Delete deve restituire google.protobuf.Empty.

Un'API non deve basarsi su informazioni restituite da un metodo Delete, poiché non può essere richiamata ripetutamente.

Mappatura HTTP:

  • Il metodo Delete deve utilizzare un verbo HTTP DELETE.
  • I campi del messaggio di richiesta che ricevono il nome della risorsa devono essere mappati al percorso dell'URL.
  • Tutti i restanti campi del messaggio di richiesta saranno mappati ai parametri query dell'URL.
  • Non esiste un corpo della richiesta; la configurazione API non deve dichiarare una clausola body.
  • Se il metodo Delete rimuove immediatamente la risorsa, dovrebbe restituire una risposta vuota.
  • Se il metodo Delete avvia un'operazione a lunga esecuzione, dovrebbe restituire l'operazione a lunga esecuzione.
  • Se il metodo Delete contrassegna solo la risorsa come eliminata, dovrebbe restituire la risorsa aggiornata.

Le chiamate al metodo Delete dovrebbero essere idempotenti in effetto, ma non devono generare la stessa risposta. Un numero qualsiasi di richieste Delete dovrebbe comportare l'eliminazione di una risorsa, ma solo la prima richiesta dovrebbe comportare un codice di esito positivo. Le richieste successive dovrebbero generare un google.rpc.Code.NOT_FOUND.

Esempio:

// Deletes a book.
rpc DeleteBook(DeleteBookRequest) returns (google.protobuf.Empty) {
  // Delete maps to HTTP DELETE. Resource name maps to the URL path.
  // There is no request body.
  option (google.api.http) = {
    // Note the URL template variable capturing the multi-segment name of the
    // book resource to be deleted, such as "shelves/shelf1/books/book2"
    delete: "/v1/{name=shelves/*/books/*}"
  };
}

message DeleteBookRequest {
  // The resource name of the book to be deleted, for example:
  // "shelves/shelf1/books/book2"
  string name = 1;
}