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@v3
- uses: erlef/setup-beam@v1
with:
otp-version: "26.1"
gleam-version: "1.4.0"
otp-version: "27.1"
gleam-version: "1.10.0"
rebar3-version: "3"
- run: gleam test
- run: gleam format --check src test
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ gleam add gleam_elli gleam_http
import gleam/http/elli
import gleam/http/request.{type Request}
import gleam/http/response.{type Response}
import gleam/bytes_builder.{type BytesBuilder}
import gleam/bytes_tree.{type BytesTree}

// Define a HTTP service
//
pub fn my_service(req: Request(t)) -> Response(BytesBuilder) {
let body = bytes_builder.from_string("Hello, world!")
let body = bytes_tree.from_string("Hello, world!")

response.new(200)
|> response.prepend_header("made-with", "Gleam")
Expand Down
12 changes: 6 additions & 6 deletions gleam.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name = "gleam_elli"
version = "2.4.2"
gleam = ">= 1.4.0"
version = "3.0.0"
gleam = ">= 1.10.0"

licences = ["Apache-2.0"]
description = "Run Gleam HTTP services with the Elli web server"
Expand All @@ -12,10 +12,10 @@ links = [
]

[dependencies]
gleam_erlang = "~> 0.23"
gleam_stdlib = "~> 0.42"
gleam_http = "~> 3.0"
gleam_otp = "~> 0.3"
gleam_erlang = ">= 0.34.0 and < 1.0.0"
gleam_otp = ">= 0.16.1 and < 1.0.0"
gleam_stdlib = ">= 0.44.0 and < 2.0.0"
gleam_http = ">= 4.0.0 and < 5.0.0"
elli = "~> 3.0"

[dev-dependencies]
Expand Down
28 changes: 14 additions & 14 deletions manifest.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,28 @@
# You typically do not need to edit this file

packages = [
{ name = "certifi", version = "2.12.0", build_tools = ["rebar3"], requirements = [], otp_app = "certifi", source = "hex", outer_checksum = "EE68D85DF22E554040CDB4BE100F33873AC6051387BAF6A8F6CE82272340FF1C" },
{ name = "certifi", version = "2.15.0", build_tools = ["rebar3"], requirements = [], otp_app = "certifi", source = "hex", outer_checksum = "B147ED22CE71D72EAFDAD94F055165C1C182F61A2FF49DF28BCC71D1D5B94A60" },
{ name = "elli", version = "3.3.0", build_tools = ["rebar3"], requirements = [], otp_app = "elli", source = "hex", outer_checksum = "698B13B33D05661DB9FE7EFCBA41B84825A379CCE86E486CF6AFF9285BE0CCF8" },
{ name = "gleam_erlang", version = "0.30.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "760618870AE4A497B10C73548E6E44F43B76292A54F0207B3771CBB599C675B4" },
{ name = "gleam_hackney", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_http", "gleam_stdlib", "hackney"], otp_app = "gleam_hackney", source = "hex", outer_checksum = "066B1A55D37DBD61CC72A1C4EDE43C6015B1797FAF3818C16FE476534C7B6505" },
{ name = "gleam_http", version = "3.7.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_http", source = "hex", outer_checksum = "A9EE0722106FCCAB8AD3BF9D0A3EFF92BFE8561D59B83BAE96EB0BE1938D4E0F" },
{ name = "gleam_otp", version = "0.14.1", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "5A8CE8DBD01C29403390A7BD5C0A63D26F865C83173CF9708E6E827E53159C65" },
{ name = "gleam_stdlib", version = "0.43.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "69EF22E78FDCA9097CBE7DF91C05B2A8B5436826D9F66680D879182C0860A747" },
{ name = "gleeunit", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "F7A7228925D3EE7D0813C922E062BFD6D7E9310F0BEE585D3A42F3307E3CFD13" },
{ name = "hackney", version = "1.20.1", build_tools = ["rebar3"], requirements = ["certifi", "idna", "metrics", "mimerl", "parse_trans", "ssl_verify_fun", "unicode_util_compat"], otp_app = "hackney", source = "hex", outer_checksum = "FE9094E5F1A2A2C0A7D10918FEE36BFEC0EC2A979994CFF8CFE8058CD9AF38E3" },
{ name = "gleam_erlang", version = "0.34.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "0C38F2A128BAA0CEF17C3000BD2097EB80634E239CE31A86400C4416A5D0FDCC" },
{ name = "gleam_hackney", version = "1.3.1", build_tools = ["gleam"], requirements = ["gleam_http", "gleam_stdlib", "hackney"], otp_app = "gleam_hackney", source = "hex", outer_checksum = "0449AADBEBF3E979509A4079EE34B92EEE4162C5A0DC94F3DA2787E4777F6B45" },
{ name = "gleam_http", version = "4.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_http", source = "hex", outer_checksum = "0A62451FC85B98062E0907659D92E6A89F5F3C0FBE4AB8046C99936BF6F91DBC" },
{ 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.60.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "621D600BB134BC239CB2537630899817B1A42E60A1D46C5E9F3FAE39F88C800B" },
{ name = "gleeunit", version = "1.3.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "A7DD6C07B7DA49A6E28796058AA89E651D233B357D5607006D70619CD89DAAAB" },
{ name = "hackney", version = "1.24.1", build_tools = ["rebar3"], requirements = ["certifi", "idna", "metrics", "mimerl", "parse_trans", "ssl_verify_fun", "unicode_util_compat"], otp_app = "hackney", source = "hex", outer_checksum = "F4A7392A0B53D8BBC3EB855BDCC919CD677358E65B2AFD3840B5B3690C4C8A39" },
{ name = "idna", version = "6.1.1", build_tools = ["rebar3"], requirements = ["unicode_util_compat"], otp_app = "idna", source = "hex", outer_checksum = "92376EB7894412ED19AC475E4A86F7B413C1B9FBB5BD16DCCD57934157944CEA" },
{ name = "metrics", version = "1.0.1", build_tools = ["rebar3"], requirements = [], otp_app = "metrics", source = "hex", outer_checksum = "69B09ADDDC4F74A40716AE54D140F93BEB0FB8978D8636EADED0C31B6F099F16" },
{ name = "mimerl", version = "1.3.0", build_tools = ["rebar3"], requirements = [], otp_app = "mimerl", source = "hex", outer_checksum = "A1E15A50D1887217DE95F0B9B0793E32853F7C258A5CD227650889B38839FE9D" },
{ name = "mimerl", version = "1.4.0", build_tools = ["rebar3"], requirements = [], otp_app = "mimerl", source = "hex", outer_checksum = "13AF15F9F68C65884ECCA3A3891D50A7B57D82152792F3E19D88650AA126B144" },
{ name = "parse_trans", version = "3.4.1", build_tools = ["rebar3"], requirements = [], otp_app = "parse_trans", source = "hex", outer_checksum = "620A406CE75DADA827B82E453C19CF06776BE266F5A67CFF34E1EF2CBB60E49A" },
{ name = "ssl_verify_fun", version = "1.1.7", build_tools = ["mix", "rebar3", "make"], requirements = [], otp_app = "ssl_verify_fun", source = "hex", outer_checksum = "FE4C190E8F37401D30167C8C405EDA19469F34577987C76DDE613E838BBC67F8" },
{ name = "unicode_util_compat", version = "0.7.0", build_tools = ["rebar3"], requirements = [], otp_app = "unicode_util_compat", source = "hex", outer_checksum = "25EEE6D67DF61960CF6A794239566599B09E17E668D3700247BC498638152521" },
{ name = "unicode_util_compat", version = "0.7.1", build_tools = ["rebar3"], requirements = [], otp_app = "unicode_util_compat", source = "hex", outer_checksum = "B3A917854CE3AE233619744AD1E0102E05673136776FB2FA76234F3E03B23642" },
]

[requirements]
elli = { version = "~> 3.0" }
gleam_erlang = { version = "~> 0.23" }
gleam_erlang = { version = ">= 0.34.0 and < 1.0.0" }
gleam_hackney = { version = "~> 1.0" }
gleam_http = { version = "~> 3.0" }
gleam_otp = { version = "~> 0.3" }
gleam_stdlib = { version = "~> 0.42" }
gleam_http = { version = ">= 4.0.0 and < 5.0.0" }
gleam_otp = { version = ">= 0.16.1 and < 1.0.0" }
gleam_stdlib = { version = ">= 0.44.0 and < 2.0.0" }
gleeunit = { version = "~> 1.0" }
56 changes: 46 additions & 10 deletions src/gleam/http/elli.gleam
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import gleam/bytes_tree.{type BytesTree}
import gleam/dynamic.{type Dynamic}
import gleam/dynamic/decode
import gleam/erlang/atom.{type Atom}
import gleam/erlang/process.{type Pid}
import gleam/http
Expand All @@ -22,6 +23,18 @@ type StartLinkOption {
Port(Int)
}

type ElliMethod {
Get
Post
Head
Put
Delete
Trace
Connect
Options
Patch
}

@external(erlang, "binary", "split")
fn split(a: String, b: List(String)) -> List(String)

Expand All @@ -37,14 +50,23 @@ fn get_headers(a: ElliRequest) -> List(http.Header)
@external(erlang, "gleam_elli_native", "get_host")
fn get_host(a: ElliRequest) -> String

@external(erlang, "elli_request", "method")
fn get_dynamic_method(a: ElliRequest) -> Dynamic

fn get_method(req) {
req
|> get_dynamic_method
|> http.method_from_dynamic
|> result.unwrap(http.Get)
@external(erlang, "gleam_elli_native", "get_method")
fn get_elli_method(a: ElliRequest) -> Result(ElliMethod, Nil)

fn get_method(req) -> http.Method {
case get_elli_method(req) {
Ok(Trace) -> http.Trace
Ok(Put) -> http.Put
Ok(Post) -> http.Post
Ok(Patch) -> http.Patch
Ok(Options) -> http.Options
Ok(Head) -> http.Head
Ok(Get) -> http.Get
Ok(Delete) -> http.Delete
Ok(Connect) -> http.Connect
// FIXME: Don't just default, ensure this isn't reachable.
_ -> http.Other("unknown")
}
}

@external(erlang, "elli_request", "port")
Expand All @@ -53,7 +75,7 @@ fn get_dynamic_port(a: ElliRequest) -> Dynamic
fn get_port(req) {
req
|> get_dynamic_port
|> dynamic.int
|> decode.run(decode.int)
|> option.from_result
}

Expand All @@ -64,7 +86,7 @@ fn get_scheme(req) -> http.Scheme {
let scheme =
req
|> get_dynamic_scheme
|> dynamic.string
|> decode.run(decode.string)
|> result.unwrap("")
|> string.lowercase
case scheme {
Expand All @@ -73,6 +95,20 @@ fn get_scheme(req) -> http.Scheme {
}
}

// pub fn method_from_dynamic(
// value: Dynamic,
// ) -> Result(Method, List(decode.DecodeError)) {
// case do_method_from_dynamic(value) {
// Ok(method) -> Ok(method)
// Error(_) ->
// Error([decode.DecodeError("HTTP method", dynamic.classify(value), [])])
// }
// }

// @target(erlang)
// @external(erlang, "gleam_http_native", "decode_method")
// fn do_method_from_dynamic(a: Dynamic) -> Result(ElliMethod, nil)

@external(erlang, "elli_request", "query_str")
fn get_query(a: ElliRequest) -> String

Expand Down
16 changes: 15 additions & 1 deletion src/gleam_elli_native.erl
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
-include_lib("kernel/include/logger.hrl").
-include_lib("elli/include/elli.hrl").

-export([handle/2, handle_event/3, await_shutdown/1, get_host/1]).
-export([handle/2, handle_event/3, await_shutdown/1, get_host/1, get_method/1]).

handle(Req, Handler) ->
Handler(Req).
Expand Down Expand Up @@ -47,6 +47,20 @@ get_host(Request) ->
Host when is_binary(Host) -> Host
end.

get_method(#req{method = Method}) ->
case Method of
'CONNECT' -> {ok, connect};
'DELETE' -> {ok, delete};
'GET' -> {ok, get};
'HEAD' -> {ok, head};
'OPTIONS' -> {ok, options};
'PATCH' -> {ok, patch};
'POST' -> {ok, post};
'PUT' -> {ok, put};
'TRACE' -> {ok, trace};
_ -> {error, nil}
end.

path(#req{path = Path}) ->
erlang:iolist_to_binary(["/"] ++ lists:join("/", Path)).

Expand Down
7 changes: 4 additions & 3 deletions test/gleam/http/elli_logging_test.gleam
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import gleam/bytes_tree.{type BytesTree}
import gleam/dict.{type Dict}
import gleam/dynamic.{type DecodeError, type Dynamic}
import gleam/dynamic.{type Dynamic}
import gleam/dynamic/decode.{type DecodeError}
import gleam/erlang/atom.{type Atom}
import gleam/hackney
import gleam/http.{type Method, Get, Post, Put}
Expand Down Expand Up @@ -120,7 +121,7 @@ fn get_string(
) -> Result(String, List(DecodeError)) {
dict.get(report, key)
|> result.map_error(fn(_) { [] })
|> result.then(dynamic.string)
|> result.then(decode.run(_, decode.string))
}

fn list_length(
Expand All @@ -129,7 +130,7 @@ fn list_length(
) -> Result(Int, List(DecodeError)) {
dict.get(report, key)
|> result.map_error(fn(_) { [] })
|> result.then(dynamic.shallow_list)
|> result.then(decode.run(_, decode.list(decode.dynamic)))
|> result.map(list.length)
}

Expand Down