From 8eef034e6d7f551b5f092d87e54fa7a52da35b81 Mon Sep 17 00:00:00 2001 From: Eileen Noonan Date: Sat, 23 Mar 2024 16:58:34 -0400 Subject: =?UTF-8?q?=F0=9F=94=80=20Write=20docs=20for=2005-http-requests.?= =?UTF-8?q?=20(#74)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/05-http-requests/README.md | 55 ++++++++++++++++++++++++++++++--- examples/05-http-requests/gleam.toml | 4 +-- examples/05-http-requests/manifest.toml | 14 ++++----- 3 files changed, 59 insertions(+), 14 deletions(-) diff --git a/examples/05-http-requests/README.md b/examples/05-http-requests/README.md index 2773713..f0ef1ee 100644 --- a/examples/05-http-requests/README.md +++ b/examples/05-http-requests/README.md @@ -1,15 +1,60 @@ ![](./header.png) -# 04 HTTP Requests +# 05 HTTP Requests > **Note**: this guide is written for Lustre v4. The latest stable release of > Lustre is v3. To follow along with this guide, you need to _manually_ edit your > `gleam.toml` and change the required version of lustre to `"4.0.0-rc.2"`. -We haven't quite got round to documenting this example yet. If you know a little -bit about Lustre or Elm and want to help out, we'd love to have your help! Please -[open an issue](https://github.com/lustre-labs/lustre/issues/new) if you have any -ideas or reach out to @hayleigh.dev on the [Gleam discord](https://discord.gg/Fm8Pwmy). +Up until now, all the logic in our examples has run neatly in a self-contained `Init -> Update 🔁 View` loop. But our applications often need to interact with the outside world, whether through browser APIs or HTTP requests. + +For this, Lustre provides an `Effect` system. You should [read the docs on Lustre Effects](https://hexdocs.pm/lustre/4.0.0-rc1/lustre/effect.html) before continuing here. + +... did you read the docs? Ok, let's move on! + +## The #(model, effect) Tuple +You'll notice that running a Lustre app with side effects _changes the signature_ of our [`init`](src/app.gleam#L43) and [`update`](src/app.gleam#L54) functions. Instead of returning just a model, we return a tuple containing both a model and an `Effect(Msg)` value. The effect value specifies any further updates we might want the Lustre runtime to execute before the next invocation of the `view` function. + +```gleam +fn init(_) -> #(Model, Effect(Msg)) { + #(Model(quote: None), effect.none()) +} + +fn update(model: Model, msg: Msg) -> #(Model, Effect(Msg)) { + case msg { + Refresh -> #(model, get_quote()) + GotQuote(Ok(quote)) -> #(Model(quote: Some(quote)), effect.none()) + GotQuote(Error(_)) -> #(model, effect.none()) + } +} + +fn get_quote() -> Effect(Msg) { ... } +``` + +> **Note:** Even in an app with side effects, the `view` function signature does not change. In Lustre, the view function is always [pure](https://en.wikipedia.org/wiki/Pure_function), accepting only a `Model` and returning only an `Element` without triggering any effects itself. + +## HTTP Requests are Effects + +As we touched on before, an HTTP Request is a form of effect, because it means our program needs to interact with the outside world. + +In this example, we use the great community library `lustre_http` to fetch a random quote whenever the user clicks the "New Quote" button. [Check out the lustre_http docs here.](https://hexdocs.pm/lustre_http/lustre_http.html) + +```gleam +fn get_quote() -> Effect(Msg) { + let url = "https://api.quotable.io/random" + let decoder = + dynamic.decode2( + Quote, + dynamic.field("author", dynamic.string), + dynamic.field("content", dynamic.string), + ) + + lustre_http.get(url, lustre_http.expect_json(decoder, GotQuote)) +} +``` + +The `lustre_http.get(...)` function does a _lot_. That second parameter specifies not only what type of response to expect, but also how to decode it, what type to decode it _into_, as well as the `Msg` type that should be sent back to the Lustre runtime after it successfully executes. + ## Getting help diff --git a/examples/05-http-requests/gleam.toml b/examples/05-http-requests/gleam.toml index 96b9a10..3e5031b 100644 --- a/examples/05-http-requests/gleam.toml +++ b/examples/05-http-requests/gleam.toml @@ -4,9 +4,9 @@ target = "javascript" [dependencies] gleam_stdlib = "~> 0.34 or ~> 1.0" -lustre = { path = "../../" } +lustre = "4.0.0-rc.1" lustre_ui = "~> 0.4" -lustre_http = "~> 0.5" +lustre_http = "~> 0.5.2" [dev-dependencies] gleeunit = "~> 1.0" diff --git a/examples/05-http-requests/manifest.toml b/examples/05-http-requests/manifest.toml index 62f6791..c2e423c 100644 --- a/examples/05-http-requests/manifest.toml +++ b/examples/05-http-requests/manifest.toml @@ -2,27 +2,27 @@ # You typically do not need to edit this file packages = [ - { name = "argv", version = "1.0.1", build_tools = ["gleam"], requirements = [], otp_app = "argv", source = "hex", outer_checksum = "A6E9009E50BBE863EB37D963E4315398D41A3D87D0075480FC244125808F964A" }, + { name = "argv", version = "1.0.2", build_tools = ["gleam"], requirements = [], otp_app = "argv", source = "hex", outer_checksum = "BA1FF0929525DEBA1CE67256E5ADF77A7CDDFE729E3E3F57A5BDCAA031DED09D" }, { name = "filepath", version = "0.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "FC1B1B29438A5BA6C990F8047A011430BEC0C5BA638BFAA62718C4EAEFE00435" }, { name = "gleam_community_ansi", version = "1.4.0", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_stdlib"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "FE79E08BF97009729259B6357EC058315B6FBB916FAD1C2FF9355115FEB0D3A4" }, { name = "gleam_community_colour", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_community_colour", source = "hex", outer_checksum = "A49A5E3AE8B637A5ACBA80ECB9B1AFE89FD3D5351FF6410A42B84F666D40D7D5" }, - { name = "gleam_erlang", version = "0.24.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "26BDB52E61889F56A291CB34167315780EE4AA20961917314446542C90D1C1A0" }, + { name = "gleam_erlang", version = "0.25.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "054D571A7092D2A9727B3E5D183B7507DAB0DA41556EC9133606F09C15497373" }, { name = "gleam_fetch", version = "0.4.0", build_tools = ["gleam"], requirements = ["gleam_http", "gleam_javascript", "gleam_stdlib"], otp_app = "gleam_fetch", source = "hex", outer_checksum = "7446410A44A1D1328F5BC1FF4FC9CBD1570479EA69349237B3F82E34521CCC10" }, { name = "gleam_http", version = "3.6.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_http", source = "hex", outer_checksum = "8C07DF9DF8CC7F054C650839A51C30A7D3C26482AC241C899C1CEA86B22DBE51" }, { name = "gleam_javascript", version = "0.8.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_javascript", source = "hex", outer_checksum = "14D5B7E1A70681E0776BF0A0357F575B822167960C844D3D3FA114D3A75F05A8" }, { name = "gleam_json", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "thoas"], otp_app = "gleam_json", source = "hex", outer_checksum = "8B197DD5D578EA6AC2C0D4BDC634C71A5BCA8E7DB5F47091C263ECB411A60DF3" }, { 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_package_interface", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_package_interface", source = "hex", outer_checksum = "52A721BCA972C8099BB881195D821AAA64B9F2655BECC102165D5A1097731F01" }, { name = "gleam_stdlib", version = "0.36.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "C0D14D807FEC6F8A08A7C9EF8DFDE6AE5C10E40E21325B2B29365965D82EB3D4" }, { name = "glearray", version = "0.2.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glearray", source = "hex", outer_checksum = "908154F695D330E06A37FAB2C04119E8F315D643206F8F32B6A6C14A8709FFF4" }, { name = "gleeunit", version = "1.0.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "D364C87AFEB26BDB4FB8A5ABDE67D635DC9FA52D6AB68416044C35B096C6882D" }, { name = "glint", version = "0.16.0", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_community_colour", "gleam_stdlib", "snag"], otp_app = "glint", source = "hex", outer_checksum = "61B7E85CBB0CCD2FD8A9C7AE06CA97A80BF6537716F34362A39DF9C74967BBBC" }, { name = "justin", version = "1.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "justin", source = "hex", outer_checksum = "7FA0C6DB78640C6DC5FBFD59BF3456009F3F8B485BF6825E97E1EB44E9A1E2CD" }, - { name = "lustre", version = "4.0.0-rc.2", build_tools = ["gleam"], requirements = ["argv", "filepath", "gleam_community_ansi", "gleam_erlang", "gleam_json", "gleam_otp", "gleam_package_interface", "gleam_stdlib", "glint", "justin", "simplifile", "spinner", "tom"], source = "local", path = "../.." }, + { name = "lustre", version = "4.0.0-rc.2", build_tools = ["gleam"], requirements = ["argv", "filepath", "gleam_community_ansi", "gleam_erlang", "gleam_json", "gleam_otp", "gleam_stdlib", "glint", "justin", "shellout", "simplifile", "spinner", "tom"], otp_app = "lustre", source = "hex", outer_checksum = "3A603D4333E73D481D9F753D6750DA8AD408C84C66082BA6653B3691C8E17A63" }, { name = "lustre_http", version = "0.5.2", build_tools = ["gleam"], requirements = ["gleam_fetch", "gleam_http", "gleam_javascript", "gleam_json", "gleam_stdlib", "lustre"], otp_app = "lustre_http", source = "hex", outer_checksum = "FB0478CBFA6B16DBE8ECA326DAE2EC15645E04900595EF2C4F039ABFA0512ABA" }, { name = "lustre_ui", version = "0.4.0", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_stdlib", "lustre"], otp_app = "lustre_ui", source = "hex", outer_checksum = "9FE07E26EABDB13F7CB29F90AD8763618040729BF16E5F451A6ED584C52AA093" }, { name = "repeatedly", version = "2.1.1", build_tools = ["gleam"], requirements = [], otp_app = "repeatedly", source = "hex", outer_checksum = "38808C3EC382B0CD981336D5879C24ECB37FCB9C1D1BD128F7A80B0F74404D79" }, - { name = "simplifile", version = "1.5.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "EB9AA8E65E5C1E3E0FDCFC81BC363FD433CB122D7D062750FFDF24DE4AC40116" }, + { name = "shellout", version = "1.6.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "shellout", source = "hex", outer_checksum = "E2FCD18957F0E9F67E1F497FC9FF57393392F8A9BAEAEA4779541DE7A68DD7E0" }, + { name = "simplifile", version = "1.5.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "C44DB387524F90DC42142699C78C850003289D32C7C99C7D32873792A299CDF7" }, { name = "snag", version = "0.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "snag", source = "hex", outer_checksum = "54D32E16E33655346AA3E66CBA7E191DE0A8793D2C05284E3EFB90AD2CE92BCC" }, { name = "spinner", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_erlang", "gleam_stdlib", "glearray", "repeatedly"], otp_app = "spinner", source = "hex", outer_checksum = "200BA3D4A04D468898E63C0D316E23F526E02514BC46454091975CB5BAE41E8F" }, { name = "thoas", version = "0.4.1", build_tools = ["rebar3"], requirements = [], otp_app = "thoas", source = "hex", outer_checksum = "4918D50026C073C4AB1388437132C77A6F6F7C8AC43C60C13758CC0ADCE2134E" }, @@ -32,6 +32,6 @@ packages = [ [requirements] gleam_stdlib = { version = "~> 0.34 or ~> 1.0" } gleeunit = { version = "~> 1.0" } -lustre = { path = "../../" } -lustre_http = { version = "~> 0.5" } +lustre = { version = "4.0.0-rc.1" } +lustre_http = { version = "~> 0.5.2" } lustre_ui = { version = "~> 0.4" } -- cgit v1.2.3