+1
-1
README.md
+1
-1
README.md
+121
-5
docs/index.html
+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
+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
gleam.toml