diff options
author | Hayleigh Thompson <me@hayleigh.dev> | 2023-08-23 23:13:52 +0100 |
---|---|---|
committer | Hayleigh Thompson <me@hayleigh.dev> | 2023-08-23 23:13:52 +0100 |
commit | 6d295d0bcf23bb4410d6d93435ce53f9670a1d1c (patch) | |
tree | 33ac9652ed41109d425210fabdaf638f92952f0b | |
parent | c0a3607d41dd24b9ea03425892a361261893d076 (diff) | |
download | lustre-6d295d0bcf23bb4410d6d93435ce53f9670a1d1c.tar.gz lustre-6d295d0bcf23bb4410d6d93435ce53f9670a1d1c.zip |
:ambulance: Update third-party lustre_http package to new api.
-rw-r--r-- | compat/lustre_http/.gitignore | 2 | ||||
-rw-r--r-- | compat/lustre_http/README.md | 17 | ||||
-rw-r--r-- | compat/lustre_http/gleam.toml | 16 | ||||
-rw-r--r-- | compat/lustre_http/manifest.toml | 16 | ||||
-rw-r--r-- | compat/lustre_http/src/ffi.mjs | 16 | ||||
-rw-r--r-- | compat/lustre_http/src/lustre_http.gleam | 126 | ||||
-rw-r--r-- | compat/lustre_http/test/lustre_http_test.gleam | 15 |
7 files changed, 208 insertions, 0 deletions
diff --git a/compat/lustre_http/.gitignore b/compat/lustre_http/.gitignore new file mode 100644 index 0000000..e03d74b --- /dev/null +++ b/compat/lustre_http/.gitignore @@ -0,0 +1,2 @@ +build +*tar diff --git a/compat/lustre_http/README.md b/compat/lustre_http/README.md new file mode 100644 index 0000000..1117b93 --- /dev/null +++ b/compat/lustre_http/README.md @@ -0,0 +1,17 @@ +# lustre_http + +[](https://hex.pm/packages/lustre_http) +[](https://hexdocs.pm/lustre_http/) + +Make HTTP requests from `lustre` via its `cmd` interface. +Makes life easy when such requests are initiated by the user. + +## Quick start + +Add to your Gleam project: + +```sh +gleam add lustre_http +``` + +View the documentation at <https://hexdocs.pm/lustre_http>, although only `get_as_text` is documented a.t.m. diff --git a/compat/lustre_http/gleam.toml b/compat/lustre_http/gleam.toml new file mode 100644 index 0000000..19bf4bc --- /dev/null +++ b/compat/lustre_http/gleam.toml @@ -0,0 +1,16 @@ +name = "lustre_http" +version = "0.3.0" +target = "javascript" + +licences = ["MIT"] +description = "HTTP requests from lustre" +repository = { type = "custom", url = "https://git.chmeee.org/lustre_http" } +links = [{ title = "Package", href = "https://hex.pm/packages/lustre_http" }] + +[dependencies] +gleam_stdlib = "~> 0.30" +gleam_json = "~> 0.6" +lustre = { path = "../../lib" } + +[dev-dependencies] +gleeunit = "~> 0.10"
\ No newline at end of file diff --git a/compat/lustre_http/manifest.toml b/compat/lustre_http/manifest.toml new file mode 100644 index 0000000..7b77a95 --- /dev/null +++ b/compat/lustre_http/manifest.toml @@ -0,0 +1,16 @@ +# This file was generated by Gleam +# You typically do not need to edit this file + +packages = [ + { name = "gleam_json", version = "0.6.0", build_tools = ["gleam"], requirements = ["thoas", "gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "C6CC5BEECA525117E97D0905013AB3F8836537455645DDDD10FE31A511B195EF" }, + { name = "gleam_stdlib", version = "0.30.1", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "704258528887F95075FFED7AAE1CCF836A9B88E3AADA2F69F9DA15815F94A4F9" }, + { name = "gleeunit", version = "0.11.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "1397E5C4AC4108769EE979939AC39BF7870659C5AFB714630DEEEE16B8272AD5" }, + { name = "lustre", version = "3.0.0-rc.8", build_tools = ["gleam"], requirements = ["gleam_stdlib"], source = "local", path = "/Users/hayleigh/dev/gleam/lustre/lib" }, + { name = "thoas", version = "0.4.1", build_tools = ["rebar3"], requirements = [], otp_app = "thoas", source = "hex", outer_checksum = "4918D50026C073C4AB1388437132C77A6F6F7C8AC43C60C13758CC0ADCE2134E" }, +] + +[requirements] +gleam_json = { version = "~> 0.6" } +gleam_stdlib = { version = "~> 0.30" } +gleeunit = { version = "~> 0.10" } +lustre = { path = "../../lib" } diff --git a/compat/lustre_http/src/ffi.mjs b/compat/lustre_http/src/ffi.mjs new file mode 100644 index 0000000..bb01b09 --- /dev/null +++ b/compat/lustre_http/src/ffi.mjs @@ -0,0 +1,16 @@ +export const do_request = (method, url, body, on_success, on_error) => { + let xhr = new XMLHttpRequest() + xhr.onerror = _evt => { + console.log("error for", method, url, ":", xhr) + on_error(888, "oops!") + } + xhr.onloadend = _evt => { + switch (xhr.status) { + case 200: + case 204: on_success(xhr.responseText); break; + default: on_error(xhr.status, xhr.responseText) + } + } + xhr.open(method, url) + xhr.send(body); +} diff --git a/compat/lustre_http/src/lustre_http.gleam b/compat/lustre_http/src/lustre_http.gleam new file mode 100644 index 0000000..a066faa --- /dev/null +++ b/compat/lustre_http/src/lustre_http.gleam @@ -0,0 +1,126 @@ +import gleam/json +import lustre/effect.{Effect} + +pub type HttpError { + Unauthorized + NotFound + InternalServerError(String) + OtherError(Int, String) +} + +pub type StringResult = + Result(String, HttpError) + +pub type HttpOrJsonError { + H(HttpError) + J(json.DecodeError) +} + +pub type JsonResult(t) = + Result(t, HttpOrJsonError) + +external fn do_request( + method: String, + url: String, + body: String, + on_success: fn(String) -> Nil, + on_error: fn(Int, String) -> Nil, +) -> Nil = + "./ffi.mjs" "do_request" + +fn do_get(url, on_success, on_error) { + do_request("GET", url, "", on_success, on_error) +} + +fn do_post(url, body, on_success, on_error) { + do_request("POST", url, body, on_success, on_error) +} + +/// ### Usage +/// ``` +/// import lustre_http as http +/// +/// type Msg { +/// SomeInteraction +/// TextReceived(StringResult) +/// } +/// +/// pub fn update(model, msg) { +/// case msg { +/// SomeInteraction -> #(model, http.get_as_text("the_text", TextReceived)) +/// TextReceived(Ok(text)) -> #(apply(text, model), effect.none()) +/// TextReceived(Error(e)) -> #(indicate_problem(e, model), effect.none()) +/// } +/// } +/// ``` +pub fn get_as_text(url: String, to_msg: fn(StringResult) -> msg) -> Effect(msg) { + use dispatch <- effect.from + + do_get( + url, + fn(body) { dispatch(to_msg(Ok(body))) }, + fn(code, msg) { + decode_error(code, msg) + |> Error + |> to_msg + |> dispatch + }, + ) +} + +fn decode_error(code, msg) { + case code { + 401 -> Unauthorized + 404 -> NotFound + 500 -> InternalServerError(msg) + _ -> OtherError(code, msg) + } +} + +/// Will automatically try to decode the JSON for you. +/// The error-type is a bit complicated. In a future version will probably +/// (a) force "text/json" in the headers (b) not decode for you. +pub fn get_as_json( + url: String, + to_msg: fn(JsonResult(String)) -> msg, + decoder, +) -> Effect(msg) { + use dispatch <- effect.from + + do_get( + url, + fn(body) { + case json.decode(from: body, using: decoder) { + Ok(json) -> dispatch(to_msg(Ok(json))) + Error(json_error) -> dispatch(to_msg(Error(J(json_error)))) + } + }, + fn(code, msg) { + let http_error = case code { + 401 -> Unauthorized + 404 -> NotFound + 500 -> InternalServerError(msg) + _ -> OtherError(code, msg) + } + dispatch(to_msg(Error(H(http_error)))) + }, + ) +} + +/// Future versions will force headers in both the request and the response +/// so you can post json and receive text, post text and receive json, etc. +pub fn post_text(url: String, body: String, to_msg: fn(StringResult) -> msg) { + use dispatch <- effect.from + + do_post( + url, + body, + fn(body) { dispatch(to_msg(Ok(body))) }, + fn(code, msg) { + decode_error(code, msg) + |> Error + |> to_msg + |> dispatch + }, + ) +} diff --git a/compat/lustre_http/test/lustre_http_test.gleam b/compat/lustre_http/test/lustre_http_test.gleam new file mode 100644 index 0000000..e426a70 --- /dev/null +++ b/compat/lustre_http/test/lustre_http_test.gleam @@ -0,0 +1,15 @@ +import lustre_http as http +import gleeunit + +pub fn main() { + gleeunit.main() +} + +pub type ToMsgProvider { + Wrapper(http.StringResult) +} + +// We cannot run the resulting lustre.Cmd, but we can at least ensure it can be used/compiled this way +pub fn compilation_test() { + http.get_as_text("http://localhost:8080/not_here", Wrapper) +} |