Pular para o conteúdo

Servidor HTTP

Rotas, parâmetros, JSON e validação com Arcane.Http.

Montar#

dataforge
adopt Arcane.Http as Http

app := Http.create("API de Tarefas")
Http.cors(app)         # libera chamadas de outra origem
Http.logger(app)       # registra cada requisição

Rotas#

dataforge
Http.get(app, "/api/tarefas", listar)
Http.get(app, "/api/tarefas/:id", buscar)
Http.post(app, "/api/tarefas", criar)
Http.put(app, "/api/tarefas/:id", atualizar)
Http.delete(app, "/api/tarefas/:id", remover)

Http.listen(app, 3000)

O :id é um parâmetro de caminho, disponível em req["params"]["id"] — como texto, sempre. Converta antes de comparar.

Requisição e resposta#

LeituraContém
req["params"]parâmetros do caminho (:id)
req["query"]da query string (?pagina=2)
req["json"]o corpo, já interpretado
req["headers"]os cabeçalhos
EscritaFaz
res.json(dados)responde JSON com 200
res.json(dados, 404)com o código que você escolher
res.html(texto)responde HTML
res.send(texto, 200)texto puro

Uma rota completa#

dataforge
action buscar(req, res):
    id := cast req["params"]["id"] as Integer
    achadas := tarefas >> sift t: t["id"] is id
    given len(achadas) is 0:
        res.json({"erro": "tarefa nao encontrada"}, 404)
    otherwise:
        res.json(achadas[0])

Códigos que importam#

CódigoQuando
200deu certo
201criou algo novo
400o cliente mandou dado inválido
404não existe
500o servidor quebrou

Devolver 200 com {"erro": …} no corpo obriga todo cliente a inspecionar o JSON para saber se deu certo. O código HTTP existe justamente para isso.

Validação fora da rota#

dataforge
action validar_tarefa(corpo):
    problemas := []
    given corpo is void:
        problemas.append("corpo ausente")
        yield problemas
    given "titulo" not in corpo:
        problemas.append("titulo e obrigatorio")
    orif len(corpo["titulo"].trim()) smaller 3:
        problemas.append("titulo precisa de ao menos 3 letras")
    yield problemas

action criar(req, res):
    problemas := validar_tarefa(req["json"])
    given len(problemas) bigger 0:
        res.json({"erros": problemas}, 400)
        yield void
    ...

Duas vantagens de separar: testável sem servidor, e reutilizável entre POST e PUT. E devolver todos os problemas de uma vez poupa o cliente de descobrir um erro por requisição.

O detalhe do orif#

Repare: sem o orif, o segundo teste rodaria mesmo quando a chave não existe, e corpo["titulo"] estouraria. orif só é avaliado se o given foi falso.

Testar#

bash
curl localhost:3000/api/tarefas
curl -X POST localhost:3000/api/tarefas \
     -H 'Content-Type: application/json' \
     -d '{"titulo":"Nova tarefa"}'