🧚 A practical web framework for Gleam

Wobsite

Changed files
+193 -12
docs
+1 -1
README.md
··· 50 50 } 51 51 ``` 52 52 53 - # Documentation 53 + # Learning Wisp 54 54 55 55 The Wisp examples are a good place to start. They cover various scenarios and 56 56 include comments and tests.
+121 -5
docs/index.html
··· 1 1 <!DOCTYPE html> 2 2 <html lang="en"> 3 + 3 4 <head> 4 5 <meta charset="UTF-8"> 5 6 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 - <title>Wisp - A practical Gleam web framework</title> 7 + <title>Wisp - A practical web framework for Gleam</title> 7 8 <link rel="stylesheet" href="style.css"> 8 9 </head> 10 + 9 11 <body> 10 - <img class="hero-wordmark" src="./images/wordmark.svg" alt="Wisp"> 11 - <nav> 12 - <a href="https://github.com/lpil/wisp">GitHub</a> 13 - </nav> 12 + <section class="home-hero"> 13 + <nav> 14 + <a href="https://github.com/lpil/wisp">Source & Guides</a> 15 + <a href="https://hexdocs.pm/wisp">API Docs</a> 16 + <a href="https://github.com/sponsors/lpil">Sponsor</a> 17 + </nav> 18 + <img src="./images/wordmark.svg" alt="Wisp"> 19 + <p> 20 + A practical web framework for Gleam 21 + </p> 22 + </section> 23 + 24 + <ul class="content-width features"> 25 + <li> 26 + 27 + <h2> 28 + Perfectly productive 29 + </h2> 30 + <p> 31 + Wisp is simple, type safe, and entirely free from confusing magic. Make 32 + development as stress-free as possible whether you're starting a new 33 + prototype or maintaining a large system. 34 + </p> 35 + </li> 36 + 37 + <li> 38 + <h2> 39 + Flipping fast 40 + </h2> 41 + <p> 42 + Thanks to the Mist HTTP server and the mighty multithreaded BEAM 43 + runtime Wisp applications are fast, even at the 99th percentile during a 44 + big burst of traffic. In benchmarks Wisp can outperform Go, NodeJS, and 45 + Elixir Phoenix + Cowboy. 46 + </p> 47 + </li> 48 + 49 + <li> 50 + <h2> 51 + Totally testable 52 + </h2> 53 + <p> 54 + If your application matters then you're going to want to test it. A Wisp 55 + web application is as easy to test as any regular Gleam function, and an 56 + assortment of useful test helpers are provided to keep your tests 57 + concise. 58 + </p> 59 + </li> 60 + 61 + <li> 62 + <h2> 63 + Really reliable 64 + </h2> 65 + <p> 66 + Scrambling to fix problems in production is stressful, so Wisp uses 67 + Gleam's type safety and the BEAM's fault tolerance help prevent those 68 + panicked late night phone calls from your boss. 69 + </p> 70 + </li> 71 + </ul> 72 + 73 + <section class="content-width"> 74 + <h2>OK, but what does Wisp actually give you?</h2> 75 + <ul> 76 + <li>Composable middleware, with lots of useful ones built-in.</li> 77 + <li>Type safe routing with good old fashioned pattern matching.</li> 78 + <li>Parsing of JSON, urlencoded, and multipart bodies.</li> 79 + <li>Tamper-proof signed cookies, suitable for authentication.</li> 80 + <li>Body size limiting and file upload streaming to disc, to prevent 81 + memory exhaustion attacks.</li> 82 + <li>Serving of CSS, JavaScript, or whatever other static assets you want.</li> 83 + <li>Logging, both ad-hoc logging and request logging, using a middleware.</li> 84 + <li>Regular Gleam programming, so you can use any Gleam package you want 85 + without trouble.</li> 86 + </ul> 87 + <p> 88 + And a recommended project structure, so you can focus on solving the 89 + problems you want to solve, rather than reinventing the wheel. 90 + </p> 91 + </section> 92 + 93 + <section class="content-width"> 94 + <h2>That sounds good! What does it look like?</h2> 95 + <p> 96 + Here's a JSON API request handler that saves an item in a database. 97 + </p> 98 + <pre><code>import my_app/people 99 + import my_app/web.{Context} 100 + import gleam/result.{try} 101 + import wisp.{Request, Response} 102 + 103 + pub fn handle_request(req: Request, ctx: Context) -> Response { 104 + use json <- wisp.require_json(req) 105 + 106 + let result = { 107 + use params <- try(people.parse_params(json)) 108 + use person <- try(people.save(params, ctx.db)) 109 + Ok(people.to_json(person)) 110 + } 111 + 112 + case result { 113 + Ok(body) -> wisp.json_response(body, 201) 114 + Error(_) -> wisp.bad_request() 115 + } 116 + } 117 + </code></pre> 118 + 119 + <p> 120 + Want to learn more? Check out <a href="https://github.com/lpil/wisp#learning-wisp"> 121 + the Wisp guides</a>. 122 + </p> 123 + </section> 124 + 125 + <footer> 126 + 🧚 127 + <a href="https://github.com/gleam-lang/gleam/blob/main/CODE_OF_CONDUCT.md">Code of conduct</a> 128 + </footer> 14 129 </body> 130 + 15 131 </html>
+70 -5
docs/style.css
··· 1 + :root { 2 + --gap: 12px; 3 + --gap-l: calc(var(--gap) * 2); 4 + --gap-xl: calc(var(--gap) * 4); 5 + --page-width: 850px; 6 + } 7 + 1 8 * { 2 9 box-sizing: border-box; 3 10 } 4 11 5 12 body, 6 13 html { 7 - height: 100vh; 8 - overflow-y: hidden; 14 + margin: 0; 15 + font-family: sans-serif; 16 + font-size: 17px; 17 + line-height: 1.25; 18 + } 19 + 20 + a { 21 + text-decoration-style: dotted; 9 22 } 10 23 11 - body { 12 - font-family: sans-serif; 24 + a:hover { 25 + text-decoration-thickness: 2px; 26 + } 27 + 28 + .home-hero { 13 29 margin: 0; 14 30 padding: 0; 31 + min-height: 70vh; 15 32 16 33 display: flex; 17 34 align-items: center; ··· 32 49 radial-gradient(at 98% 0%, hsla(121, 69%, 81%, 1) 0px, transparent 50%); 33 50 } 34 51 35 - .hero-wordmark { 52 + .home-hero img { 36 53 width: 360px; 37 54 } 55 + 56 + .home-hero nav { 57 + position: absolute; 58 + top: 0; 59 + text-align: right; 60 + width: 100%; 61 + padding: var(--gap-l); 62 + } 63 + 64 + .home-hero nav a { 65 + color: black; 66 + opacity: 0.8; 67 + margin: 0 var(--gap); 68 + } 69 + 70 + .content-width { 71 + max-width: 100%; 72 + width: var(--page-width); 73 + margin: 0 auto; 74 + padding: var(--gap-l); 75 + } 76 + 77 + .features { 78 + display: flex; 79 + flex-wrap: wrap; 80 + gap: var(--gap-l); 81 + } 82 + 83 + .features li { 84 + list-style: none; 85 + width: calc((var(--page-width) - var(--gap-l) * 3) * 0.5); 86 + max-width: 100%; 87 + } 88 + 89 + pre { 90 + font-size: 16px; 91 + padding: var(--gap-l); 92 + background-color: #f5f5f5; 93 + box-shadow: 7px 7px #c0c0c0; 94 + margin: var(--gap-l) 0; 95 + } 96 + 97 + footer { 98 + display: flex; 99 + flex-direction: column; 100 + align-items: center; 101 + padding: var(--gap-xl); 102 + }
+1 -1
gleam.toml
··· 1 1 name = "wisp" 2 2 version = "0.4.0" 3 3 gleam = ">= 0.30.0" 4 - description = "A fun and practical web framework for Gleam" 4 + description = "A practical web framework for Gleam" 5 5 licences = ["Apache-2.0"] 6 6 7 7 repository = { type = "github", user = "lpil", repo = "wisp" }