Métodos padrão

Este capítulo define o conceito de métodos padrão, que são List, Get, Create, Update e Delete. Os métodos padrão reduzem a complexidade e aumentam a consistência. Mais de 70% dos métodos da API no repositório de APIs do Google são métodos padrão, o que os torna muito mais fáceis de aprender e usar.

Na tabela a seguir descrevemos como mapear métodos padrão para métodos HTTP:

Método padrão Mapeamento de HTTP Corpo de solicitação HTTP Corpo de resposta HTTP
List GET <collection URL> N/A Lista de recursos*
Get GET <resource URL> N/A Recurso*
Create POST <collection URL> Recurso Recurso*
Update PUT or PATCH <resource URL> Recurso Recurso*
Delete DELETE <resource URL> N/A google.protobuf.Empty**

*O recurso retornado dos métodos List, Get, Create e Update pode conter dados parciais se os métodos suportarem máscaras de campo de resposta, que especificam um subconjunto de campos a serem retornados. Em alguns casos, a plataforma da API é compatível de modo nativo com máscaras de campo para todos os métodos.

**A resposta retornada de um método Delete que não remove imediatamente o recurso (como atualizar uma sinalização ou criar uma operação de exclusão de longa duração) precisa conter a operação de longa duração ou o recurso modificado.

Em um método padrão, uma operação de longa duração também pode ser retornada para solicitações que não se completem no intervalo de tempo de uma única chamada da API.

Nas seções a seguir, descrevemos cada um dos métodos padrão em detalhes. Os exemplos mostram os métodos definidos em arquivos .proto com anotações especiais para os mapeamentos HTTP. Você pode encontrar muitos exemplos de uso de métodos padrão no repositório das APIs do Google.

List

O método List usa um nome de coleção e zero ou mais parâmetros como entrada e retorna uma lista de recursos que correspondem à entrada.

List é comumente usado para pesquisar recursos. List é adequado para dados de uma única coleção limitada em tamanho e não em cache. Para casos mais amplos, o método personalizado Search precisa ser usado.

Um lote de get (como um método que usa vários IDs de recurso e retorna um objeto para cada um desses IDs) precisa ser implementado como um método BatchGet personalizado em vez de um List. No entanto, se você tiver um método List já existente que fornece a mesma funcionalidade, você pode reutilizar o método List para essa finalidade. Se você estiver usando um método BatchGet personalizado, ele precisa ser mapeado para HTTP GET.

Padrões comuns aplicáveis: paginação e ordenação de resultados.

Convenções de nomenclatura aplicáveis: campo de filtro e campo de resultados.

Mapeamento do HTTP:

  • O método List deve usar um verbo GET.
  • Os campos da mensagem de solicitação que recebem o nome do conjunto cujos recursos estão sendo listados devem mapear para o caminho do URL. Se o nome do conjunto é mapeado para o caminho do URL, o último segmento do modelo de URL (o IDdo conjunto) precisa ser literal.
  • Todos os campos restantes da mensagem de solicitação deverão ser mapeados para os parâmetros de consulta do URL.
  • Não há corpo de solicitação. Portanto, a configuração da API não pode declarar uma cláusula body.
  • O corpo de resposta deve conter uma lista de recursos junto com metadados opcionais.

Exemplo:

// 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

O método Get usa um nome de recurso, zero ou mais parâmetros e retorna o recurso especificado.

Mapeamento do HTTP:

  • O método Get deve usar um verbo GET.
  • Os campos da mensagem de solicitação que recebem o nome do recurso precisam mapear para o caminho do URL.
  • Todos os campos restantes da mensagem de solicitação deverão ser mapeados para os parâmetros de consulta do URL.
  • Não há corpo de solicitação. Portanto, a configuração da API não pode declarar uma cláusula body.
  • O recurso retornado deverá mapear para todo o corpo de resposta.

Exemplo:

// 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;
}

Criar

O método Create usa um nome de recurso pai, um recurso e zero ou mais parâmetros. Ele cria um novo recurso no recurso pai especificado e retorna o recurso recém-criado.

Se uma API for compatível com a criação de recursos, ela precisa ter um método Create para cada tipo de recurso que possa ser criado.

