Erros

Este capítulo fornece uma visão geral do modelo de erro das APIs do Google. Também oferece orientações gerais para os desenvolvedores sobre como gerar e lidar corretamente com erros.

As APIs do Google usam um modelo simples de erro independente de protocolo, que nos permite expor uma experiência consistente em diferentes APIs, protocolos de APIs (como gRPC ou HTTP) e contextos de erro (como assíncrono, lote ou erros do fluxo de trabalho).

Modelo de erro

O modelo de erro é logicamente definido por google.rpc.Status, uma instância da qual é retornada ao cliente quando ocorre um erro de API. O snippet de código a seguir mostra o projeto geral do modelo de erro:

package google.rpc;

message Status {
  // A simple error code that can be easily handled by the client. The
  // actual error code is defined by `google.rpc.Code`.
  int32 code = 1;

  // A developer-facing human-readable error message in English. It should
  // both explain the error and offer an actionable resolution to it.
  string message = 2;

  // Additional error information that the client code can use to handle
  // the error, such as retry delay or a help link.
  repeated google.protobuf.Any details = 3;
}

Como a maioria das APIs do Google usa um design orientado a recursos, o tratamento de erros segue o mesmo princípio do design, usando um pequeno conjunto de erros padrão com uma grande quantidade de recursos. Por exemplo, em vez de definir diferentes tipos de erros "não encontrado", o servidor usa um código de erro google.rpc.Code.NOT_FOUND padrão e informa ao cliente qual recurso específico não foi encontrado. O espaço com estado menor reduz a complexidade da documentação, oferece melhores mapeamentos idiomáticos nas bibliotecas de cliente e reduz a complexidade da lógica do cliente sem restringir a inclusão de informações acionáveis.

Códigos de erro

As APIs do Google precisam usar os códigos de erro canônicos definidos por google.rpc.Code. As APIs individuais precisam evitar a definição de códigos dos erros adicionais, porque é muito improvável que os desenvolvedores escrevam uma lógica para lidar com um grande número de códigos dos erros. Para referência, o tratamento de uma média de três códigos de erro por chamada de API significa que a maior parte da lógica do aplicativo é apenas para o tratamento de erros, o que não é uma boa experiência para o desenvolvedor.

Mensagens de erro

A mensagem de erro deve ajudar os usuários a entender e resolver o erro da API de maneira fácil e rápida. Em geral, considere as diretrizes a seguir ao escrever mensagens de erro:

  • Não presuma que os usuários sejam especialistas na sua API. Eles podem ser desenvolvedores de clientes, pessoal de operações, equipe de TI ou usuários finais de aplicativos.
  • Não presuma que o usuário saiba de tudo sobre a implementação do seu serviço ou esteja familiarizado com o contexto dos erros (como análise de registro).
  • Quando possível, as mensagens de erro precisam ser criadas de maneira que um usuário técnico, não necessariamente um desenvolvedor da sua API, possa responder ao erro e corrigi-lo.
  • Mantenha a mensagem de erro resumida. Se necessário, forneça um link em que um leitor com dúvidas possa fazer perguntas, dar feedback ou obter mais informações que não se encaixam em uma mensagem de erro. Caso contrário, use o campo de detalhes para expandir.

Detalhes do erro

As APIs do Google definem um conjunto de payloads de erro padrão para detalhes de erros, que você pode encontrar em google/rpc/error_details.proto. Eles abrangem as necessidades mais comuns de erros de API, como falha de cota e parâmetros inválidos. Assim como os códigos de erro, os desenvolvedores precisam usar esses payloads padrão sempre que possível.

Os tipos de detalhes de erros adicionais apenas serão introduzidos se puderem ajudar o código do aplicativo a lidar com os erros. Se as informações de erro exigirem intervenção humana, confie no conteúdo da mensagem de erro e deixe os desenvolvedores lidarem com isso manualmente, em vez de introduzir outros tipos de detalhes de erros.

Veja alguns exemplos de payloads error_details:

  • RetryInfo descreve quando os clientes podem repetir uma solicitação com falha. Pode ser retornado em Code.UNAVAILABLE ou Code.ABORTED
  • QuotaFailure Descreve como uma verificação de cota falhou. Pode ser retornado em Code.RESOURCE_EXHAUSTED
  • BadRequest Descreve violações em uma solicitação do cliente. Pode ser retornado em Code.INVALID_ARGUMENT
  • ErrorInfo Fornece informações de erro estruturadas que são estáveis e extensíveis.

ErrorInfo

