Published 2024-10-07 by Daniel Bark
First time trying out Gleam
Installation
Following the official docs I got started with:
brew install gleam
Then setting up the project
gleam new http_proxy_gleam
We get some code in src/http_proxy_gleam.gleam
import gleam/io
pub fn main() {
io.println("Hello from http_proxy_gleam!")
}
Then first test run
gleam run
// Hello from http_proxy_gleam!
I like to make sure I have a working state before i mess everything up.
Now lets add some packages
gleam add \
wisp@1.1 \
mist@2.0 \
gleam_http@3.6 \
gleam_erlang@0.25
And get some Hello world from the http server:
pub fn main() {
let assert Ok(_) =
wisp_mist.handler(
fn(_) {
wisp.html_response(
string_builder.from_string(
"<body style=\"color:pink;\">Hello, World!</body>",
),
200,
)
},
"secret_key",
)
|> mist.new
|> mist.port(8000)
|> mist.start_http
process.sleep_forever()
}
Not that strange to me. The secret key is used sign cookies and other sensitive data and should of course come from an env var in real life.
Now let break out the inline req handler function to:
pub type Context {
Context
}
pub fn handle_request(_: Request, _: Context) -> Response {
wisp.html_response(
string_builder.from_string(
"<body style=\"color:pink;\">Hello, World!</body>",
),
200,
)
}
Wisp support passing along a context with request to keep a Db connection or other data you might need. Lets see if we can do something basic like sending back the req headers.
pub fn handle_request(req: Request, _: Context) -> Response {
let headers = req.headers
let header_list =
headers
|> iterator.from_list
|> iterator.map(fn(header) {
let #(key, value) = header
"<div>" <> key <> ":" <> value <> "</div>"
})
|> iterator.to_list
let headers_string = string.concat(header_list)
wisp.html_response(
string_builder.from_string("<div>Request Headers:</div>" <> headers_string),
200,
)
}
Here we get to try out some iterator pipeline operations that Gleam brags about :)
Now lets try fetching data from somewhere and returning it.
First we install an http client:
gleam add gleam_httpc@3
pub fn handle_request(_: Request, _: Context) -> Response {
let data = result.unwrap(fetch_some_data(), "Error")
wisp.html_response(string_builder.from_string(data), 200)
}
pub fn fetch_some_data() {
// Prepare a HTTP request record
let assert Ok(base_req) =
request.to("https://test-api.service.hmrc.gov.uk/hello/world")
let req =
request.prepend_header(base_req, "accept", "application/vnd.hmrc.1.0+json")
// Send the HTTP request to the server
use resp <- result.try(httpc.send(req))
// We get a response record back
resp.status
|> should.equal(200)
resp
|> response.get_header("content-type")
|> should.equal(Ok("application/json"))
resp.body
|> should.equal("{\"message\":\"Hello World\"}")
Ok(resp.body)
}
And we do get a {"message":"Hello World"}
back from test-api.service.hmrc.gov.uk
and then back from out server.
The first hour of Gleam was not that bad. The iterator patterns remind me of Rust. The STD lib reminds me of Go since methods dont live on the types.
Thanks for reading :)
Written by Daniel Bark
← Back to blog