A chamada funciona em desenvolvimento. Agora está a escrever a parte que corre em produção — o bloco catch. Um erro HTTP de uma API de terceiros, por si só, diz pouco: um código de estado a vermelho e nenhuma resposta óbvia à única pergunta que importa às 3 da manhã — o problema é do meu pedido, da minha chave, do meu plano ou dos servidores deles? E, desses casos, quais devo repetir e quais devo mostrar ao utilizador?
A Lingo.dev responde com estrutura. Todos os erros — de todos os endpoints, síncronos ou assíncronos — regressam no mesmo objeto JSON e com um código de estado tirado de uma única tabela fixa. O código de estado não é um rótulo, é uma instrução: diz-lhe se deve corrigir o pedido, rodar a chave, carregar a conta, abrandar ou repetir. Leia o código e sabe logo o que fazer a seguir. Um único handler de erros, orientado pelo estado, cobre toda a API.
Nesta página
- A estrutura do erro
- Códigos de estado
- Que erros repetir
- 402 vs 429: dois limites diferentes
- Onde aparecem os erros dos jobs assíncronos
A estrutura do erro#
Todas as respostas não 2xx têm o mesmo corpo: um objeto JSON com um único campo message que descreve o que correu mal.
{
"message": "Invalid API key"
}Esse é o contrato inteiro. Não há nenhum invólucro para desembrulhar, nem formatos de erro por endpoint que exijam tratamento especial. Um 400 de /process/localize e um 404 numa pesquisa de job devolvem a mesma estrutura — só mudam o código de estado e o texto de message.
Faça correspondência pelo código de estado, não pelo texto da mensagem
O código de estado HTTP é o sinal estável — baseie nele o seu tratamento de erros. A string message foi escrita para um humano a ler um log; trate-a como uma descrição, não como um código de erro legível por máquina, e não faça correspondência pela formulação exata.
Códigos de estado#
Sete códigos de estado cobrem todas as respostas. Estão agrupados aqui por quem os resolve — porque esse agrupamento também define a sua política de repetição.
Enviou algo que o pedido não consegue satisfazer (corrija o pedido, não repita às cegas):
| Estado | Significado |
|---|---|
400 Bad Request | A validação do pedido falhou — um campo em falta, um idioma inválido, um callbackUrl HTTP (e não HTTPS) ou uma payload malformada. |
401 Unauthorized | O header X-API-Key está em falta ou é inválido. Veja Authentication. |
403 Forbidden | A chave é válida, mas não tem acesso ao recurso pedido. |
404 Not Found | O recurso — um motor, um job, um grupo de jobs — não existe. |
A sua organização atingiu um limite da conta (resolva na faturação):
| Estado | Significado |
|---|---|
402 Payment Required | A organização atingiu o seu limite de crédito. |
429 Too Many Requests | A organização atingiu a sua quota diária de tokens. Atualize o plano para aumentar o limite. |
Algo falhou do nosso lado (transitório — repetir):
| Estado | Significado |
|---|---|
500 Internal Server Error | Uma falha inesperada — um erro de base de dados, ou uma falha na chamada de tradução em todos os modelos configurados no motor. |
Um 401 e um 403 parecem semelhantes, mas não são o mesmo problema: 401 significa que não conseguimos sequer identificar quem fez a chamada; 403 significa que identificámos a chave, mas ela não tem permissão de acesso. A correção para 401 está na própria chave (rode-a ou verifique-a); a correção para 403 está no acesso dessa chave.
Que erros repetir#
A primeira pergunta de um integrador cético sobre qualquer tabela de erros é, normalmente, a que fica por responder: quais destes devo repetir? O agrupamento acima é a resposta.
- 4xx — não repita às cegas. Um
400,401,403ou404descreve uma condição no seu pedido. Repetir exatamente o mesmo pedido produz exatamente o mesmo erro. Corrija o input, a chave ou o ID do recurso e só depois volte a enviar. - 402 e 429 — abrande e depois resolva o limite. Não são erros transitórios ao nível do pedido; o pedido seguinte embate na mesma barreira até o limite subjacente mudar. Pare de repetir num loop apertado, exponha o limite e resolva-o (carregue a conta ou atualize o plano).
- 500 — repita com backoff. Esta é a única classe genuinamente transitória. Um
500pode significar que todos os modelos configurados entraram em timeout nessa chamada; uma nova tentativa pode calhar num modelo saudável. Use backoff exponencial e um limite máximo de tentativas.
A API assíncrona reporta resultados de forma diferente
Esta política de repetição aplica-se a chamadas síncronas feitas por si. A API de localização assíncrona não lhe devolve um código de estado para o resultado do trabalho: um POST devolve 202 assim que o pedido é aceite, e cada idioma de destino corre como um job independente através de workflows de fundo duráveis. Em vez de apanhar um código de estado na chamada original, consulta o job ou recebe um webhook com o resultado. Veja onde aparecem os erros dos jobs assíncronos.
402 vs 429: dois limites diferentes#
Os dois códigos ao nível da conta parecem semelhantes — ambos soam a "ficou sem" — e confundi-los leva um programador à correção errada. São limites distintos, com resoluções distintas:
402 Payment Required— a organização atingiu o seu limite de crédito. Isto é um limite de faturação. A chamada seguinte continuará a falhar até o estado de faturação da sua organização mudar.429 Too Many Requests— a organização atingiu a sua quota diária de tokens. Este é um teto de consumo que é reposto e que pode ser aumentado ao atualizar o plano.
A razão para os manter separados no seu handler: um 402 exige uma ação de faturação tomada por uma pessoa; um 429 é uma quota que ou espera que seja reposta ou aumenta com um upgrade de plano. Encaminhar ambos para uma mensagem genérica de "problema de pagamento" esconde, na prática, qual é a alavanca que o operador precisa mesmo de acionar.
O corpo de um 402 é igual ao de qualquer outro erro — é o código de estado que lhe diz que se trata de um limite de crédito:
{
"message": "Organization has reached its credit limit"
}Onde aparecem os erros dos jobs assíncronos#
Vale a pena traçar aqui uma linha, porque é precisamente aqui que um handler de códigos de estado deixa de ser a ferramenta certa.
Os códigos de estado desta página são ao nível do transporte: descrevem se a API aceitou e conseguiu servir o seu pedido HTTP. Um 202 da API assíncrona significa que o seu pedido foi aceite — não que a tradução tenha sido bem-sucedida. Um job assíncrono pode ser aceite sem problemas e ainda assim falhar mais tarde, quando um modelo entra em timeout a meio da execução. Essa falha não surge como código de estado HTTP na chamada original; fica registada no próprio job.
Por isso, as falhas assíncronas aparecem em três sítios, e nenhum deles é esta tabela:
- Estado por job. Um idioma com falha inclui
status: "failed"e umerrorMessageno job. Veja job statuses. - Estado do grupo. Quando alguns idiomas são concluídos com sucesso e outros falham, o grupo reporta
partial— os idiomas concluídos com sucesso seguem na mesma. Veja tracking a job group. - Entrega por webhook. Uma falha é entregue como um evento
translation.failedcom um campoerror. Veja webhook delivery.
Há ainda outra distinção que costuma apanhar muita gente desprevenida: a falha de uma etapa não crítica do pipeline não faz falhar o job. O job termina com completed_with_warnings e avisos por etapa, em vez de um erro. Isto é uma questão de observabilidade do pipeline, não um código de erro — veja observe pipeline runs.
Próximos passos#
Um bom handler de erros começa pelos dois códigos com que se vai cruzar primeiro durante a integração — autenticação e os pontos em que o trabalho assíncrono reporta o seu próprio resultado.
