glen
🏕️ A peaceful web framework that targets JS.
Other packages you will need:
gleam_http
— everythingRequest
andResponse
relatedgleam_javascript
— provides tools for working with JavaScript promises.
Types
A request handler.
Examples
fn my_serve(port: Int, handler: glen.Handler) -> Nil {
io.println("Starting server...")
glen.serve(port, handler)
}
pub type Handler =
fn(Request) -> Promise(Response)
A JavaScript request handler.
pub type JsHandler =
fn(JsRequest) -> Promise(JsResponse)
A standard JavaScript ReadableStream
.
pub type JsReadableStream =
conversation.JsReadableStream
A standard JavaScript Response
.
pub type JsResponse =
conversation.JsResponse
An incoming request’s body.
pub type RequestBody =
conversation.RequestBody
An outgoing response’s body.
pub type ResponseBody {
Text(String)
File(path: String)
Bits(BitArray)
Empty
Websocket(ws.WebsocketBody)
}
Constructors
-
Text(String)
A text body.
-
File(path: String)
A file body. The file will be streamed and not read into memory, so it is okay to send files of any size. If the file cannot be accessed, an empty response with a 500 status code (internal server error) will be returned.
-
Bits(BitArray)
A
BitArray
body. -
Empty
An empty body, equivalent to
Bits(<<>>)
. -
Websocket(ws.WebsocketBody)
A websocket response body.
Constants
pub const path_segments: fn(Request(RequestBody)) -> List(String)
Return the non-empty segments of a request path.
ℹ️ This function is re-exported from
gleam_http
.
Examples
case glen.path_segments(req) {
[] -> index_page()
["about"] -> about_page()
["greet", name] -> greet_page(name)
_ -> not_found_page()
}
pub const set_body: fn(Response(ResponseBody), ResponseBody) ->
Response(ResponseBody)
Set the body of a response.
ℹ️ This function is re-exported from
gleam_http
.
pub const set_header: fn(Response(ResponseBody), String, String) ->
Response(ResponseBody)
Set the header with the given value under the given header key.
If the response already has that key, it is replaced.
ℹ️ This function is re-exported from
gleam_http
.
Functions
pub fn bit_array_body(
res: Response(ResponseBody),
bits: BitArray,
) -> Response(ResponseBody)
Set the body of a response to a BitArray
.
pub fn convert_request(req: JsRequest) -> Request(RequestBody)
Convert a JavaScript request into a Glen request.
pub fn convert_response(
res: Response(ResponseBody),
) -> JsResponse
Convert a Glen response into a JavaScript response.
pub fn escape_html(string: String) -> String
Escape a string so it can be included inside of HTML safely. You should run this function on all user input being included in HTML to prevent possible XSS attacks.
pub fn file(path: String, status: Int) -> Response(ResponseBody)
Create a response with a file stream as the body. The content-type
header
will be automatically set based on the file’s extension.
pub fn file_body(
res: Response(ResponseBody),
path: String,
) -> Response(ResponseBody)
Set the body of a response to a file stream. The content-type
header
will be automatically set based on the file’s extension.
pub fn get_query(
req: Request(RequestBody),
) -> List(#(String, String))
Get the query parameters from a request. Parameters are not predictably
ordered, so you should not pattern match on them. Instead, use the
key_find
function from gleam/list
to access parameters.
pub fn html(html: String, status: Int) -> Response(ResponseBody)
Create a response with an HTML body.
pub fn html_body(
res: Response(ResponseBody),
html: String,
) -> Response(ResponseBody)
Set the body of a response to HTML.
pub fn json(json: String, status: Int) -> Response(ResponseBody)
Create a response with a JSON body.
pub fn json_body(
res: Response(ResponseBody),
json: String,
) -> Response(ResponseBody)
Set the body of a response to JSON.
pub fn log(
req: Request(RequestBody),
next: fn() -> Promise(Response(ResponseBody)),
) -> Promise(Response(ResponseBody))
Middleware function for logging requests and responses.
Examples
fn handle_req(req) {
use <- glen.log(req)
// ...requests and responses are now logged...
}
pub fn method_not_allowed(
allowed: List(Method),
) -> Response(ResponseBody)
Create a response with a status of 405 (method not allowed). The allowed
header will be set to the given allowed methods.
pub fn read_body_bits(
req: Request(RequestBody),
) -> Promise(Result(BitArray, ReadError))
Read a request body as a BitArray
.
pub fn read_form_body(
req: Request(RequestBody),
) -> Promise(Result(FormData, ReadError))
Read a request body as FormData
.
pub fn read_json_body(
req: Request(RequestBody),
) -> Promise(Result(Dynamic, ReadError))
Read a request body as JSON.
pub fn read_text_body(
req: Request(RequestBody),
) -> Promise(Result(String, ReadError))
Read a request body as text.
pub fn redirect(
url: String,
status: Int,
) -> Response(ResponseBody)
Redirect the client to a URL with the given status. The status should be
in the 3xx range (such as 303: See Other
or 307: Temporary Redirect
).
pub fn require_bit_array_body(
req: Request(RequestBody),
next: fn(BitArray) -> Promise(Response(ResponseBody)),
) -> Promise(Response(ResponseBody))
Middleware function that reads a request body as a BitArray
.
Examples
fn handle_req(req) {
use bits <- glen.require_bit_array_body(req)
"Look at all the bits! " <> string.inspect(bits)
|> glen.html(status.ok)
|> promise.resolve
}
pub fn require_content_type(
req: Request(RequestBody),
required: String,
next: fn() -> Promise(Response(ResponseBody)),
) -> Promise(Response(ResponseBody))
Middleware function for requiring the request to have a content-type
header
with a specific content type. Returns the same as
unsupported_media_type
if the header is missing
or does not meet the requirement.
Examples
fn handle_req(req) {
use <- glen.require_content_type(req, "text/html")
// ...the request's content-type must be text/html...
}
pub fn require_form(
req: Request(RequestBody),
next: fn(FormData) -> Promise(Response(ResponseBody)),
) -> Promise(Response(ResponseBody))
Middleware for requiring the request body to be a form with a content-type
of either application/x-www-form-urlencoded
or multipart/form-data
.
Formdata values are sorted alphabetically so they can be pattern matched on.
Examples
fn handle_req(req) {
use formdata <- glen.require_form(req)
case formdata.values {
[#("name", name)] -> greet(name)
_ -> glen.response(status.bad_request)
}
|> promise.resolve
}
pub fn require_json(
req: Request(RequestBody),
next: fn(Dynamic) -> Promise(Response(ResponseBody)),
) -> Promise(Response(ResponseBody))
Middleware function for requiring the request body to be JSON with a
content-type
of application/json
.
Examples
fn handle_req(req) {
use json <- glen.require_json(req)
case my_decoder(json) {
Ok(decoded) -> decoded.foo |> glen.text(status.ok)
Error(_) -> glen.response(status.bad_request)
}
|> promise.resolve
}
pub fn require_method(
req: Request(RequestBody),
method: Method,
next: fn() -> Promise(Response(ResponseBody)),
) -> Promise(Response(ResponseBody))
Middleware function for requiring the request to be of a certain HTTP method.
Returns the same as method_not_allowed
if the method
does not meet the requirement.
Examples
fn handle_req(req) {
use <- glen.require_method(req, http.Get)
// ...only GET requests are allowed...
}
pub fn require_string_body(
req: Request(RequestBody),
next: fn(String) -> Promise(Response(ResponseBody)),
) -> Promise(Response(ResponseBody))
Middleware function that reads a request body as a string.
Examples
fn handle_req(req) {
use string_body <- glen.require_string_body(req)
"You gave me: " <> glen.escape_html(string_body)
|> glen.html(status.ok)
|> promise.resolve
}
pub fn rescue_crashes(
handler: fn() -> Promise(Response(ResponseBody)),
) -> Promise(Response(ResponseBody))
Middleware function that rescues any crashes with an empty response and a status of 500 (internal server error).
Gleam code should never crash under normal circumstances, but it’s always good to be prepared.
Examples
fn handle_req(req) {
use <- glen.rescue_crashes
// ...crashes are now handled gracefully...
}
pub fn response(status: Int) -> Response(ResponseBody)
Create a response with the given status code and an empty body.
pub fn serve(
port: Int,
handler: fn(Request(RequestBody)) ->
Promise(Response(ResponseBody)),
) -> Nil
Start a server using Deno.serve
.
ℹ️ Only works when using the
deno
runtime. See the readme for more info.
Examples
glen.serve(8000, fn(_req) {
"Hello, world!"
|> glen.text(status.ok)
|> promise.resolve
})
pub fn static(
req: Request(RequestBody),
prefix: String,
directory: String,
next: fn() -> Promise(Response(ResponseBody)),
) -> Promise(Response(ResponseBody))
Middleware for serving up static files from a directory under a path prefix.
Examples
fn handle_req(req) {
use <- glen.static(req, "static", "./somedir/static")
"<img src='/static/image.png'/>" |> glen.html(status.ok) |> promise.resolve
}
pub fn text(text: String, status: Int) -> Response(ResponseBody)
Create a response with a text body.
pub fn text_body(
res: Response(ResponseBody),
text: String,
) -> Response(ResponseBody)
Set the body of a response to text.
pub fn unsupported_media_type(
supported: List(String),
) -> Response(ResponseBody)
Create a response with a status of 415 (unsupported media type). The accept
header will be set to the given supported content types.
pub fn websocket(
req: Request(RequestBody),
on_open on_open: fn(WebsocketConn(a)) -> b,
on_close on_close: fn(b) -> Nil,
on_event on_event: fn(WebsocketConn(a), b, WebsocketMessage(a)) ->
b,
with_conn do: fn(WebsocketConn(a)) -> Nil,
) -> Promise(Response(ResponseBody))
Upgrade a request to become a websocket. If the request does not have an
upgrade
header set to websocket
, a response of 426 (upgrade required) will
be returned.
on_open
gets called when a client starts a websocket connection.on_close
is called when the connection in closed.on_event
gets called when the websocket recieves an event or message.
ℹ️ Websockets are currently only supported when using the
deno
runtime.
Examples
See this for a more detailed example of websockets.
fn handle_req(req) {
use _conn <- glen.websocket(
req,
on_open: on_open,
on_close: on_close,
on_event: on_event,
)
Nil
}
fn on_open(conn) {
// ...
}
fn on_close(state) {
// ...
}
fn on_event(conn, state, msg) {
// ...
}