Current section
Files
Jump to
Current section
Files
src/gleam/http/response.gleam
import gleam/http.{type Header}
import gleam/http/cookie
import gleam/list
import gleam/option
import gleam/result
import gleam/string
/// A HTTP response.
///
/// The body of the request is parameterised. The HTTP server or client you are
/// using will have a particular set of types it supports for the body.
///
pub type Response(body) {
Response(
status: Int,
/// The request headers. The keys must always be lowercase.
headers: List(Header),
body: body,
)
}
/// Update the body of a response using a given result returning function.
///
/// If the given function returns an `Ok` value the body is set, if it returns
/// an `Error` value then the error is returned.
///
pub fn try_map(
response: Response(old_body),
transform: fn(old_body) -> Result(new_body, error),
) -> Result(Response(new_body), error) {
use body <- result.try(transform(response.body))
Ok(set_body(response, body))
}
/// Construct an empty Response.
///
/// The body type of the returned response is `String` and could be set with a
/// call to `set_body`.
///
pub fn new(status: Int) -> Response(String) {
Response(status:, headers: [], body: "")
}
/// Get the value for a given header.
///
/// If the response does not have that header then `Error(Nil)` is returned.
///
pub fn get_header(response: Response(body), key: String) -> Result(String, Nil) {
list.key_find(response.headers, string.lowercase(key))
}
/// Set the header with the given value under the given header key.
///
/// If the response already has that key, it is replaced.
///
/// Header keys are always lowercase in `gleam_http`. To use any uppercase
/// letter is invalid.
///
pub fn set_header(
response: Response(body),
key: String,
value: String,
) -> Response(body) {
let headers = list.key_set(response.headers, string.lowercase(key), value)
Response(..response, headers:)
}
/// Prepend the header with the given value under the given header key.
///
/// Similar to `set_header` except if the header already exists it prepends
/// another header with the same key.
///
/// Header keys are always lowercase in `gleam_http`. To use any uppercase
/// letter is invalid.
///
pub fn prepend_header(
response: Response(body),
key: String,
value: String,
) -> Response(body) {
let headers = [#(string.lowercase(key), value), ..response.headers]
Response(..response, headers:)
}
/// Set the body of the response, overwriting any existing body.
///
pub fn set_body(
response: Response(old_body),
body: new_body,
) -> Response(new_body) {
Response(..response, body:)
}
/// Update the body of a response using a given function.
///
pub fn map(
response: Response(old_body),
transform: fn(old_body) -> new_body,
) -> Response(new_body) {
response.body
|> transform
|> set_body(response, _)
}
/// Create a response that redirects to the given uri.
///
pub fn redirect(uri: String) -> Response(String) {
Response(
status: 303,
headers: [#("location", uri)],
body: string.append("You are being redirected to ", uri),
)
}
/// Fetch the cookies sent in a response.
///
/// Badly formed cookies will be discarded.
///
pub fn get_cookies(resp: Response(body)) -> List(#(String, String)) {
let Response(headers:, ..) = resp
list.flat_map(headers, fn(header) {
case header {
#("set-cookie", value) -> cookie.parse(value)
_ -> []
}
})
}
/// Set a cookie value for a client
///
pub fn set_cookie(
response: Response(body),
name: String,
value: String,
attributes: cookie.Attributes,
) -> Response(body) {
prepend_header(
response,
"set-cookie",
cookie.set_header(name, value, attributes),
)
}
/// Expire a cookie value for a client
///
/// Note: The attributes value should be the same as when the response cookie was set.
pub fn expire_cookie(
response: Response(body),
name: String,
attributes: cookie.Attributes,
) -> Response(body) {
let attrs = cookie.Attributes(..attributes, max_age: option.Some(0))
set_cookie(response, name, "", attrs)
}