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 verboGET
. - 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 verboGET
. - 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 verboPOST
. - 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étodoCreate
, o formuláriobody: "<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 HTTPPATCH
com um campoFieldMask
chamadoupdate_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 HTTPPUT
. 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 verboDELETE
. - 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;
}