messua/err

An error type made to be converted into an error response.

This allows for streamlined handling of error responses.

import messua/err
import messua/errs
import messua/handle
import messua/ok
import messua/rr.{type MRequest, type MResponse}

import my_mod.{type ServerState}

fn update_record(req: MRequest(ServerState)) -> MResponse {
  // If there's no Authorization: header, this returns an `Err` that
  // becomes a 400 response.
  use auth_key <- handle.require_header(req, "authorization")
  
  // If auth fails, we construct an error response ourselves.
  use user_id <- result.try(
    case rr.state(req) |> my_mod.verify_auth(auth_key) {
      my_mod.AuthFailure -> errs.unauthorized() |> Error()
      my_mod.AuthSuccess(user_id) -> Ok(user_id)
    }
  )
  
  // If there's not a properly-formed request body, this returns an
  // `Err` that becomes a 400.
  use new_record <- handle.require_json_body(req, my_mod.record_decoder)
  
  // If there's an error in our business logic, we return an `Err`
  // that becomes a 500, and add the error message to be logged.
  use response_data <- result.try(
    rr.state(req)
    |> my_mod.update_record(user_id, new_record)
    |> result.map_error(fn(msg) { errs.error() |> err.log([msg]) })
  )
  
  let body = my_mod.encode_response_data(response_data)
  
  ok.ok()
  |> ok.with_json_body(body)
  |> Ok()
}

Types

The Error variant of the MResponse type.

It will be converted to an actual gleam/http.Response once it’s out of your handler’s hands. You can optionally give it “log message” (distinct from the body message and not returned with the response—intended only for a little visibility of server errors) that will be logged by the log Layer from the messua/mware module. (Alternatively, of course, you can write your own logging Layer that uses these.)

pub type Err {
  Err(
    status: Int,
    headers: List(http.Header),
    log_msg: Option(StringBuilder),
    body_msg: Option(StringBuilder),
  )
}

Constructors

  • Err(
      status: Int,
      headers: List(http.Header),
      log_msg: Option(StringBuilder),
      body_msg: Option(StringBuilder),
    )

    You shouldn’t need to use this constructor yourself; there are plenty of functions for building these more conveniently.

    Arguments

    • status

      Response status code. This will probably be in the 4xx or 5xx range. Many of the messua/handle.require_xxx functions return 400 errors on failure.

    • headers

      Any additional headers you want to provide; these are not generally required.

    • log_msg

      An optional diagnostic message for the server administrator’s benefit.

    • body_msg

      An optional message to send as the body of the response.

Functions

pub fn log(e: Err, msg: List(String)) -> Err

Add a log message to the given response.

The message is supplied as a list of strings that will get joined with no intervening content.

pub fn new(status: Int) -> Err

Instantiate a new message with the given status code.

See also messua/errs for some functions to instantiate these more mnemonically.

pub fn to_response(
  e: Err,
  logger: fn(StringBuilder) -> Nil,
) -> Response(ResponseData)

This function is used by the handler harness to convert the Err to a proper Response before shooting it back down the pipe.

pub fn with_header(e: Err, name: String, value: String) -> Err

Add the given name: value header to the error response.

pub fn with_message(e: Err, msg: List(String)) -> Err

Add a body message to the given response.

The message is supplied as a list of strings that will get joined with no intervening content, but will have a \n suffixed.

Search Document