messua/mout

Instantiating and building Outgoing responses.

Types

The response type used throughout this library.

Outgoing is a Result type, which takes advantage of the “early return on error” behavior1 of use sugar. The Error(Failure) variant is turned into an actual HTTP response before being spit back out into the world.

(This example contains some hypothetical functions and types that we do not define, but the general idea should be clear from context.)


// This wrapper around our database module's `check_auth()` function
// is designed to work with `result.try()`.
fn check_auth(
  db_handle: DatabaseHandle,
  auth_header: String,
) -> Result(User, Failure) {
  case dbase.get_user_from_auth(auth_header) {
    Ok(user) -> Ok(user)
    Error(dbase.UserNotFound) -> fail.error(fail.Unauthorized) |> Error()
    Error(_) -> fail.error(fail.InternalServerError) |> Error()
  }
}

fn handle(in: Incoming(DatabaseHandle)) -> Outgoing {
  // If the request doesn't have an "authorization" header, this returns a
  // 400: Bad Request response with a body noting the required header.
  use auth_header <- handle.require_header(in, "authorization")
  // If, for some reason, we can't get our hands on the server state, this
  // returns a 500: Internal Server Error response.
  use db_handle <- handle.require_state(in)
  // If `check_auth()` fails, we return the `Error(Failure)` response
  // it gives us, otherwise we have our authenticated `User`.
  use user <- result.try(check_auth(db_handle, auth_header))
  // If we can't decode request data from the body (because it's invalid
  // or missing), we return a 400: Bad Request response.
  use request_data <- handle.require_json_body(
    in,
    1024 * 1024,
    request_data_decoder(),
  )
  // If our actual processing of the request fails, we return a
  // 500: Internal Server Error response here, otherwise we have
  // the data for our response.
  use result_data <- result.try(
    dbase.do_business_logic(db_handle, user, request_data)
    |> result.replace_error(fail.new()),
  )
  let result_json = result_data_to_json(result_data)
  // And we return our response data in a 200: Ok response.
  mout.ok()
  |> mout.with_json_body(result_json)
}
pub type Outgoing =
  Result(response.Response(mist.ResponseData), fail.Failure)

Values

pub fn fail() -> Result(
  response.Response(mist.ResponseData),
  fail.Failure,
)

A new Outgoing response that will translate to an otherwise-empty 500: Internal Server Error response.

pub fn from_response(
  resp: response.Response(mist.ResponseData),
) -> Result(response.Response(mist.ResponseData), fail.Failure)

Easily turn your hand-tweaked response.Response into an Outgoing.

pub fn into_response(
  out: Result(response.Response(mist.ResponseData), fail.Failure),
) -> response.Response(mist.ResponseData)

Convert an Outgoing into a response.Response from the gleam_http package.

pub fn ok() -> Result(
  response.Response(mist.ResponseData),
  fail.Failure,
)

A new Outgoing 200: OK response with no other information.

pub fn raw_response(
  status: Int,
) -> response.Response(mist.ResponseData)

Generate a raw response.Response type from the gleam_http library with the given status, if you need to manipulate it in a way this library doesn’t provide.

pub fn serve_dir(
  dir: String,
  subsegments: List(String),
) -> Result(response.Response(mist.ResponseData), fail.Failure)

Serve a file from dir (or one of its subdirectories) by appending the list of subsegments to get a path.

This otherwise has the same semantics as serve_file().

serve_file("/home/server/content", ["images", "blue_frog.jpg"])

will return the file at /home/server/content/images/blue_frog.jpg, or 404 trying.

pub fn serve_file(
  path: String,
) -> Result(response.Response(mist.ResponseData), fail.Failure)

Return the file at the given path on the server’s local filesystem as the body of a request.

This will attempt to guess the content-type based on the file extension (using marceau, and you can always set it manually), and will return a 404: Not Found if there’s any problem accessing the given path.

pub fn with_body(
  out: Result(response.Response(mist.ResponseData), fail.Failure),
  body: BitArray,
) -> Result(response.Response(mist.ResponseData), fail.Failure)

Add a body to the response. The “content-length” should get set correctly, but you should set the “content-type” header.

pub fn with_header(
  out: Result(response.Response(mist.ResponseData), fail.Failure),
  name: String,
  value: String,
) -> Result(response.Response(mist.ResponseData), fail.Failure)

Add the given header to the Outgoing response.

pub fn with_json_body(
  out: Result(response.Response(mist.ResponseData), fail.Failure),
  body: json.Json,
) -> Result(response.Response(mist.ResponseData), fail.Failure)

Add the given encoded JSON as a body. The “content-length” and “content-type” (application/json) should get set correctly.

pub fn with_status(
  out: Result(response.Response(mist.ResponseData), fail.Failure),
  status: Int,
) -> Result(response.Response(mist.ResponseData), fail.Failure)

Set the status of the response.

pub fn with_string_body(
  out: Result(response.Response(mist.ResponseData), fail.Failure),
  body: String,
) -> Result(response.Response(mist.ResponseData), fail.Failure)

Add a body to the response. The “content-length” and “content-type” (text/plain) should get set correctly.

Search Document