tangled
alpha
login
or
join now
keii.dev
/
wisp
3
fork
atom
🧚 A practical web framework for Gleam
3
fork
atom
overview
issues
pulls
pipelines
Rescue crashes
Louis Pilfold
2 years ago
d3395b76
1a26d9c4
+37
-10
7 changed files
expand all
collapse all
unified
split
action
manifest.toml
src
action
applications
form.gleam
applications.gleam
router.gleam
web.gleam
test
action
applications
form_test.gleam
framework
src
framework.gleam
+2
-2
action/manifest.toml
···
3
3
4
4
packages = [
5
5
{ name = "esqlite", version = "0.8.6", build_tools = ["rebar3"], requirements = [], otp_app = "esqlite", source = "hex", outer_checksum = "607E45F4DA42601D8F530979417F57A4CD629AB49085891849302057E68EA188" },
6
6
-
{ name = "framework", version = "0.1.0", build_tools = ["gleam"], requirements = ["gleam_http", "gleam_stdlib", "mist"], source = "local", path = "/Users/louis/src/gleam/action/framework" },
6
6
+
{ name = "framework", version = "0.1.0", build_tools = ["gleam"], requirements = ["gleam_http", "gleam_stdlib", "mist"], source = "local", path = "../framework" },
7
7
{ name = "gleam_erlang", version = "0.20.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "F216A80C8FDFF774447B494D5E08AE4E9A911E971727B9A78FEBF5F300914584" },
8
8
{ name = "gleam_http", version = "3.4.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_http", source = "hex", outer_checksum = "B6EB76D304E0E66267485983E6B7BC28F3BFA6795BB2BF90FC411F6903AF6A1A" },
9
9
{ name = "gleam_otp", version = "0.6.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "gleam_erlang"], otp_app = "gleam_otp", source = "hex", outer_checksum = "E31B158857E3D2AF946FE6E90E0CB21699AF226F4630E93FBEAC5DB4515F8920" },
10
10
{ name = "gleam_stdlib", version = "0.30.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "03710B3DA047A3683117591707FCA19D32B980229DD8CE8B0603EB5B5144F6C3" },
11
11
{ name = "gleeunit", version = "0.10.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "ECEA2DE4BE6528D36AFE74F42A21CDF99966EC36D7F25DEB34D47DD0F7977BAF" },
12
12
{ name = "glisten", version = "0.8.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "gleam_erlang", "gleam_otp"], otp_app = "glisten", source = "hex", outer_checksum = "6DDE276F8A2E3C79E5A580DEA05C7D87FCDE3A37FF69F607770D92686E193531" },
13
13
-
{ name = "htmb", version = "0.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], source = "local", path = "/Users/louis/src/gleam/action/htmb" },
13
13
+
{ name = "htmb", version = "0.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], source = "local", path = "../htmb" },
14
14
{ name = "ids", version = "0.8.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "gleam_otp", "gleam_erlang"], otp_app = "ids", source = "hex", outer_checksum = "7A378014D40E848326FBEE8AC0C9B35EB9C8094DC4414D89F9A5AA99397A6042" },
15
15
{ name = "mist", version = "0.13.0", build_tools = ["gleam"], requirements = ["glisten", "gleam_erlang", "gleam_stdlib", "gleam_http"], otp_app = "mist", source = "hex", outer_checksum = "9A374CA245D682E2C08A5224B4420DDA252EF553AE5FD0ED7BAD33F86ACF7C98" },
16
16
{ name = "sqlight", version = "0.7.0", build_tools = ["gleam"], requirements = ["esqlite", "gleam_stdlib"], otp_app = "sqlight", source = "hex", outer_checksum = "BDBAA35B58E11B6DE20DC869EAA247F447268B8F398E0677F25444C9F7AE54EA" },
+1
-1
action/src/action/feature/applications.gleam
action/src/action/applications.gleam
···
1
1
// TODO: Sign the application id so that bad actors can't generate them.
2
2
3
3
import action/database
4
4
-
import action/feature/applications/form.{
4
4
+
import action/applications/form.{
5
5
BoolSubmitButtons, Checkboxes, Email, Phone, Question, Radio, Step, Text,
6
6
}
7
7
import action/html
action/src/action/feature/applications/form.gleam
action/src/action/applications/form.gleam
+4
-4
action/src/action/router.gleam
···
1
1
-
import action/feature/applications
1
1
+
import action/applications
2
2
import action/html.{h, text}
3
3
import action/web.{Context}
4
4
import framework.{Request, Response}
···
6
6
import gleam/http.{Get}
7
7
8
8
pub fn handle_request(req: Request, ctx: Context) -> Response {
9
9
-
let req = framework.method_override(req)
9
9
+
use req <- web.middleware(req)
10
10
11
11
case framework.path_segments(req) {
12
12
["take-action"] -> applications.resource(req, ctx)
13
13
[] -> home_page(req)
14
14
_ -> framework.not_found()
15
15
}
16
16
-
|> web.default_responses
17
16
}
18
17
19
18
pub fn home_page(request: Request) -> Response {
20
19
use <- framework.require_method(request, Get)
21
21
-
framework.html_response(home_html(), 200)
20
20
+
home_html()
21
21
+
|> framework.html_response(200)
22
22
}
23
23
24
24
fn home_html() {
+11
-2
action/src/action/web.gleam
···
1
1
import sqlight
2
2
-
import framework.{Response}
2
2
+
import framework.{Request, Response}
3
3
import htmb.{h, text}
4
4
import gleam/bool
5
5
···
7
7
Context(db: sqlight.Connection)
8
8
}
9
9
10
10
-
pub fn default_responses(response: Response) -> Response {
10
10
+
pub fn middleware(req: Request, service: fn(Request) -> Response) -> Response {
11
11
+
let req = framework.method_override(req)
12
12
+
use <- serve_default_responses
13
13
+
use <- framework.rescue_crashes
14
14
+
15
15
+
service(req)
16
16
+
}
17
17
+
18
18
+
fn serve_default_responses(service: fn() -> Response) -> Response {
19
19
+
let response = service()
11
20
use <- bool.guard(response.body != framework.Empty, return: response)
12
21
13
22
case response.status {
+1
-1
action/test/action/feature/applications/form_test.gleam
action/test/action/applications/form_test.gleam
···
1
1
-
import action/feature/applications/form.{
1
1
+
import action/applications/form.{
2
2
Answer, BoolAnswer, BoolSubmitButtons, Checkboxes, Email, MultipleChoiceAnswer,
3
3
NoAnswer, Phone, Question, Radio, Text, TextAnswer,
4
4
}
+18
framework/src/framework.gleam
···
23
23
import gleam/string_builder.{StringBuilder}
24
24
import gleam/bit_builder.{BitBuilder}
25
25
import gleam/bit_string
26
26
+
import gleam/erlang
26
27
import gleam/bool
27
28
import gleam/http.{Method}
28
29
import gleam/http/request.{Request as HttpRequest}
···
143
144
// TODO: document
144
145
pub fn entity_too_large() -> Response {
145
146
HttpResponse(413, [], Empty)
147
147
+
}
148
148
+
149
149
+
// TODO: test
150
150
+
// TODO: document
151
151
+
pub fn internal_server_error() -> Response {
152
152
+
HttpResponse(500, [], Empty)
146
153
}
147
154
148
155
// TODO: test
···
324
331
case result {
325
332
Ok(value) -> next(value)
326
333
Error(_) -> bad_request()
334
334
+
}
335
335
+
}
336
336
+
337
337
+
//
338
338
+
// Middleware
339
339
+
//
340
340
+
341
341
+
pub fn rescue_crashes(service: fn() -> Response) -> Response {
342
342
+
case erlang.rescue(service) {
343
343
+
Ok(response) -> response
344
344
+
Error(_) -> internal_server_error()
327
345
}
328
346
}
329
347