ErrorInfo é um dos payloads de erro padrão. Ele fornece informações de erro estáveis e extensíveis que podem ser usadas por pessoas e aplicativos. Cada ErrorInfo tem três informações: um domínio de erro, um motivo de erro e um conjunto de metadados de erro. Para mais informações, consulte a definição de ErrorInfo.

Mapeamento de HTTP

Enquanto as mensagens proto3 têm codificação JSON nativa, a plataforma da API do Google usa um esquema de erros diferente para as APIs Google JSON REST por motivos de compatibilidade com versões anteriores.

Esquema:

// The error schema for Google REST APIs. NOTE: this schema is not used for
// other wire protocols.
message Error {
  // This message has the same semantics as `google.rpc.Status`. It has an extra
  // field `status` for backward compatibility with Google API Client Library.
  message Status {
    // This corresponds to `google.rpc.Status.code`.
    int32 code = 1;
    // This corresponds to `google.rpc.Status.message`.
    string message = 2;
    // This is the enum version for `google.rpc.Status.code`.
    google.rpc.Code status = 4;
    // This corresponds to `google.rpc.Status.details`.
    repeated google.protobuf.Any details = 5;
  }
  // The actual error payload. The nested message structure is for backward
  // compatibility with Google API client libraries. It also makes the error
  // more readable to developers.
  Status error = 1;
}

Por exemplo:

{
  "error": {
    "code": 401,
    "message": "Request had invalid credentials.",
    "status": "UNAUTHENTICATED",
    "details": [{
      "@type": "type.googleapis.com/google.rpc.RetryInfo",
      ...
    }]
  }
}

Mapeamento de RPC

Cada protocolo RPC mapeia o modelo de erro de maneira diferente. Para gRPC, o modelo de erro é compatível de maneira nativa com o código gerado e com a biblioteca de tempo de execução em cada linguagem aceita. Para mais informações, veja a documentação da API do gRPC. Por exemplo, consulte io.grpc.Status do Java gRPC.

Mapeamento da biblioteca de cliente

As bibliotecas de cliente do Google podem exibir erros de modo diferente, conforme a linguagem, para consistência com idiomas estabelecidos. Por exemplo, a biblioteca google-cloud-go retorna um erro que implementa a mesma interface de google.rpc.Status, enquanto google-cloud-java gerará uma exceção.

Localização de erros

O campo message em google.rpc.Status é voltado para desenvolvedores e precisa estar em inglês.

Se for necessária uma mensagem de erro para o usuário, use google.rpc.LocalizedMessage como campo de detalhes. Embora o campo de mensagem em google.rpc.LocalizedMessage possa ser localizado, verifique se o campo de mensagem em google.rpc.Status está em inglês.

Por padrão, o serviço da API precisa usar a localidade do usuário autenticado ou o cabeçalho HTTP Accept-Language para determinar o idioma da localização.

Como lidar com erros

Veja abaixo uma tabela contendo todos os códigos de erro gRPC definidos em google.rpc.Code e uma breve descrição da causa. Para lidar com um erro, você pode verificar a descrição do código de status retornado e modificar a chamada de acordo com ela.

HTTP RPC Descrição
200 OK Sem erro.
400 INVALID_ARGUMENT O cliente especificou um argumento inválido. Verifique a mensagem e os detalhes do erro para mais informações.
400 FAILED_PRECONDITION A solicitação não pode ser executada no estado atual do sistema atual, como excluir um diretório que não está vazio.
400 OUT_OF_RANGE O cliente especificou um intervalo inválido.
401 UNAUTHENTICATED Solicitação não autenticada devido ao token OAuth ausente, inválido ou expirado.
403 PERMISSION_DENIED O cliente não tem permissão suficiente. Isso pode acontecer porque o token OAuth não tem os escopos certos, o cliente não tem permissão ou a API não foi ativada para o projeto do cliente.
404 NOT_FOUND Um recurso especificado não foi encontrado ou a solicitação foi rejeitada por motivos não divulgados, como a listagem de permissões.
409 ABORTED Conflito de simultaneidade, como leitura-modificação-gravação.
409 ALREADY_EXISTS O recurso que um cliente tentou criar já existe.
429 RESOURCE_EXHAUSTED Fora da cota de recursos ou perto de atingir o limite de taxa. O cliente deve procurar detalhes do erro google.rpc.QuotaFailure para mais informações.
499 CANCELLED Solicitação cancelada pelo cliente.
500 DATA_LOSS Perda de dados irrecuperável ou dados corrompidos. O cliente deve comunicar o erro ao usuário.
500 UNKNOWN Erro desconhecido no servidor. Geralmente, um bug do servidor.
500 INTERNAL Erro interno do servidor. Geralmente, um bug do servidor.
501 NOT_IMPLEMENTED Método da API não implementado pelo servidor.
503 UNAVAILABLE Serviço indisponível. Geralmente, o servidor está desativado.
504 DEADLINE_EXCEEDED O prazo de solicitação foi excedido. Isso acontecerá somente se o chamador definir um prazo menor que o prazo padrão do método (ou seja, o prazo solicitado não é suficiente para o servidor processar a solicitação) e a solicitação não for concluída dentro do prazo.

