Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ jobs:
- uses: actions/checkout@v4
- uses: erlef/setup-beam@v1
with:
otp-version: "26.0"
gleam-version: "1.0.0"
otp-version: "27"
gleam-version: "1.9.1"
rebar3-version: "3"
- run: gleam test
- run: gleam format --check src test
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM ghcr.io/gleam-lang/gleam:v0.25.3-erlang-alpine
FROM ghcr.io/gleam-lang/gleam:v1.9.1-erlang-alpine

# Create a group and user to run as
RUN addgroup -S echogroup && adduser -S echouser -G echogroup
Expand Down
12 changes: 7 additions & 5 deletions gleam.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name = "reply"
version = "1.0.0"
version = "1.1.0"
licences = ["Apache-2.0"]
description = "A tiny echo server written in Gleam!"

Expand All @@ -10,10 +10,12 @@ links = [
]

[dependencies]
gleam_stdlib = "~> 0.25 or ~> 1.0"
gleam_http = "~> 3.0"
gleam_elli = "~> 2.0"
gleam_erlang = "~> 0.17"
gleam_stdlib = "~> 0.38"
gleam_http = "~> 3.5"
gleam_erlang = "~> 0.23"
wisp = ">= 1.2.0 and < 2.0.0"
mist = ">= 4.0.6 and < 5.0.0"
envoy = ">= 1.0.2 and < 2.0.0"

[dev-dependencies]
gleeunit = "~> 1.0"
39 changes: 28 additions & 11 deletions manifest.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,35 @@
# You typically do not need to edit this file

