messua/aux
Helper functions for use in handlers.
Functions
pub fn require_body(
req: MRequest(a),
size_limit: Int,
next: fn(BitArray) -> Result(Response(ResponseData), Err),
) -> Result(Response(ResponseData), Err)
Extract the raw bytes of the body of the request, or return a 400 with a message if the body is absent.
Examples
import messua/aux
import messua/err
import messua/ok
const max_body_size: Int = 0x100000 // 1 MiB
fn process_request(req: MRequest(state)) -> MResponse {
use body_bytes <- aux.require_body(req, max_body_size)
case process_body(body_bytes) {
Ok(result) -> ok.ok()
|> ok.with_binary_body(result)
Error(e) -> err.new(500)
|> err.with_message(["unable to process request: ", string.inspect(e)])
}
}
pub fn require_header(
req: MRequest(a),
name: String,
next: fn(String) -> Result(Response(ResponseData), Err),
) -> Result(Response(ResponseData), Err)
Get the given header value, or return a 400 response with a message if not present.
Examples
import gleam/result
import messua/aux
import messua/ok
fn retrieve_user_data(req: MRequest) -> MResponse {
use uname <- aux.require_header(req, "x-user-name")
use user <- result.try(
get_user_by_name(uname)
|> result.replace_error(err.new(500))
)
let body = encode_user_details(user)
ok.ok()
|> ok.with_json_body(body)
|> Ok()
}
pub fn require_json_body(
req: MRequest(a),
size_limit: Int,
decoder: fn(Dynamic) -> Result(b, List(DecodeError)),
next: fn(b) -> Result(Response(ResponseData), Err),
) -> Result(Response(ResponseData), Err)
Extract the body of the request and attempt to JSON from it with the
given gleam/dynamic
decoder. Returns a 400 if the body is missing or
fails to decode with the given decoder.
Examples
import gleam/dynamic.{type Dynamic, type DecodeErrors}
import messua/aux
import messua/err
import messua/ok
type Book {
Book(
author: String,
title: String,
pub_year: Int,
)
}
fn book_decoder(chunk: Dynamic) -> Result(Book, DecodeErrors) {
chunk
|> dynamic.decode3(
Book,
dynamic.field("author", dynamic.string),
dynamic.field("title", dynamic.string),
dynamic.field("pub_year", dynamic.int)
)
}
fn read_books(req: MRequest) -> MResponse {
use book_list <- aux.require_json_body(
req,
0x1000, // 4 KiB of `Book`s
dynamic.list(book_decoder)
)
case fetch_and_consume_these_books(book_list) {
Ok(_) -> ok.ok() |> Ok() // Okay, okay, okay!!!
Error(_) -> err.new(500)
|> err.with_message(["Couldn't read them all! :^("])
|> Error()
}
}
pub fn require_string_body(
req: MRequest(a),
size_limit: Int,
next: fn(String) -> Result(Response(ResponseData), Err),
) -> Result(Response(ResponseData), Err)
Like require_body
, but returns a String
; will also fail with
a 400 if the body isn’t valid UTF-8.
pub fn require_valid_header(
req: MRequest(a),
name: String,
validator: fn(String) -> Result(b, c),
next: fn(b) -> Result(Response(ResponseData), Err),
) -> Result(Response(ResponseData), Err)
Requires the given header to both exist and have a value acceptable to a supplied validator function. A 400 result with an explanatory message is returned on failure.
Examples
import gleam/int
import gleam/result
import messua/aux
import messua/ok
fn retrieve_user_data(req: MRequest) -> MResponse {
use uid <- aux.require_valid_header(req, "x-user-name", int.parse)
use user <- result.try(
get_user_by_id(uid)
|> result.replace_error(err.new(500))
)
let body = encode_user_details(user)
ok.ok()
|> ok.with_json_body(body)
|> Ok()
}