messua/rr

Requests and Responses.

Types

Naturally, a function that accepts an MRequest and returns an MResponse is considered a request Handler.

pub type Handler(state) =
  fn(MRequest(state)) -> MResponse

A Layer is a Handler with another “inner” Handler it can optionally pass an incoming request through. This inner handler may itself be another layer; it is possible to form stacks arbitrarily deep this way (see the Stack example).

(The inspiration for this particular type is the tower-layer Rust crate.)

Examples

A layer that logs requests to stdout might look like this:

import gleam/int
import gleam/io
import gleam/string_builder

import gleam/http

fn handler(req: MRequest(State)) -> MResponse {
// ...Routing and handling goes here.  
}

fn log_layer(req: MRequest(State), next: Handler(State)) -> MResponse {
  // Get source, method, path from request.
  let source = case info(req) {
    Ok(info) -> string_builder.from_strings([
      string.inspect(info.ip_address), ":", int.to_string(info.port)
    ])
    Error(_) -> string_builder.from_string("[ source ??? ]")
  }
  
  let inner_req = inner(req)
  let url = string_builder.from_strings([
    string.inspect(inner_req.method),
    " ",
    string.inspect(inner_req.path)
  ])

  // Call inner handling function, get response.
  let mresp = next(req)

  // Note response status.
  let result_msg = case mresp {
    Ok(resp) -> string_builder.from_string(int.to_string(resp.status))
    Err(e) -> string_builder.from_string(int.to_string(e.status))
  }

  // Print a request log entry with the source, method, path fo the
  // request and the status code of the associated response.
  string_builder.append(source, " ")
  |> string_builder.append_builder(url)
  |> string_builder.append(" ")
  |> string_builder.append(result_msg)
  |> string_builder.to_string()
  |> io.println()

  // Return the response.
  mresp
}

messua.default()
|> messua.start(log_layer(_, handler))
pub type Layer(state) =
  fn(MRequest(state), Handler(state)) -> MResponse

A request with some user-defined server state.

The type parameter is the type of the state object that gets injected into (or bundled with) each incoming request.

pub opaque type MRequest(state)

A result type with Errors that will automatically become responses.

pub type MResponse =
  Result(response.Response(mist.ResponseData), err.Err)

Functions

pub fn info(req: MRequest(a)) -> Result(ConnectionInfo, Nil)

Get the underlying connection’s mist.ConnectionInfo.

Consider handle.get_client() or handle.require_client() for something in this namespace that returns equivalent information.

pub fn inner(req: MRequest(a)) -> Request(Connection)

Access the underlying gleam/http/request.Request.

pub fn make_mist_handler(
  state: a,
  handle: fn(MRequest(a)) -> Result(Response(ResponseData), Err),
) -> fn(Request(Connection)) -> Response(ResponseData)

messau.start() uses this internally. You don’t need to use it, but Gleam’s visibility rules aren’t granular enough to hide it fron you.

pub fn stack(
  base: fn(MRequest(a)) -> Result(Response(ResponseData), Err),
  layers: List(
    fn(
      MRequest(a),
      fn(MRequest(a)) -> Result(Response(ResponseData), Err),
    ) -> Result(Response(ResponseData), Err),
  ),
) -> fn(MRequest(a)) -> Result(Response(ResponseData), Err)

Compose a stack of nested Layers into a Handler that can be passed to messua.start().

The front of the list is the “bottom” of the stack; the end of the list is the top.

Examples

See the Stack example in the repository for an expository example.

pub fn state(req: MRequest(a)) -> a

Retrieve the state that’s been injected into the MRequest.

Search Document