packages = [
{ name = "elli", version = "3.3.0", build_tools = ["rebar3"], requirements = [], otp_app = "elli", source = "hex", outer_checksum = "698B13B33D05661DB9FE7EFCBA41B84825A379CCE86E486CF6AFF9285BE0CCF8" },
{ name = "gleam_elli", version = "2.4.0", build_tools = ["gleam"], requirements = ["elli", "gleam_erlang", "gleam_http", "gleam_otp", "gleam_stdlib"], otp_app = "gleam_elli", source = "hex", outer_checksum = "433F5AF4ED92C55F3EBA8942610E974254EEF90F484AF26E3D775E33338DE832" },
{ name = "gleam_erlang", version = "0.25.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "054D571A7092D2A9727B3E5D183B7507DAB0DA41556EC9133606F09C15497373" },
{ name = "gleam_http", version = "3.6.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_http", source = "hex", outer_checksum = "8C07DF9DF8CC7F054C650839A51C30A7D3C26482AC241C899C1CEA86B22DBE51" },
{ name = "gleam_otp", version = "0.10.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "0B04FE915ACECE539B317F9652CAADBBC0F000184D586AAAF2D94C100945D72B" },
{ name = "gleam_stdlib", version = "0.36.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "C0D14D807FEC6F8A08A7C9EF8DFDE6AE5C10E40E21325B2B29365965D82EB3D4" },
{ name = "gleeunit", version = "1.0.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "D364C87AFEB26BDB4FB8A5ABDE67D635DC9FA52D6AB68416044C35B096C6882D" },
{ name = "directories", version = "1.1.0", build_tools = ["gleam"], requirements = ["envoy", "gleam_stdlib", "platform", "simplifile"], otp_app = "directories", source = "hex", outer_checksum = "BDA521A4EB9EE3A7894F0DC863797878E91FF5C7826F7084B2E731E208BDB076" },
{ name = "envoy", version = "1.0.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "envoy", source = "hex", outer_checksum = "95FD059345AA982E89A0B6E2A3BF1CF43E17A7048DCD85B5B65D3B9E4E39D359" },
{ name = "exception", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "exception", source = "hex", outer_checksum = "F5580D584F16A20B7FCDCABF9E9BE9A2C1F6AC4F9176FA6DD0B63E3B20D450AA" },
{ name = "filepath", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "B06A9AF0BF10E51401D64B98E4B627F1D2E48C154967DA7AF4D0914780A6D40A" },
{ name = "gleam_crypto", version = "1.5.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_crypto", source = "hex", outer_checksum = "917BC8B87DBD584830E3B389CBCAB140FFE7CB27866D27C6D0FB87A9ECF35602" },
{ name = "gleam_erlang", version = "0.34.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "0C38F2A128BAA0CEF17C3000BD2097EB80634E239CE31A86400C4416A5D0FDCC" },
{ name = "gleam_http", version = "3.7.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_http", source = "hex", outer_checksum = "8A70D2F70BB7CFEB5DF048A2183FFBA91AF6D4CF5798504841744A16999E33D2" },
{ name = "gleam_json", version = "2.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "C55C5C2B318533A8072D221C5E06E5A75711C129E420DD1CE463342106012E5D" },
{ name = "gleam_otp", version = "0.16.1", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "50DA1539FC8E8FA09924EB36A67A2BBB0AD6B27BCDED5A7EF627057CF69D035E" },
{ name = "gleam_stdlib", version = "0.59.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "F8FEE9B35797301994B81AF75508CF87C328FE1585558B0FFD188DC2B32EAA95" },
{ name = "gleam_yielder", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_yielder", source = "hex", outer_checksum = "8E4E4ECFA7982859F430C57F549200C7749823C106759F4A19A78AEA6687717A" },
{ name = "gleeunit", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "0E6C83834BA65EDCAAF4FE4FB94AC697D9262D83E6F58A750D63C9F6C8A9D9FF" },
{ name = "glisten", version = "7.0.1", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_otp", "gleam_stdlib", "logging", "telemetry"], otp_app = "glisten", source = "hex", outer_checksum = "1A53CF9FB3231A93FF7F1BD519A43DC968C1722F126CDD278403A78725FC5189" },
{ name = "gramps", version = "3.0.1", build_tools = ["gleam"], requirements = ["gleam_crypto", "gleam_erlang", "gleam_http", "gleam_stdlib"], otp_app = "gramps", source = "hex", outer_checksum = "59194B3980110B403EE6B75330DB82CDE05FC8138491C2EAEACBC7AAEF30B2E8" },
{ name = "hpack_erl", version = "0.3.0", build_tools = ["rebar3"], requirements = [], otp_app = "hpack", source = "hex", outer_checksum = "D6137D7079169D8C485C6962DFE261AF5B9EF60FBC557344511C1E65E3D95FB0" },
{ name = "logging", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "logging", source = "hex", outer_checksum = "1098FBF10B54B44C2C7FDF0B01C1253CAFACDACABEFB4B0D027803246753E06D" },
{ name = "marceau", version = "1.3.0", build_tools = ["gleam"], requirements = [], otp_app = "marceau", source = "hex", outer_checksum = "2D1C27504BEF45005F5DFB18591F8610FB4BFA91744878210BDC464412EC44E9" },
{ name = "mist", version = "4.0.6", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_http", "gleam_otp", "gleam_stdlib", "gleam_yielder", "glisten", "gramps", "hpack_erl", "logging"], otp_app = "mist", source = "hex", outer_checksum = "ED319E5A7F2056E08340B6976EA5E717F3C3BB36056219AF826D280D9C077952" },
{ name = "platform", version = "1.0.0", build_tools = ["gleam"], requirements = [], otp_app = "platform", source = "hex", outer_checksum = "8339420A95AD89AAC0F82F4C3DB8DD401041742D6C3F46132A8739F6AEB75391" },
{ name = "simplifile", version = "2.2.1", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "C88E0EE2D509F6D86EB55161D631657675AA7684DAB83822F7E59EB93D9A60E3" },
{ name = "telemetry", version = "1.3.0", build_tools = ["rebar3"], requirements = [], otp_app = "telemetry", source = "hex", outer_checksum = "7015FC8919DBE63764F4B4B87A95B7C0996BD539E0D499BE6EC9D7F3875B79E6" },
{ name = "wisp", version = "1.6.0", build_tools = ["gleam"], requirements = ["directories", "exception", "gleam_crypto", "gleam_erlang", "gleam_http", "gleam_json", "gleam_stdlib", "logging", "marceau", "mist", "simplifile"], otp_app = "wisp", source = "hex", outer_checksum = "AE1C568FE30718C358D3B37666DF0A0743ECD96094AD98C9F4921475075F660A" },
]

[requirements]
gleam_elli = { version = "~> 2.0" }
gleam_erlang = { version = "~> 0.17" }
gleam_http = { version = "~> 3.0" }
gleam_stdlib = { version = "~> 0.25 or ~> 1.0" }
envoy = { version = ">= 1.0.2 and < 2.0.0" }
gleam_erlang = { version = "~> 0.23" }
gleam_http = { version = "~> 3.5" }
gleam_stdlib = { version = "~> 0.38" }
gleeunit = { version = "~> 1.0" }
mist = { version = ">= 4.0.6 and < 5.0.0" }
wisp = { version = ">= 1.2.0 and < 2.0.0" }
26 changes: 14 additions & 12 deletions src/reply.gleam
Original file line number Diff line number Diff line change
@@ -1,26 +1,28 @@
import gleam/erlang/os
import envoy
import gleam/erlang/process
import gleam/http/elli
import gleam/int
import gleam/io
import gleam/result
import gleam/string
import reply/web
import mist
import reply/router
import wisp
import wisp/wisp_mist

pub fn main() {
wisp.configure_logger()

let port =
os.get_env("PORT")
envoy.get("PORT")
|> result.then(int.parse)
|> result.unwrap(3000)

let secret_key_base = wisp.random_string(64)

// Start the web server process
let assert Ok(_) =
web.stack()
|> elli.start(on_port: port)

["Started listening on localhost:", int.to_string(port), " ✨"]
|> string.concat
|> io.println
wisp_mist.handler(router.handle_request, secret_key_base)
|> mist.new
|> mist.port(port)
|> mist.start_http

// Put the main process to sleep while the web server does its thing
process.sleep_forever()
Expand Down
12 changes: 12 additions & 0 deletions src/reply/router.gleam
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import reply/web
import wisp.{type Request, type Response}

pub fn handle_request(req: Request) -> Response {
use req <- web.middleware(req)

case wisp.path_segments(req) {
["echo"] -> web.reply(req)
["hello", name] -> web.hello(name)
_ -> web.not_found()
}
}
82 changes: 43 additions & 39 deletions src/reply/web.gleam
Original file line number Diff line number Diff line change
@@ -1,58 +1,62 @@
import gleam/bit_array
import gleam/bytes_builder
import gleam/http.{Get, Post}
import gleam/http.{Post}
import gleam/http/request
import gleam/http/response
import gleam/http/service
import gleam/result
import gleam/string
import reply/web/logger
import wisp.{type Request, type Response}

fn reply(request) {
let content_type =
request
|> request.get_header("content-type")
|> result.unwrap("application/octet-stream")
pub fn middleware(
req: Request,
handle_request: fn(Request) -> Response,
) -> wisp.Response {
let req = wisp.method_override(req)
use <- wisp.log_request(req)
use <- wisp.rescue_crashes
use req <- wisp.handle_head(req)

response.new(200)
|> response.set_body(request.body)
|> response.prepend_header("content-type", content_type)
use <- default_responses

handle_request(req)
}

fn not_found() {
let body =
"There's nothing here. Try POSTing to /echo"
|> bit_array.from_string
pub fn default_responses(handle_request: fn() -> Response) {
let response = handle_request()

response.new(404)
|> response.set_body(body)
|> response.prepend_header("content-type", "text/plain")
response.set_header(response, "made-with", "Gleam")
}

fn hello(name) {
let reply = case string.lowercase(name) {
"mike" -> "Hello, Joe!"
_ -> string.concat(["Hello, ", name, "!"])
pub fn reply(request: Request) {
case request.method {
Post -> reply_post_response(request)
_ -> wisp.method_not_allowed([Post])
}

response.new(200)
|> response.set_body(bit_array.from_string(reply))
|> response.prepend_header("content-type", "text/plain")
}

pub fn service(request) {
let path = request.path_segments(request)
fn reply_post_response(request: Request) {
use body <- wisp.require_string_body(request)

let content_type =
request.get_header(request, "content-type")
|> result.unwrap("application/octet-stream")

wisp.ok()
|> wisp.set_header("content-type", content_type)
|> wisp.string_body(body)
}

case request.method, path {
Post, ["echo"] -> reply(request)
Get, ["hello", name] -> hello(name)
_, _ -> not_found()
pub fn hello(name) {
let reply = case string.lowercase(name) {
"mike" -> "Hello, Joe!"
_ -> string.concat(["Hello, ", name, "!"])
}

wisp.ok()
|> wisp.set_header("content-type", "text/plain")
|> wisp.string_body(reply)
}

pub fn stack() {
service
|> service.prepend_response_header("made-with", "Gleam")
|> service.map_response_body(bytes_builder.from_bit_array)
|> logger.middleware
pub fn not_found() {
wisp.not_found()
|> wisp.set_header("content-type", "text/plain")
|> wisp.string_body("There's nothing here. Try POSTing to /echo")
}
29 changes: 0 additions & 29 deletions src/reply/web/logger.gleam

This file was deleted.

Loading