Cookbook / Requests and responses

A JSON API

Parse JSON bodies, query strings and typed path parameters, and get the right 4xx status for free.

The typed request helpers parse input and answer bad input with the correct status code, so handlers only see data that already has the right shape.

ProblemStatus
:id is not a number400
Body is not application/json415
Body is malformed JSON400
JSON has the wrong fields422
src/main.rs
use axeon::{Json, Server, ServerError};
use serde::{Deserialize, Serialize};

#[derive(Deserialize, Serialize)]
struct NewUser {
    name: String,
    age: u8,
}

#[derive(Deserialize)]
struct Search {
    q: String,
    page: Option<u32>,
}

fn main() {
    let mut app = Server::new();

    // 400 if `id` isn't a number.
    app.get("/users/:id", |req| async move {
        let id: u64 = req.param("id")?;
        Ok::<_, ServerError>(format!("user {}", id))
    });

    // GET /search?q=rust&page=2
    app.get("/search", |req| async move {
        let search: Search = req.query_as()?;
        Ok::<_, ServerError>(format!("{} (page {})", search.q, search.page.unwrap_or(1)))
    });

    // A status code and a body, as a tuple.
    app.post("/users", |req| async move {
        let user: NewUser = req.json()?;
        Ok::<_, ServerError>((201, Json(user)))
    });

    app.listen("127.0.0.1:3000").expect("server failed to start");
}
Terminal
curl -X POST http://127.0.0.1:3000/users \
  -H 'content-type: application/json' \
  -d '{"name":"Ada","age":36}'

curl -i -X POST http://127.0.0.1:3000/users \
  -H 'content-type: application/json' \
  -d '{"name":"Ada"}'          # 422: the age is missing

Notes#

  • When a handler's only result is Ok(..), with no ? or Err, either return the value directly or write the error type once: Ok::<_, ServerError>(..).
  • Also available: req.query_param("page"), req.get_header("authorization"), req.text(), req.form(), req.form_value() and req.remote_addr().
  • For field-level checks see Validation.