Mapeamento do HTTP:

  • O método Create deve usar um verbo POST.
  • A mensagem de solicitação precisa ter um campo parent que especifique o nome do recurso pai no qual o recurso precisa ser criado.
  • O campo de mensagem de solicitação que contém o recurso precisa mapear para o corpo de solicitação. Se a anotação google.api.http for usada para o método Create, o formulário body: "<resource_field>" precisará ser usado.
  • A solicitação pode conter um campo chamado <resource>_id para permitir que os autores da chamada selecionem um ID atribuído pelo cliente. Este campo pode estar dentro do recurso.
  • Todos os campos restantes da mensagem de solicitação deverão ser mapeados para os parâmetros de consulta do URL.
  • O recurso retornado deverá mapear para todo o corpo de resposta.

Se o método Create for compatível com o nome do recurso atribuído pelo cliente e o recurso já existir, a solicitação precisará falhar com o código de erro ALREADY_EXISTS ou usar um nome de recurso diferente atribuído pelo servidor e a documentação deve deixar claro que o nome do recurso criado pode ser diferente do passado.

O método Create precisa receber um recurso de entrada para que, quando o esquema do recurso for alterado, não haja necessidade de atualizar o esquema de solicitação e de recurso. Os campos de recursos que não podem ser configurados pelos clientes precisam ser documentados como campos "Somente de saída".

Exemplo:

// 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;
}

Update

O método Update recebe uma mensagem de solicitação contendo um recurso e zero ou mais parâmetros. Ele atualiza o recurso especificado e as respectivas propriedades e retorna o recurso atualizado.

As propriedades mutáveis do recurso precisam ser alteradas pelo método Update, exceto as propriedades que contenham o nome ou pai do recurso. Qualquer funcionalidade para renomear ou mover um recurso não pode acontecer no método Update e, em vez disso, precisa ser manipulados por um método personalizado.

Mapeamento do HTTP:

  • O método Update padrão precisa aceitar a atualização parcial de recursos e usar o verbo HTTP PATCH com um campo FieldMask chamado update_mask. Campos de saída que são fornecidos pelo cliente como entradas precisam ser ignorados.
  • Um método Update que requer uma semântica de patch mais avançada, como anexar a um campo repetido, precisa ser disponibilizado por um método personalizado.
  • Se o método Update for compatível apenas com a atualização completa de recursos, ele precisa usar o verbo HTTP PUT. No entanto, a atualização completa não é recomendada, porque ela tem problemas de compatibilidade com versões anteriores ao adicionar novos campos de recurso.
  • O campo de mensagem que recebe o nome do recurso precisa mapear para o caminho do URL. O campo pode estar na própria mensagem do recurso.
  • O campo de mensagem de solicitação que contém o recurso precisa mapear para o corpo de solicitação.
  • Todos os campos restantes da mensagem de solicitação precisam ser mapeados para os parâmetros da consulta do URL.
  • A mensagem de resposta precisa ser o próprio recurso atualizado.

Se a API aceitar nomes de recurso atribuídos pelo cliente, o servidor pode permitir que o cliente especifique um nome de recurso inexistente e crie um novo recurso. Caso contrário, o método Update deverá falhar com um nome de recurso não existente. O código de erro NOT_FOUND precisa ser usado se ele for a única condição de erro.

Uma API com um método Update compatível com a criação de recursos também precisa fornecer um método Create. O motivo é que não está claro como criar recursos se o método Update for a única maneira de fazer isso.

Exemplo:

// 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;
}

Excluir

O método Delete usa um nome de recurso e nenhum ou mais parâmetros, além de exclusões ou agendamentos para exclusão do recurso especificado. O método Delete deve retornar google.protobuf.Empty.

Uma API não pode depender de nenhuma informação retornada por um método Delete, pois ela não pode ser invocada repetidamente.

Mapeamento do HTTP:

  • O método Delete deve usar um verbo DELETE.
  • Os campos da mensagem de solicitação que recebem o nome do recurso precisam mapear para o caminho do URL.
  • Todos os campos restantes da mensagem de solicitação precisarão ser mapeados para os parâmetros de consulta do URL.
  • Não há corpo de solicitação. Portanto, a configuração da API não pode declarar uma cláusula body.
  • Se o método Delete remover imediatamente o recurso, ele precisará retornar uma resposta vazia.
  • Se o método Delete inicia uma operação de longa duração, ele precisará retornar a operação de longa duração.
  • Se o método Delete marcar apenas o recurso como excluído, ele precisará retornar o recurso atualizado.

As chamadas para o método Delete precisam ser idempotentes e não precisam gerar a mesma resposta. Qualquer número de solicitações Delete precisa resultar na exclusão de um recurso, mas somente a primeira solicitação deve resultar em um código de sucesso. As solicitações subsequentes precisam resultar em um google.rpc.Code.NOT_FOUND.

Exemplo:

// 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;
}