Pular para o conteúdo

Erros que um programa lê

application/problem+json (RFC 9457): o tipo, o título, o detalhe — e por que texto de erro não é contrato.

Todo cliente de uma API acaba precisando decidir o que fazer com um erro: tentar de novo, pedir outro dado, mostrar uma mensagem. Se o erro é só um texto — {"erro": "saldo insuficiente"} —, o cliente decide comparando texto, e a primeira revisão de ortografia no servidor quebra todos eles.

A RFC 9457 resolve isso com cinco campos, e Kiln.problema os monta:

CampoO que éQuem lê
typeuma URI que identifica o tipo do problemao programa: é por ele que se decide
titleo resumo do tipo, igual em toda ocorrênciaa pessoa, num log
statuso mesmo código da resposta HTTPquem só tem o corpo em mãos
detailo que aconteceu desta veza pessoa, na tela
instancequal pedido falhouo suporte, cruzando com o log
dataforge
adopt Arcane.Kiln as Kiln

saldos := {"ana": 30}
app := Kiln.app()

action comprar(req):
    quem := req["params"]["quem"]
    preco := req["body"]["preco"]
    given (saldos[quem] ?? void) is void:
        yield Kiln.problema(404, "Conta não encontrada", $"não há conta '{quem}'")
    given preco bigger saldos[quem]:
        yield Kiln.problema(422, "Saldo insuficiente",
            $"o saldo é {saldos[quem]} e a compra custa {preco}",
            "https://loja.exemplo/erros/saldo-insuficiente",
            {"saldo": saldos[quem], "preco": preco})
    saldos[quem] -= preco
    yield Kiln.json({"saldo": saldos[quem]})

Kiln.post(app, "/contas/:quem/compras", comprar)

r := Kiln.test(app, "POST", "/contas/ana/compras", {"preco": 50})
assert r["status"] is 422
assert r["body"]["type"] is "https://loja.exemplo/erros/saldo-insuficiente"
assert r["body"]["saldo"] is 30
assert Kiln.test(app, "POST", "/contas/bia/compras", {"preco": 1})["status"] is 404

Três decisões que a peça cobra#

  • Problema é erro. Kiln.problema(200, …) é recusado: um corpo de problema num 200 faz o cliente que olha o status seguir adiante com um erro na mão.
  • Os campos da RFC não vêm em `extras`. Um extras com status sobrescreveria o status real no corpo e deixaria corpo e cabeçalho dizendo coisas diferentes.
  • `about:blank` é o tipo padrão, e ele quer dizer "o status HTTP já diz tudo". Assim que um cliente precisar distinguir dois 422, dê a cada um o seu type.