Novas tentativas em caso de erro

Os clientes podem tentar novamente em 503 erros de DESCONTOÁVEIS com retirada exponencial. O atraso mínimo deve ser de um segundo, a menos que seja documentado de outra maneira.

Para erros 429 de RESOURCE_EXHAUSTED, o cliente pode tentar novamente no nível superior com atraso mínimo de 30 segundos. Essas novas tentativas são úteis somente para jobs em execução longa em segundo plano.

Para todos os outros erros, a nova tentativa pode não ser aplicável. Primeiro, verifique se a solicitação é idempotente e veja google.rpc.RetryInfo para orientação.

Propagação de erro

Se o serviço da API depende de outros serviços, não convém propagar precipitadamente os erros desses serviços para os seus clientes. Ao traduzir erros, sugerimos o seguinte:

  • Oculte detalhes de implementação e informações confidenciais.
  • Ajuste a parte responsável pelo erro. Por exemplo, um servidor que recebe um erro INVALID_ARGUMENT de outro serviço deve propagar um INTERNAL para o próprio autor da chamada.

Como gerar erros

Se você é um desenvolvedor de servidores, precisa gerar erros com informações suficientes para ajudar os desenvolvedores de clientes a entender e resolver o problema. Ao mesmo tempo, você precisa estar ciente da segurança e da privacidade dos dados do usuário e evitar a divulgação de informações confidenciais na mensagem e nos detalhes do erro, visto que os erros geralmente são registrados e podem ser acessados por outras pessoas. Por exemplo, uma mensagem de erro como "O endereço IP do cliente não está na lista de permissões 128.0.0.0/8" expõe informações sobre a política do servidor, o que talvez não seja acessível ao usuário.

Para gerar erros adequados, primeiro você precisa estar familiarizado com google.rpc.Code para escolher o código de erro mais adequado para cada condição de erro. Um aplicativo do servidor pode verificar várias condições de erro em paralelo e retornar a primeira.

A tabela a seguir lista cada código do erro e um exemplo de uma boa mensagem.

HTTP RPC Exemplo de mensagem de erro
400 INVALID_ARGUMENT O campo de solicitação xyz é xxx, mas o esperado é [yyy, zzz].
400 FAILED_PRECONDITION O recurso xxx é um diretório que não está vazio, portanto, não pode ser excluído.
400 OUT_OF_RANGE A "idade" do parâmetro está fora do intervalo [0, 125].
401 UNAUTHENTICATED Credenciais de autenticação inválidas.
403 PERMISSION_DENIED Permissão "xxx" negada no recurso "yyy".
404 NOT_FOUND O recurso "xxx" não foi encontrado.
409 ABORTED Não foi possível adquirir o bloqueio no recurso "xxx".
409 ALREADY_EXISTS O recurso "xxx" já existe.
429 RESOURCE_EXHAUSTED Limite de cota "xxx" excedido.
499 CANCELLED Solicitação cancelada pelo cliente.
500 DATA_LOSS Consulte a observação.
500 UNKNOWN Consulte a observação.
500 INTERNAL Consulte a observação.
501 NOT_IMPLEMENTED Método "xxx" não implementado.
503 UNAVAILABLE Consulte a observação.
504 DEADLINE_EXCEEDED Consulte a observação.

O pacote google.rpc define um conjunto de payloads de erro padrão, que são preferenciais aos payloads de erro personalizados. A tabela a seguir lista cada código do erro e o payload padrão correspondente, se aplicável.

HTTP RPC Detalhe de erro recomendado
400 INVALID_ARGUMENT google.rpc.BadRequest
400 FAILED_PRECONDITION google.rpc.PreconditionFailure
400 OUT_OF_RANGE google.rpc.BadRequest
401 UNAUTHENTICATED
403 PERMISSION_DENIED
404 NOT_FOUND google.rpc.ResourceInfo
409 ABORTED
409 ALREADY_EXISTS google.rpc.ResourceInfo
429 RESOURCE_EXHAUSTED google.rpc.QuotaFailure
499 CANCELLED
500 DATA_LOSS
500 UNKNOWN
500 INTERNAL
501 NOT_IMPLEMENTED
503 UNAVAILABLE
504 DEADLINE_EXCEEDED