aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHayleigh Thompson <me@hayleigh.dev>2023-08-23 23:13:52 +0100
committerHayleigh Thompson <me@hayleigh.dev>2023-08-23 23:13:52 +0100
commit6d295d0bcf23bb4410d6d93435ce53f9670a1d1c (patch)
tree33ac9652ed41109d425210fabdaf638f92952f0b
parentc0a3607d41dd24b9ea03425892a361261893d076 (diff)
downloadlustre-6d295d0bcf23bb4410d6d93435ce53f9670a1d1c.tar.gz
lustre-6d295d0bcf23bb4410d6d93435ce53f9670a1d1c.zip
:ambulance: Update third-party lustre_http package to new api.
-rw-r--r--compat/lustre_http/.gitignore2
-rw-r--r--compat/lustre_http/README.md17
-rw-r--r--compat/lustre_http/gleam.toml16
-rw-r--r--compat/lustre_http/manifest.toml16
-rw-r--r--compat/lustre_http/src/ffi.mjs16
-rw-r--r--compat/lustre_http/src/lustre_http.gleam126
-rw-r--r--compat/lustre_http/test/lustre_http_test.gleam15
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
+
+[![Package Version](https://img.shields.io/hexpm/v/lustre_http)](https://hex.pm/packages/lustre_http)
+[![Hex Docs](https://img.shields.io/badge/hex-docs-ffaff3)](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)
+}