En este capítulo se define el concepto de métodos estándares, que son List
, Get
, Create
, Update
y Delete
. Los métodos estándar reducen la complejidad y aumentan la coherencia. Más del 70% de los métodos de API en el repositorio de las API de Google son métodos estándar, lo que los hace mucho más fáciles de aprender y usar.
En la siguiente tabla, se describe cómo asignar métodos estándar a métodos HTTP:
Método estándar | Asignación HTTP | Cuerpo de la solicitud HTTP | Cuerpo de la respuesta HTTP |
---|---|---|---|
List |
GET <collection URL> |
No disponible | Lista de recursos* |
Get |
GET <resource URL> |
No disponible | Recurso* |
Create |
POST <collection URL> |
Recurso | Recurso* |
Update |
PUT or PATCH <resource URL> |
Recurso | Recurso* |
Delete |
DELETE <resource URL> |
N/A | google.protobuf.Empty ** |
*El recurso que muestran los métodos List
, Get
, Create
y Update
puede contener datos parciales si los métodos son compatibles con máscaras de campo de respuesta, que especifican un subconjunto de campos para mostrar.
En algunos casos, la plataforma de API admite de forma nativa las máscaras de campo para todos los métodos.
**La respuesta que muestra un método Delete
que no quita el recurso de forma inmediata (como actualizar una marca o crear una operación de borrado de larga duración) debe contener la operación de larga duración o el recurso modificado.
Un método estándar también puede mostrar una operación de larga duración para solicitudes que no se completan dentro del período de la única llamada a la API.
En las siguientes secciones, se describen cada uno de los métodos estándar en detalle. Los ejemplos muestran los métodos definidos en archivos .proto con anotaciones especiales para las asignaciones HTTP. Puedes encontrar muchos ejemplos que usan métodos estándar en el repositorio de API de Google.
Enumerar
El método List
toma un nombre de colección y cero o más parámetros como entrada, y muestra una lista de recursos que coinciden con la entrada.
Por lo general, List
se usa para buscar recursos. List
es adecuada para datos de una sola colección con límite de tamaño que no está almacenada en caché. Para casos más amplios, debe usarse el método personalizado Search
.
Un get por lotes (como un método que toma varios ID de recursos y muestra un objeto por cada uno de esos ID) debe implementarse como un método BatchGet
personalizado, en lugar de un List
. Sin embargo, si tienes un método List
ya existente que proporciona la misma funcionalidad, puedes volver a usar el método List
para este fin. Si usas un método BatchGet
personalizado, debe asignarse a HTTP GET
.
Patrones comunes aplicables: paginación, ordenamiento de resultados.
Convenciones de nomenclatura aplicables: campo de filtro, campo de resultados
Asignación HTTP:
- El método
List
debe usar un verbo HTTPGET
. - Los campos del mensaje de solicitud que reciben el nombre de la colección cuyos recursos se enumeran deben asignarse a la ruta de la URL. Si el nombre de la colección se asigna a la ruta de URL, el último segmento de la plantilla URL (el ID de colección) debe ser literal.
- Todos los campos de mensaje de solicitud restantes se asignarán a los parámetros de consulta de URL.
- No hay cuerpo de solicitud; la configuración de la API no debe declarar una cláusula
body
. - El cuerpo de la respuesta debe contener una lista de recursos junto con metadatos opcionales.
Ejemplo:
// 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
El método Get
toma un nombre de recurso, cero o más parámetros, y muestra el recurso especificado.
Asignación HTTP:
- El método
Get
debe usar un verbo HTTPGET
. - Los campos de mensaje de solicitud que reciben el nombre del recurso deben asignarse a la ruta de URL.
- Todos los campos de mensaje de solicitud restantes se asignarán a los parámetros de consulta de URL.
- No hay cuerpo de solicitud; la configuración de la API no debe declarar una cláusula
body
. - El recurso mostrado se asignará a todo el cuerpo de la respuesta.
Ejemplo:
// 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;
}
Crear
El método Create
toma un nombre de recurso superior, un recurso y cero o más parámetros. Crea un nuevo recurso bajo el superior especificado y lo muestra.
Si una API admite la creación de recursos, debe tener un método Create
para cada tipo de recurso que se pueda crear.
Asignación HTTP:
- El método
Create
debe usar un verbo HTTPPOST
. - El mensaje de solicitud debe tener un campo
parent
que especifique el nombre del recurso superior donde se creará el recurso nuevo. - El campo de mensaje de solicitud que contiene el recurso debe asignarse al cuerpo de la solicitud HTTP. Si se usa la anotación
google.api.http
para el métodoCreate
, se debe usar el formulariobody: "<resource_field>"
. - La solicitud puede contener un campo llamado
<resource>_id
para permitir que los emisores seleccionen un ID asignado por el cliente. Este campo puede estar dentro del recurso. - Todos los campos de mensaje de solicitud restantes se asignarán a los parámetros de consulta de URL.
- El recurso mostrado se asignará a todo el cuerpo de la respuesta HTTP.
Si el método Create
admite el nombre de recurso asignado por el cliente y el recurso ya existe, la solicitud debe fallar con el código de error ALREADY_EXISTS
o usar otro nombre de recurso asignado por el servidor, y la documentación debe aclarar que el nombre del recurso creado puede ser diferente del que se pasó.
El método Create
debe tomar un recurso de entrada para que, cuando se modifique el esquema de recursos, no sea necesario actualizar el esquema de solicitudes y el esquema de recursos. Los campos de recursos que los clientes no pueden configurar deben documentarse como campos “Solo de salida”.
Ejemplo:
// 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;
}
Actualizar
El método Update
toma un mensaje de solicitud que contiene un recurso y cero o más parámetros. Actualiza el recurso especificado y sus propiedades, y luego lo muestra.
Las propiedades de recursos mutables deben poder mutarse con el método Update
, excepto las propiedades que contienen el nombre o el superior del recurso. Cualquier funcionalidad para renombrar o mover un recurso no debe ocurrir en el método Update
y, en su lugar, se manejará mediante un método personalizado.
Asignación HTTP:
- El método
Update
estándar debería admitir la actualización parcial de recursos y usar el verbo HTTPPATCH
con un campoFieldMask
llamadoupdate_mask
. Los campos de salida que proporcione el cliente como entradas deben ignorarse. - Un método
Update
que requiera una semántica de parches más avanzada, como adjuntar a un campo repetido, debe estar disponible mediante un método personalizado. - Si el método
Update
solo admite la actualización completa de recursos, debe usar el verbo HTTPPUT
. Sin embargo, no se recomienda la actualización completa, ya que tiene problemas de retrocompatibilidad cuando se agregan nuevos campos de recursos. - El campo de mensaje que recibe el nombre del recurso debe asignarse a la ruta de URL. El campo puede encontrarse en el propio mensaje de recursos.
- El campo de mensaje de solicitud que contiene el recurso debe asignarse al cuerpo de la solicitud.
- Todos los campos de mensaje de solicitud restantes deben asignarse a los parámetros de consulta de URL.
- El mensaje de respuesta debe ser el propio recurso actualizado.
Si la API acepta nombres de recursos asignados por el cliente, el servidor puede permitir que el cliente especifique un nombre de recurso inexistente y cree un nuevo recurso.
De lo contrario, el método Update
debe fallar con un nombre de recurso inexistente.
Sedebe usar el código de error NOT_FOUND
si es la única condición de error.
Una API con un método Update
que admita la creación de recursos también debe proporcionar un método Create
. La razón es que no queda claro cómo crear recursos si el método Update
es la única manera de hacerlo.
Ejemplo:
// 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;
}
Borrar
El método Delete
toma un nombre de recurso y cero o más parámetros, y borra o programa la eliminación del recurso especificado.
El método Delete
debe mostrar google.protobuf.Empty
.
Una API no debe basarse en la información que muestra un método Delete
, ya que no se puede invocar de manera reiterada.
Asignación HTTP:
- El método
Delete
debe usar un verbo HTTPDELETE
. - Los campos de mensaje de solicitud que reciben el nombre del recurso deben asignarse a la ruta de URL.
- Todos los campos de mensaje de solicitud restantes se asignarán a los parámetros de consulta de URL.
- No hay cuerpo de solicitud; la configuración de la API no debe declarar una cláusula
body
. - Si el método
Delete
quita el recurso de inmediato, debe mostrar una respuesta vacía. - Si el método
Delete
inicia una operación de larga duración, debe mostrarla. - Si el método
Delete
solo marca el recurso como borrado, debe mostrar el recurso actualizado.
Las llamadas al método Delete
deben ser idempotentes en efecto, pero no es necesario que brinden la misma respuesta. Cualquier cantidad de solicitudes Delete
debe dar como resultado que un recurso se borre (en algún momento), pero solo la primera solicitud debe dar como resultado un código de éxito. Las solicitudes posteriores deben dar como resultado una google.rpc.Code.NOT_FOUND
.
Ejemplo:
// 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;
}