+2
-2
.github/workflows/ci.yml
+2
-2
.github/workflows/ci.yml
+19
-1
CHANGELOG.md
+19
-1
CHANGELOG.md
···
1
# Changelog
2
3
+
## v1.3.0 - 2024-11-21
4
+
5
+
- Updated for `gleam_stdlib` v0.43.0.
6
7
+
## v1.2.0 - 2024-10-09
8
+
9
+
- The requirement for `gleam_json` has been relaxed to < 3.0.0.
10
+
- The requirement for `mist` has been relaxed to < 4.0.0.
11
+
- The Gleam version requirement has been corrected to `>= 1.1.0` from the
12
+
previously inaccurate `">= 0.32.0`.
13
+
14
+
## v1.1.0 - 2024-08-23
15
+
16
+
- Rather than using `/tmp`, the platform-specific temporary directory is
17
+
detected used.
18
+
19
+
## v1.0.0 - 2024-08-21
20
+
21
+
- The Mist web server related functions have been moved to the `wisp_mist`
22
+
module.
23
- The `wisp` module gains the `set_logger_level` function and `LogLevel` type.
24
25
## v0.16.0 - 2024-07-13
+1
-1
examples/00-hello-world/gleam.toml
+1
-1
examples/00-hello-world/gleam.toml
+3
-3
examples/00-hello-world/src/app/router.gleam
+3
-3
examples/00-hello-world/src/app/router.gleam
···
1
-
import wisp.{type Request, type Response}
2
-
import gleam/string_builder
3
import app/web
4
5
/// The HTTP request handler- your application!
6
///
···
9
use _req <- web.middleware(req)
10
11
// Later we'll use templates, but for now a string will do.
12
-
let body = string_builder.from_string("<h1>Hello, Joe!</h1>")
13
14
// Return a 200 OK response with the body and a HTML content type.
15
wisp.html_response(body, 200)
···
1
import app/web
2
+
import gleam/string_tree
3
+
import wisp.{type Request, type Response}
4
5
/// The HTTP request handler- your application!
6
///
···
9
use _req <- web.middleware(req)
10
11
// Later we'll use templates, but for now a string will do.
12
+
let body = string_tree.from_string("<h1>Hello, Joe!</h1>")
13
14
// Return a 200 OK response with the body and a HTML content type.
15
wisp.html_response(body, 200)
+3
-2
examples/00-hello-world/src/app.gleam
+3
-2
examples/00-hello-world/src/app.gleam
···
1
import gleam/erlang/process
2
import mist
3
import wisp
4
-
import app/router
5
6
pub fn main() {
7
// This sets the logger to print INFO level logs, and other sensible defaults
···
14
15
// Start the Mist web server.
16
let assert Ok(_) =
17
-
wisp.mist_handler(router.handle_request, secret_key_base)
18
|> mist.new
19
|> mist.port(8000)
20
|> mist.start_http
···
1
+
import app/router
2
import gleam/erlang/process
3
import mist
4
import wisp
5
+
import wisp/wisp_mist
6
7
pub fn main() {
8
// This sets the logger to print INFO level logs, and other sensible defaults
···
15
16
// Start the Mist web server.
17
let assert Ok(_) =
18
+
wisp_mist.handler(router.handle_request, secret_key_base)
19
|> mist.new
20
|> mist.port(8000)
21
|> mist.start_http
+1
-1
examples/01-routing/gleam.toml
+1
-1
examples/01-routing/gleam.toml
+7
-7
examples/01-routing/src/app/router.gleam
+7
-7
examples/01-routing/src/app/router.gleam
···
1
-
import wisp.{type Request, type Response}
2
-
import gleam/string_builder
3
-
import gleam/http.{Get, Post}
4
import app/web
5
6
pub fn handle_request(req: Request) -> Response {
7
use req <- web.middleware(req)
···
31
// used to return a 405: Method Not Allowed response for all other methods.
32
use <- wisp.require_method(req, Get)
33
34
-
let html = string_builder.from_string("Hello, Joe!")
35
wisp.ok()
36
|> wisp.html_body(html)
37
}
···
48
49
fn list_comments() -> Response {
50
// In a later example we'll show how to read from a database.
51
-
let html = string_builder.from_string("Comments!")
52
wisp.ok()
53
|> wisp.html_body(html)
54
}
55
56
fn create_comment(_req: Request) -> Response {
57
// In a later example we'll show how to parse data from the request body.
58
-
let html = string_builder.from_string("Created")
59
wisp.created()
60
|> wisp.html_body(html)
61
}
···
66
// The `id` path parameter has been passed to this function, so we could use
67
// it to look up a comment in a database.
68
// For now we'll just include in the response body.
69
-
let html = string_builder.from_string("Comment with id " <> id)
70
wisp.ok()
71
|> wisp.html_body(html)
72
}
···
1
import app/web
2
+
import gleam/http.{Get, Post}
3
+
import gleam/string_tree
4
+
import wisp.{type Request, type Response}
5
6
pub fn handle_request(req: Request) -> Response {
7
use req <- web.middleware(req)
···
31
// used to return a 405: Method Not Allowed response for all other methods.
32
use <- wisp.require_method(req, Get)
33
34
+
let html = string_tree.from_string("Hello, Joe!")
35
wisp.ok()
36
|> wisp.html_body(html)
37
}
···
48
49
fn list_comments() -> Response {
50
// In a later example we'll show how to read from a database.
51
+
let html = string_tree.from_string("Comments!")
52
wisp.ok()
53
|> wisp.html_body(html)
54
}
55
56
fn create_comment(_req: Request) -> Response {
57
// In a later example we'll show how to parse data from the request body.
58
+
let html = string_tree.from_string("Created")
59
wisp.created()
60
|> wisp.html_body(html)
61
}
···
66
// The `id` path parameter has been passed to this function, so we could use
67
// it to look up a comment in a database.
68
// For now we'll just include in the response body.
69
+
let html = string_tree.from_string("Comment with id " <> id)
70
wisp.ok()
71
|> wisp.html_body(html)
72
}
+3
-2
examples/01-routing/src/app.gleam
+3
-2
examples/01-routing/src/app.gleam
···
1
import gleam/erlang/process
2
import mist
3
import wisp
4
-
import app/router
5
6
pub fn main() {
7
wisp.configure_logger()
8
let secret_key_base = wisp.random_string(64)
9
10
let assert Ok(_) =
11
-
wisp.mist_handler(router.handle_request, secret_key_base)
12
|> mist.new
13
|> mist.port(8000)
14
|> mist.start_http
···
1
+
import app/router
2
import gleam/erlang/process
3
import mist
4
import wisp
5
+
import wisp/wisp_mist
6
7
pub fn main() {
8
wisp.configure_logger()
9
let secret_key_base = wisp.random_string(64)
10
11
let assert Ok(_) =
12
+
wisp_mist.handler(router.handle_request, secret_key_base)
13
|> mist.new
14
|> mist.port(8000)
15
|> mist.start_http
+1
-1
examples/02-working-with-form-data/gleam.toml
+1
-1
examples/02-working-with-form-data/gleam.toml
+3
-3
examples/02-working-with-form-data/src/app/router.gleam
+3
-3
examples/02-working-with-form-data/src/app/router.gleam
···
2
import gleam/http.{Get, Post}
3
import gleam/list
4
import gleam/result
5
-
import gleam/string_builder
6
import wisp.{type Request, type Response}
7
8
pub fn handle_request(req: Request) -> Response {
···
21
// In a larger application a template library or HTML form library might
22
// be used here instead of a string literal.
23
let html =
24
-
string_builder.from_string(
25
"<form method='post'>
26
<label>Title:
27
<input type='text' name='title'>
···
60
case result {
61
Ok(content) -> {
62
wisp.ok()
63
-
|> wisp.html_body(string_builder.from_string(content))
64
}
65
Error(_) -> {
66
wisp.bad_request()
···
2
import gleam/http.{Get, Post}
3
import gleam/list
4
import gleam/result
5
+
import gleam/string_tree
6
import wisp.{type Request, type Response}
7
8
pub fn handle_request(req: Request) -> Response {
···
21
// In a larger application a template library or HTML form library might
22
// be used here instead of a string literal.
23
let html =
24
+
string_tree.from_string(
25
"<form method='post'>
26
<label>Title:
27
<input type='text' name='title'>
···
60
case result {
61
Ok(content) -> {
62
wisp.ok()
63
+
|> wisp.html_body(string_tree.from_string(content))
64
}
65
Error(_) -> {
66
wisp.bad_request()
+3
-2
examples/02-working-with-form-data/src/app.gleam
+3
-2
examples/02-working-with-form-data/src/app.gleam
···
1
import gleam/erlang/process
2
import mist
3
import wisp
4
-
import app/router
5
6
pub fn main() {
7
wisp.configure_logger()
8
let secret_key_base = wisp.random_string(64)
9
10
let assert Ok(_) =
11
-
wisp.mist_handler(router.handle_request, secret_key_base)
12
|> mist.new
13
|> mist.port(8000)
14
|> mist.start_http
···
1
+
import app/router
2
import gleam/erlang/process
3
import mist
4
import wisp
5
+
import wisp/wisp_mist
6
7
pub fn main() {
8
wisp.configure_logger()
9
let secret_key_base = wisp.random_string(64)
10
11
let assert Ok(_) =
12
+
wisp_mist.handler(router.handle_request, secret_key_base)
13
|> mist.new
14
|> mist.port(8000)
15
|> mist.start_http
+1
-1
examples/03-working-with-json/gleam.toml
+1
-1
examples/03-working-with-json/gleam.toml
+3
-2
examples/03-working-with-json/src/app.gleam
+3
-2
examples/03-working-with-json/src/app.gleam
···
1
import gleam/erlang/process
2
import mist
3
import wisp
4
-
import app/router
5
6
pub fn main() {
7
wisp.configure_logger()
8
let secret_key_base = wisp.random_string(64)
9
10
let assert Ok(_) =
11
-
wisp.mist_handler(router.handle_request, secret_key_base)
12
|> mist.new
13
|> mist.port(8000)
14
|> mist.start_http
···
1
+
import app/router
2
import gleam/erlang/process
3
import mist
4
import wisp
5
+
import wisp/wisp_mist
6
7
pub fn main() {
8
wisp.configure_logger()
9
let secret_key_base = wisp.random_string(64)
10
11
let assert Ok(_) =
12
+
wisp_mist.handler(router.handle_request, secret_key_base)
13
|> mist.new
14
|> mist.port(8000)
15
|> mist.start_http
+1
-1
examples/04-working-with-other-formats/gleam.toml
+1
-1
examples/04-working-with-other-formats/gleam.toml
+3
-2
examples/04-working-with-other-formats/src/app.gleam
+3
-2
examples/04-working-with-other-formats/src/app.gleam
···
1
import gleam/erlang/process
2
import mist
3
import wisp
4
-
import app/router
5
6
pub fn main() {
7
wisp.configure_logger()
8
let secret_key_base = wisp.random_string(64)
9
10
let assert Ok(_) =
11
-
wisp.mist_handler(router.handle_request, secret_key_base)
12
|> mist.new
13
|> mist.port(8000)
14
|> mist.start_http
···
1
+
import app/router
2
import gleam/erlang/process
3
import mist
4
import wisp
5
+
import wisp/wisp_mist
6
7
pub fn main() {
8
wisp.configure_logger()
9
let secret_key_base = wisp.random_string(64)
10
11
let assert Ok(_) =
12
+
wisp_mist.handler(router.handle_request, secret_key_base)
13
|> mist.new
14
|> mist.port(8000)
15
|> mist.start_http
+1
-1
examples/05-using-a-database/gleam.toml
+1
-1
examples/05-using-a-database/gleam.toml
+2
-2
examples/05-using-a-database/src/app/web/people.gleam
+2
-2
examples/05-using-a-database/src/app/web/people.gleam
···
1
import app/web.{type Context}
2
import gleam/dynamic.{type Dynamic}
3
import gleam/http.{Get, Post}
4
import gleam/json
5
-
import gleam/dict
6
import gleam/result.{try}
7
import tiny_database
8
import wisp.{type Request, type Response}
···
122
// In this example we are not going to be reporting specific errors to the
123
// user, so we can discard the error and replace it with Nil.
124
result
125
-
|> result.nil_error
126
}
127
128
/// Save a person to the database and return the id of the newly created record.
···
1
import app/web.{type Context}
2
+
import gleam/dict
3
import gleam/dynamic.{type Dynamic}
4
import gleam/http.{Get, Post}
5
import gleam/json
6
import gleam/result.{try}
7
import tiny_database
8
import wisp.{type Request, type Response}
···
122
// In this example we are not going to be reporting specific errors to the
123
// user, so we can discard the error and replace it with Nil.
124
result
125
+
|> result.replace_error(Nil)
126
}
127
128
/// Save a person to the database and return the id of the newly created record.
+5
-4
examples/05-using-a-database/src/app.gleam
+5
-4
examples/05-using-a-database/src/app.gleam
···
1
import gleam/erlang/process
2
-
import tiny_database
3
import mist
4
import wisp
5
-
import app/router
6
-
import app/web
7
8
pub const data_directory = "tmp/data"
9
···
24
25
let assert Ok(_) =
26
handler
27
-
|> wisp.mist_handler(secret_key_base)
28
|> mist.new
29
|> mist.port(8000)
30
|> mist.start_http
···
1
+
import app/router
2
+
import app/web
3
import gleam/erlang/process
4
import mist
5
+
import tiny_database
6
import wisp
7
+
import wisp/wisp_mist
8
9
pub const data_directory = "tmp/data"
10
···
25
26
let assert Ok(_) =
27
handler
28
+
|> wisp_mist.handler(secret_key_base)
29
|> mist.new
30
|> mist.port(8000)
31
|> mist.start_http
+1
-1
examples/06-serving-static-assets/gleam.toml
+1
-1
examples/06-serving-static-assets/gleam.toml
+3
-3
examples/06-serving-static-assets/src/app/router.gleam
+3
-3
examples/06-serving-static-assets/src/app/router.gleam
···
1
-
import wisp.{type Request, type Response}
2
-
import gleam/string_builder
3
import app/web.{type Context}
4
5
const html = "<!DOCTYPE html>
6
<html lang=\"en\">
···
18
19
pub fn handle_request(req: Request, ctx: Context) -> Response {
20
use _req <- web.middleware(req, ctx)
21
-
wisp.html_response(string_builder.from_string(html), 200)
22
}
···
1
import app/web.{type Context}
2
+
import gleam/string_tree
3
+
import wisp.{type Request, type Response}
4
5
const html = "<!DOCTYPE html>
6
<html lang=\"en\">
···
18
19
pub fn handle_request(req: Request, ctx: Context) -> Response {
20
use _req <- web.middleware(req, ctx)
21
+
wisp.html_response(string_tree.from_string(html), 200)
22
}
+4
-3
examples/06-serving-static-assets/src/app.gleam
+4
-3
examples/06-serving-static-assets/src/app.gleam
···
1
import gleam/erlang/process
2
import mist
3
import wisp
4
-
import app/router
5
-
import app/web.{Context}
6
7
pub fn main() {
8
wisp.configure_logger()
···
16
let handler = router.handle_request(_, ctx)
17
18
let assert Ok(_) =
19
-
wisp.mist_handler(handler, secret_key_base)
20
|> mist.new
21
|> mist.port(8000)
22
|> mist.start_http
···
1
+
import app/router
2
+
import app/web.{Context}
3
import gleam/erlang/process
4
import mist
5
import wisp
6
+
import wisp/wisp_mist
7
8
pub fn main() {
9
wisp.configure_logger()
···
17
let handler = router.handle_request(_, ctx)
18
19
let assert Ok(_) =
20
+
wisp_mist.handler(handler, secret_key_base)
21
|> mist.new
22
|> mist.port(8000)
23
|> mist.start_http
+1
-1
examples/07-logging/gleam.toml
+1
-1
examples/07-logging/gleam.toml
+3
-2
examples/07-logging/src/app.gleam
+3
-2
examples/07-logging/src/app.gleam
···
1
import gleam/erlang/process
2
import mist
3
import wisp
4
-
import app/router
5
6
pub fn main() {
7
wisp.configure_logger()
8
let secret_key_base = wisp.random_string(64)
9
10
let assert Ok(_) =
11
-
wisp.mist_handler(router.handle_request, secret_key_base)
12
|> mist.new
13
|> mist.port(8000)
14
|> mist.start_http
···
1
+
import app/router
2
import gleam/erlang/process
3
import mist
4
import wisp
5
+
import wisp/wisp_mist
6
7
pub fn main() {
8
wisp.configure_logger()
9
let secret_key_base = wisp.random_string(64)
10
11
let assert Ok(_) =
12
+
wisp_mist.handler(router.handle_request, secret_key_base)
13
|> mist.new
14
|> mist.port(8000)
15
|> mist.start_http
+1
-1
examples/09-configuring-default-responses/README.md
+1
-1
examples/09-configuring-default-responses/README.md
+1
-1
examples/09-configuring-default-responses/gleam.toml
+1
-1
examples/09-configuring-default-responses/gleam.toml
+2
-2
examples/09-configuring-default-responses/src/app/router.gleam
+2
-2
examples/09-configuring-default-responses/src/app/router.gleam
···
1
import app/web
2
-
import gleam/string_builder
3
import wisp.{type Request, type Response}
4
5
pub fn handle_request(req: Request) -> Response {
···
9
// This request returns a non-empty body.
10
[] -> {
11
"<h1>Hello, Joe!</h1>"
12
-
|> string_builder.from_string
13
|> wisp.html_response(200)
14
}
15
···
1
import app/web
2
+
import gleam/string_tree
3
import wisp.{type Request, type Response}
4
5
pub fn handle_request(req: Request) -> Response {
···
9
// This request returns a non-empty body.
10
[] -> {
11
"<h1>Hello, Joe!</h1>"
12
+
|> string_tree.from_string
13
|> wisp.html_response(200)
14
}
15
+6
-6
examples/09-configuring-default-responses/src/app/web.gleam
+6
-6
examples/09-configuring-default-responses/src/app/web.gleam
···
1
-
import wisp
2
import gleam/bool
3
-
import gleam/string_builder
4
5
pub fn middleware(
6
req: wisp.Request,
···
32
case response.status {
33
404 | 405 ->
34
"<h1>There's nothing here</h1>"
35
-
|> string_builder.from_string
36
|> wisp.html_body(response, _)
37
38
400 | 422 ->
39
"<h1>Bad request</h1>"
40
-
|> string_builder.from_string
41
|> wisp.html_body(response, _)
42
43
413 ->
44
"<h1>Request entity too large</h1>"
45
-
|> string_builder.from_string
46
|> wisp.html_body(response, _)
47
48
500 ->
49
"<h1>Internal server error</h1>"
50
-
|> string_builder.from_string
51
|> wisp.html_body(response, _)
52
53
// For other status codes redirect to the home page
···
1
import gleam/bool
2
+
import gleam/string_tree
3
+
import wisp
4
5
pub fn middleware(
6
req: wisp.Request,
···
32
case response.status {
33
404 | 405 ->
34
"<h1>There's nothing here</h1>"
35
+
|> string_tree.from_string
36
|> wisp.html_body(response, _)
37
38
400 | 422 ->
39
"<h1>Bad request</h1>"
40
+
|> string_tree.from_string
41
|> wisp.html_body(response, _)
42
43
413 ->
44
"<h1>Request entity too large</h1>"
45
+
|> string_tree.from_string
46
|> wisp.html_body(response, _)
47
48
500 ->
49
"<h1>Internal server error</h1>"
50
+
|> string_tree.from_string
51
|> wisp.html_body(response, _)
52
53
// For other status codes redirect to the home page
+3
-2
examples/09-configuring-default-responses/src/app.gleam
+3
-2
examples/09-configuring-default-responses/src/app.gleam
···
1
import gleam/erlang/process
2
import mist
3
import wisp
4
-
import app/router
5
6
pub fn main() {
7
wisp.configure_logger()
8
let secret_key_base = wisp.random_string(64)
9
10
let assert Ok(_) =
11
-
wisp.mist_handler(router.handle_request, secret_key_base)
12
|> mist.new
13
|> mist.port(8000)
14
|> mist.start_http
···
1
+
import app/router
2
import gleam/erlang/process
3
import mist
4
import wisp
5
+
import wisp/wisp_mist
6
7
pub fn main() {
8
wisp.configure_logger()
9
let secret_key_base = wisp.random_string(64)
10
11
let assert Ok(_) =
12
+
wisp_mist.handler(router.handle_request, secret_key_base)
13
|> mist.new
14
|> mist.port(8000)
15
|> mist.start_http
+1
-1
examples/10-working-with-files/gleam.toml
+1
-1
examples/10-working-with-files/gleam.toml
+5
-5
examples/10-working-with-files/src/app/router.gleam
+5
-5
examples/10-working-with-files/src/app/router.gleam
···
1
import app/web
2
import gleam/http.{Get, Post}
3
import gleam/list
4
import gleam/result
5
-
import gleam/string_builder
6
-
import gleam/bytes_builder
7
import wisp.{type Request, type Response}
8
9
pub fn handle_request(req: Request) -> Response {
···
35
fn show_home(req: Request) -> Response {
36
use <- wisp.require_method(req, Get)
37
html
38
-
|> string_builder.from_string
39
|> wisp.html_response(200)
40
}
41
···
45
// In this case we have the file contents in memory as a string.
46
// This is good if we have just made the file, but if the file already exists
47
// on the disc then the approach in the next function is more efficient.
48
-
let file_contents = bytes_builder.from_string("Hello, Joe!")
49
50
wisp.ok()
51
|> wisp.set_header("content-type", "text/plain")
···
107
case result {
108
Ok(name) -> {
109
{ "<p>Thank you for your file!" <> name <> "</p>" <> html }
110
-
|> string_builder.from_string
111
|> wisp.html_response(200)
112
}
113
Error(_) -> {
···
1
import app/web
2
+
import gleam/bytes_tree
3
import gleam/http.{Get, Post}
4
import gleam/list
5
import gleam/result
6
+
import gleam/string_tree
7
import wisp.{type Request, type Response}
8
9
pub fn handle_request(req: Request) -> Response {
···
35
fn show_home(req: Request) -> Response {
36
use <- wisp.require_method(req, Get)
37
html
38
+
|> string_tree.from_string
39
|> wisp.html_response(200)
40
}
41
···
45
// In this case we have the file contents in memory as a string.
46
// This is good if we have just made the file, but if the file already exists
47
// on the disc then the approach in the next function is more efficient.
48
+
let file_contents = bytes_tree.from_string("Hello, Joe!")
49
50
wisp.ok()
51
|> wisp.set_header("content-type", "text/plain")
···
107
case result {
108
Ok(name) -> {
109
{ "<p>Thank you for your file!" <> name <> "</p>" <> html }
110
+
|> string_tree.from_string
111
|> wisp.html_response(200)
112
}
113
Error(_) -> {
+3
-2
examples/10-working-with-files/src/app.gleam
+3
-2
examples/10-working-with-files/src/app.gleam
···
1
import gleam/erlang/process
2
import mist
3
import wisp
4
-
import app/router
5
6
pub fn main() {
7
wisp.configure_logger()
8
let secret_key_base = wisp.random_string(64)
9
10
let assert Ok(_) =
11
-
wisp.mist_handler(router.handle_request, secret_key_base)
12
|> mist.new
13
|> mist.port(8000)
14
|> mist.start_http
···
1
+
import app/router
2
import gleam/erlang/process
3
import mist
4
import wisp
5
+
import wisp/wisp_mist
6
7
pub fn main() {
8
wisp.configure_logger()
9
let secret_key_base = wisp.random_string(64)
10
11
let assert Ok(_) =
12
+
wisp_mist.handler(router.handle_request, secret_key_base)
13
|> mist.new
14
|> mist.port(8000)
15
|> mist.start_http
+7
-6
gleam.toml
+7
-6
gleam.toml
···
1
name = "wisp"
2
-
version = "0.16.0"
3
-
gleam = ">= 0.32.0"
4
description = "A practical web framework for Gleam"
5
licences = ["Apache-2.0"]
6
···
12
gleam_crypto = ">= 1.0.0 and < 2.0.0"
13
gleam_erlang = ">= 0.21.0 and < 2.0.0"
14
gleam_http = ">= 3.5.0 and < 4.0.0"
15
-
gleam_json = ">= 0.6.0 and < 2.0.0"
16
-
gleam_stdlib = ">= 0.29.0 and < 2.0.0"
17
-
mist = ">= 1.2.0 and < 2.0.0"
18
simplifile = ">= 2.0.0 and < 3.0.0"
19
marceau = ">= 1.1.0 and < 2.0.0"
20
logging = ">= 1.2.0 and < 2.0.0"
21
22
[dev-dependencies]
23
-
gleeunit = "~> 1.0"
···
1
name = "wisp"
2
+
version = "1.3.0"
3
+
gleam = ">= 1.4.0"
4
description = "A practical web framework for Gleam"
5
licences = ["Apache-2.0"]
6
···
12
gleam_crypto = ">= 1.0.0 and < 2.0.0"
13
gleam_erlang = ">= 0.21.0 and < 2.0.0"
14
gleam_http = ">= 3.5.0 and < 4.0.0"
15
+
gleam_json = ">= 0.6.0 and < 3.0.0"
16
+
gleam_stdlib = ">= 0.43.0 and < 2.0.0"
17
+
mist = ">= 1.2.0 and < 4.0.0"
18
simplifile = ">= 2.0.0 and < 3.0.0"
19
marceau = ">= 1.1.0 and < 2.0.0"
20
logging = ">= 1.2.0 and < 2.0.0"
21
+
directories = ">= 1.0.0 and < 2.0.0"
22
23
[dev-dependencies]
24
+
gleeunit = ">= 1.0.0 and < 2.0.0"
+21
-17
manifest.toml
+21
-17
manifest.toml
···
3
4
packages = [
5
{ name = "birl", version = "1.7.1", build_tools = ["gleam"], requirements = ["gleam_stdlib", "ranger"], otp_app = "birl", source = "hex", outer_checksum = "5C66647D62BCB11FE327E7A6024907C4A17954EF22865FE0940B54A852446D01" },
6
{ name = "exception", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "exception", source = "hex", outer_checksum = "F5580D584F16A20B7FCDCABF9E9BE9A2C1F6AC4F9176FA6DD0B63E3B20D450AA" },
7
-
{ name = "filepath", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "EFB6FF65C98B2A16378ABC3EE2B14124168C0CE5201553DE652E2644DCFDB594" },
8
-
{ name = "gleam_crypto", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_crypto", source = "hex", outer_checksum = "ADD058DEDE8F0341F1ADE3AAC492A224F15700829D9A3A3F9ADF370F875C51B7" },
9
-
{ name = "gleam_erlang", version = "0.25.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "054D571A7092D2A9727B3E5D183B7507DAB0DA41556EC9133606F09C15497373" },
10
-
{ name = "gleam_http", version = "3.6.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_http", source = "hex", outer_checksum = "8C07DF9DF8CC7F054C650839A51C30A7D3C26482AC241C899C1CEA86B22DBE51" },
11
-
{ name = "gleam_json", version = "1.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib", "thoas"], otp_app = "gleam_json", source = "hex", outer_checksum = "9063D14D25406326C0255BDA0021541E797D8A7A12573D849462CAFED459F6EB" },
12
-
{ name = "gleam_otp", version = "0.10.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "0B04FE915ACECE539B317F9652CAADBBC0F000184D586AAAF2D94C100945D72B" },
13
-
{ name = "gleam_stdlib", version = "0.39.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "2D7DE885A6EA7F1D5015D1698920C9BAF7241102836CE0C3837A4F160128A9C4" },
14
{ name = "gleeunit", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "F7A7228925D3EE7D0813C922E062BFD6D7E9310F0BEE585D3A42F3307E3CFD13" },
15
-
{ name = "glisten", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_otp", "gleam_stdlib"], otp_app = "glisten", source = "hex", outer_checksum = "CF3A9383E9BA4A8CBAF2F7B799716290D02F2AC34E7A77556B49376B662B9314" },
16
{ name = "gramps", version = "2.0.3", build_tools = ["gleam"], requirements = ["gleam_crypto", "gleam_erlang", "gleam_http", "gleam_stdlib"], otp_app = "gramps", source = "hex", outer_checksum = "3CCAA6E081225180D95C79679D383BBF51C8D1FDC1B84DA1DA444F628C373793" },
17
{ name = "hpack_erl", version = "0.3.0", build_tools = ["rebar3"], requirements = [], otp_app = "hpack", source = "hex", outer_checksum = "D6137D7079169D8C485C6962DFE261AF5B9EF60FBC557344511C1E65E3D95FB0" },
18
-
{ name = "logging", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "logging", source = "hex", outer_checksum = "FCB111401BDB4703A440A94FF8CC7DA521112269C065F219C2766998333E7738" },
19
-
{ name = "marceau", version = "1.2.0", build_tools = ["gleam"], requirements = [], otp_app = "marceau", source = "hex", outer_checksum = "5188D643C181EE350D8A20A3BDBD63AF7B6C505DE333CFBE05EF642ADD88A59B" },
20
-
{ name = "mist", version = "1.2.0", build_tools = ["gleam"], requirements = ["birl", "gleam_erlang", "gleam_http", "gleam_otp", "gleam_stdlib", "glisten", "gramps", "hpack_erl", "logging"], otp_app = "mist", source = "hex", outer_checksum = "109B4D64E68C104CC23BB3CC5441ECD479DD7444889DA01113B75C6AF0F0E17B" },
21
{ name = "ranger", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "ranger", source = "hex", outer_checksum = "1566C272B1D141B3BBA38B25CB761EF56E312E79EC0E2DFD4D3C19FB0CC1F98C" },
22
-
{ name = "simplifile", version = "2.0.1", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "5FFEBD0CAB39BDD343C3E1CCA6438B2848847DC170BA2386DF9D7064F34DF000" },
23
-
{ name = "thoas", version = "1.2.1", build_tools = ["rebar3"], requirements = [], otp_app = "thoas", source = "hex", outer_checksum = "E38697EDFFD6E91BD12CEA41B155115282630075C2A727E7A6B2947F5408B86A" },
24
]
25
26
[requirements]
27
exception = { version = ">= 2.0.0 and < 3.0.0" }
28
gleam_crypto = { version = ">= 1.0.0 and < 2.0.0" }
29
gleam_erlang = { version = ">= 0.21.0 and < 2.0.0" }
30
gleam_http = { version = ">= 3.5.0 and < 4.0.0" }
31
-
gleam_json = { version = ">= 0.6.0 and < 2.0.0" }
32
-
gleam_stdlib = { version = ">= 0.29.0 and < 2.0.0" }
33
-
gleeunit = { version = "~> 1.0" }
34
logging = { version = ">= 1.2.0 and < 2.0.0" }
35
marceau = { version = ">= 1.1.0 and < 2.0.0" }
36
-
mist = { version = ">= 1.2.0 and < 2.0.0" }
37
simplifile = { version = ">= 2.0.0 and < 3.0.0" }
···
3
4
packages = [
5
{ name = "birl", version = "1.7.1", build_tools = ["gleam"], requirements = ["gleam_stdlib", "ranger"], otp_app = "birl", source = "hex", outer_checksum = "5C66647D62BCB11FE327E7A6024907C4A17954EF22865FE0940B54A852446D01" },
6
+
{ name = "directories", version = "1.1.0", build_tools = ["gleam"], requirements = ["envoy", "gleam_stdlib", "platform", "simplifile"], otp_app = "directories", source = "hex", outer_checksum = "BDA521A4EB9EE3A7894F0DC863797878E91FF5C7826F7084B2E731E208BDB076" },
7
+
{ name = "envoy", version = "1.0.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "envoy", source = "hex", outer_checksum = "95FD059345AA982E89A0B6E2A3BF1CF43E17A7048DCD85B5B65D3B9E4E39D359" },
8
{ name = "exception", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "exception", source = "hex", outer_checksum = "F5580D584F16A20B7FCDCABF9E9BE9A2C1F6AC4F9176FA6DD0B63E3B20D450AA" },
9
+
{ name = "filepath", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "67A6D15FB39EEB69DD31F8C145BB5A421790581BD6AA14B33D64D5A55DBD6587" },
10
+
{ name = "gleam_crypto", version = "1.4.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_crypto", source = "hex", outer_checksum = "8AE56026B3E05EBB1F076778478A762E9EB62B31AEEB4285755452F397029D22" },
11
+
{ name = "gleam_erlang", version = "0.30.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "760618870AE4A497B10C73548E6E44F43B76292A54F0207B3771CBB599C675B4" },
12
+
{ name = "gleam_http", version = "3.7.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_http", source = "hex", outer_checksum = "A9EE0722106FCCAB8AD3BF9D0A3EFF92BFE8561D59B83BAE96EB0BE1938D4E0F" },
13
+
{ name = "gleam_json", version = "2.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "0A57FB5666E695FD2BEE74C0428A98B0FC11A395D2C7B4CDF5E22C5DD32C74C6" },
14
+
{ name = "gleam_otp", version = "0.14.1", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "5A8CE8DBD01C29403390A7BD5C0A63D26F865C83173CF9708E6E827E53159C65" },
15
+
{ name = "gleam_stdlib", version = "0.43.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "69EF22E78FDCA9097CBE7DF91C05B2A8B5436826D9F66680D879182C0860A747" },
16
{ name = "gleeunit", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "F7A7228925D3EE7D0813C922E062BFD6D7E9310F0BEE585D3A42F3307E3CFD13" },
17
+
{ name = "glisten", version = "6.0.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_otp", "gleam_stdlib", "logging", "telemetry"], otp_app = "glisten", source = "hex", outer_checksum = "912132751031473CB38F454120124FFC96AF6B0EA33D92C9C90DB16327A2A972" },
18
{ name = "gramps", version = "2.0.3", build_tools = ["gleam"], requirements = ["gleam_crypto", "gleam_erlang", "gleam_http", "gleam_stdlib"], otp_app = "gramps", source = "hex", outer_checksum = "3CCAA6E081225180D95C79679D383BBF51C8D1FDC1B84DA1DA444F628C373793" },
19
{ name = "hpack_erl", version = "0.3.0", build_tools = ["rebar3"], requirements = [], otp_app = "hpack", source = "hex", outer_checksum = "D6137D7079169D8C485C6962DFE261AF5B9EF60FBC557344511C1E65E3D95FB0" },
20
+
{ name = "logging", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "logging", source = "hex", outer_checksum = "1098FBF10B54B44C2C7FDF0B01C1253CAFACDACABEFB4B0D027803246753E06D" },
21
+
{ name = "marceau", version = "1.3.0", build_tools = ["gleam"], requirements = [], otp_app = "marceau", source = "hex", outer_checksum = "2D1C27504BEF45005F5DFB18591F8610FB4BFA91744878210BDC464412EC44E9" },
22
+
{ name = "mist", version = "3.0.0", build_tools = ["gleam"], requirements = ["birl", "gleam_erlang", "gleam_http", "gleam_otp", "gleam_stdlib", "glisten", "gramps", "hpack_erl", "logging"], otp_app = "mist", source = "hex", outer_checksum = "CDA1A74E768419235E16886463EC4722EFF4AB3F8D820A76EAD45D7C167D7282" },
23
+
{ name = "platform", version = "1.0.0", build_tools = ["gleam"], requirements = [], otp_app = "platform", source = "hex", outer_checksum = "8339420A95AD89AAC0F82F4C3DB8DD401041742D6C3F46132A8739F6AEB75391" },
24
{ name = "ranger", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "ranger", source = "hex", outer_checksum = "1566C272B1D141B3BBA38B25CB761EF56E312E79EC0E2DFD4D3C19FB0CC1F98C" },
25
+
{ name = "simplifile", version = "2.2.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "0DFABEF7DC7A9E2FF4BB27B108034E60C81BEBFCB7AB816B9E7E18ED4503ACD8" },
26
+
{ name = "telemetry", version = "1.3.0", build_tools = ["rebar3"], requirements = [], otp_app = "telemetry", source = "hex", outer_checksum = "7015FC8919DBE63764F4B4B87A95B7C0996BD539E0D499BE6EC9D7F3875B79E6" },
27
]
28
29
[requirements]
30
+
directories = { version = ">= 1.0.0 and < 2.0.0" }
31
exception = { version = ">= 2.0.0 and < 3.0.0" }
32
gleam_crypto = { version = ">= 1.0.0 and < 2.0.0" }
33
gleam_erlang = { version = ">= 0.21.0 and < 2.0.0" }
34
gleam_http = { version = ">= 3.5.0 and < 4.0.0" }
35
+
gleam_json = { version = ">= 0.6.0 and < 3.0.0" }
36
+
gleam_stdlib = { version = ">= 0.43.0 and < 2.0.0" }
37
+
gleeunit = { version = ">= 1.0.0 and < 2.0.0" }
38
logging = { version = ">= 1.2.0 and < 2.0.0" }
39
marceau = { version = ">= 1.1.0 and < 2.0.0" }
40
+
mist = { version = ">= 1.2.0 and < 4.0.0" }
41
simplifile = { version = ">= 2.0.0 and < 3.0.0" }
+6
-2
src/wisp/internal.gleam
+6
-2
src/wisp/internal.gleam
···
1
import gleam/bit_array
2
import gleam/crypto
3
import gleam/string
···
28
body_reader: Reader,
29
secret_key_base: String,
30
) -> Connection {
31
-
// TODO: replace `/tmp` with appropriate for the OS
32
-
let prefix = "/tmp/gleam-wisp/"
33
let temporary_directory = join_path(prefix, random_slug())
34
Connection(
35
reader: body_reader,
···
1
+
import directories
2
import gleam/bit_array
3
import gleam/crypto
4
import gleam/string
···
29
body_reader: Reader,
30
secret_key_base: String,
31
) -> Connection {
32
+
// Fallback to current working directory when no valid tmp directory exists
33
+
let prefix = case directories.tmp_dir() {
34
+
Ok(tmp_dir) -> tmp_dir <> "/gleam-wisp/"
35
+
Error(_) -> "./tmp/"
36
+
}
37
let temporary_directory = join_path(prefix, random_slug())
38
Connection(
39
reader: body_reader,
+6
-7
src/wisp/testing.gleam
+6
-7
src/wisp/testing.gleam
···
1
import gleam/bit_array
2
-
import gleam/bytes_builder
3
import gleam/crypto
4
import gleam/http
5
import gleam/http/request
6
import gleam/json.{type Json}
7
import gleam/option.{None, Some}
8
import gleam/string
9
-
import gleam/string_builder
10
import gleam/uri
11
import simplifile
12
import wisp.{type Request, type Response, Bytes, Empty, File, Text}
···
227
pub fn string_body(response: Response) -> String {
228
case response.body {
229
Empty -> ""
230
-
Text(builder) -> string_builder.to_string(builder)
231
Bytes(bytes) -> {
232
-
let data = bytes_builder.to_bit_array(bytes)
233
let assert Ok(string) = bit_array.to_string(data)
234
string
235
}
···
250
pub fn bit_array_body(response: Response) -> BitArray {
251
case response.body {
252
Empty -> <<>>
253
-
Bytes(builder) -> bytes_builder.to_bit_array(builder)
254
-
Text(builder) ->
255
-
bytes_builder.to_bit_array(bytes_builder.from_string_builder(builder))
256
File(path) -> {
257
let assert Ok(contents) = simplifile.read_bits(path)
258
contents
···
1
import gleam/bit_array
2
+
import gleam/bytes_tree
3
import gleam/crypto
4
import gleam/http
5
import gleam/http/request
6
import gleam/json.{type Json}
7
import gleam/option.{None, Some}
8
import gleam/string
9
+
import gleam/string_tree
10
import gleam/uri
11
import simplifile
12
import wisp.{type Request, type Response, Bytes, Empty, File, Text}
···
227
pub fn string_body(response: Response) -> String {
228
case response.body {
229
Empty -> ""
230
+
Text(tree) -> string_tree.to_string(tree)
231
Bytes(bytes) -> {
232
+
let data = bytes_tree.to_bit_array(bytes)
233
let assert Ok(string) = bit_array.to_string(data)
234
string
235
}
···
250
pub fn bit_array_body(response: Response) -> BitArray {
251
case response.body {
252
Empty -> <<>>
253
+
Bytes(tree) -> bytes_tree.to_bit_array(tree)
254
+
Text(tree) -> bytes_tree.to_bit_array(bytes_tree.from_string_tree(tree))
255
File(path) -> {
256
let assert Ok(contents) = simplifile.read_bits(path)
257
contents
+5
-5
src/wisp/wisp_mist.gleam
+5
-5
src/wisp/wisp_mist.gleam
···
1
import exception
2
-
import gleam/bytes_builder
3
import gleam/http/request.{type Request as HttpRequest}
4
import gleam/http/response.{type Response as HttpResponse}
5
import gleam/option
···
63
chunk: Result(mist.Chunk, mist.ReadError),
64
) -> Result(internal.Read, Nil) {
65
chunk
66
-
|> result.nil_error
67
|> result.map(fn(chunk) {
68
case chunk {
69
mist.Done -> internal.ReadingFinished
···
75
76
fn mist_response(response: wisp.Response) -> HttpResponse(mist.ResponseData) {
77
let body = case response.body {
78
-
wisp.Empty -> mist.Bytes(bytes_builder.new())
79
-
wisp.Text(text) -> mist.Bytes(bytes_builder.from_string_builder(text))
80
wisp.Bytes(bytes) -> mist.Bytes(bytes)
81
wisp.File(path) -> mist_send_file(path)
82
}
···
90
Error(error) -> {
91
wisp.log_error(string.inspect(error))
92
// TODO: return 500
93
-
mist.Bytes(bytes_builder.new())
94
}
95
}
96
}
···
1
import exception
2
+
import gleam/bytes_tree
3
import gleam/http/request.{type Request as HttpRequest}
4
import gleam/http/response.{type Response as HttpResponse}
5
import gleam/option
···
63
chunk: Result(mist.Chunk, mist.ReadError),
64
) -> Result(internal.Read, Nil) {
65
chunk
66
+
|> result.replace_error(Nil)
67
|> result.map(fn(chunk) {
68
case chunk {
69
mist.Done -> internal.ReadingFinished
···
75
76
fn mist_response(response: wisp.Response) -> HttpResponse(mist.ResponseData) {
77
let body = case response.body {
78
+
wisp.Empty -> mist.Bytes(bytes_tree.new())
79
+
wisp.Text(text) -> mist.Bytes(bytes_tree.from_string_tree(text))
80
wisp.Bytes(bytes) -> mist.Bytes(bytes)
81
wisp.File(path) -> mist_send_file(path)
82
}
···
90
Error(error) -> {
91
wisp.log_error(string.inspect(error))
92
// TODO: return 500
93
+
mist.Bytes(bytes_tree.new())
94
}
95
}
96
}
+30
-32
src/wisp.gleam
+30
-32
src/wisp.gleam
···
1
import exception
2
import gleam/bit_array
3
import gleam/bool
4
-
import gleam/bytes_builder.{type BytesBuilder}
5
import gleam/crypto
6
import gleam/dict.{type Dict}
7
import gleam/dynamic.{type Dynamic}
···
19
import gleam/option.{type Option}
20
import gleam/result
21
import gleam/string
22
-
import gleam/string_builder.{type StringBuilder}
23
import gleam/uri
24
import logging
25
import marceau
···
35
pub type Body {
36
/// A body of unicode text.
37
///
38
-
/// The body is represented using a `StringBuilder`. If you have a `String`
39
-
/// you can use the `string_builder.from_string` function to convert it.
40
///
41
-
Text(StringBuilder)
42
/// A body of binary data.
43
///
44
-
/// The body is represented using a `BytesBuilder`. If you have a `BitArray`
45
-
/// you can use the `bytes_builder.from_bit_array` function to convert it.
46
///
47
-
Bytes(BytesBuilder)
48
/// A body of the contents of a file.
49
///
50
/// This will be sent efficiently using the `send_file` function of the
···
146
/// # Examples
147
///
148
/// ```gleam
149
/// response(200)
150
-
/// |> file_download_from_memory(named: "myfile.txt", containing: "Hello, Joe!")
151
/// // -> Response(
152
/// // 200,
153
/// // [#("content-disposition", "attachment; filename=\"myfile.txt\"")],
···
158
pub fn file_download_from_memory(
159
response: Response,
160
named name: String,
161
-
containing data: BytesBuilder,
162
) -> Response {
163
let name = uri.percent_encode(name)
164
response
···
177
/// # Examples
178
///
179
/// ```gleam
180
-
/// let body = string_builder.from_string("<h1>Hello, Joe!</h1>")
181
/// html_response(body, 200)
182
/// // -> Response(200, [#("content-type", "text/html")], Text(body))
183
/// ```
184
///
185
-
pub fn html_response(html: StringBuilder, status: Int) -> Response {
186
HttpResponse(
187
status,
188
[#("content-type", "text/html; charset=utf-8")],
···
198
/// # Examples
199
///
200
/// ```gleam
201
-
/// let body = string_builder.from_string("{\"name\": \"Joe\"}")
202
/// json_response(body, 200)
203
/// // -> Response(200, [#("content-type", "application/json")], Text(body))
204
/// ```
205
///
206
-
pub fn json_response(json: StringBuilder, status: Int) -> Response {
207
HttpResponse(
208
status,
209
[#("content-type", "application/json; charset=utf-8")],
···
219
/// # Examples
220
///
221
/// ```gleam
222
-
/// let body = string_builder.from_string("<h1>Hello, Joe!</h1>")
223
/// response(201)
224
/// |> html_body(body)
225
/// // -> Response(201, [#("content-type", "text/html; charset=utf-8")], Text(body))
226
/// ```
227
///
228
-
pub fn html_body(response: Response, html: StringBuilder) -> Response {
229
response
230
|> response.set_body(Text(html))
231
|> response.set_header("content-type", "text/html; charset=utf-8")
···
239
/// # Examples
240
///
241
/// ```gleam
242
-
/// let body = string_builder.from_string("{\"name\": \"Joe\"}")
243
/// response(201)
244
/// |> json_body(body)
245
/// // -> Response(201, [#("content-type", "application/json; charset=utf-8")], Text(body))
246
/// ```
247
///
248
-
pub fn json_body(response: Response, json: StringBuilder) -> Response {
249
response
250
|> response.set_body(Text(json))
251
|> response.set_header("content-type", "application/json; charset=utf-8")
252
}
253
254
-
/// Set the body of a response to a given string builder.
255
///
256
/// You likely want to also set the request `content-type` header to an
257
/// appropriate value for the format of the content.
···
259
/// # Examples
260
///
261
/// ```gleam
262
-
/// let body = string_builder.from_string("Hello, Joe!")
263
/// response(201)
264
-
/// |> string_builder_body(body)
265
/// // -> Response(201, [], Text(body))
266
/// ```
267
///
268
-
pub fn string_builder_body(
269
-
response: Response,
270
-
content: StringBuilder,
271
-
) -> Response {
272
response
273
|> response.set_body(Text(content))
274
}
275
276
-
/// Set the body of a response to a given string builder.
277
///
278
/// You likely want to also set the request `content-type` header to an
279
/// appropriate value for the format of the content.
···
287
/// // -> Response(
288
/// // 201,
289
/// // [],
290
-
/// // Text(string_builder.from_string("Hello, Joe"))
291
/// // )
292
/// ```
293
///
294
pub fn string_body(response: Response, content: String) -> Response {
295
response
296
-
|> response.set_body(Text(string_builder.from_string(content)))
297
}
298
299
/// Escape a string so that it can be safely included in a HTML document.
···
723
///
724
/// This limit only applies for files in a multipart body that get streamed to
725
/// disc. For headers and other content that gets read into memory use the
726
-
/// `max_files_size` limit.
727
///
728
pub fn set_max_files_size(request: Request, size: Int) -> Request {
729
internal.Connection(..request.body, max_files_size: size)
···
1475
http.Get, True -> {
1476
let path =
1477
path
1478
-
|> string.drop_left(string.length(prefix))
1479
|> string.replace(each: "..", with: "")
1480
|> internal.join_path(directory, _)
1481
···
1541
1542
/// Create a new temporary directory for the given request.
1543
///
1544
-
/// If you are using the `mist_handler` function or another compliant web server
1545
/// adapter then this file will be deleted for you when the request is complete.
1546
/// Otherwise you will need to call the `delete_temporary_files` function
1547
/// yourself.
···
1558
1559
/// Delete any temporary files created for the given request.
1560
///
1561
-
/// If you are using the `mist_handler` function or another compliant web server
1562
/// adapter then this file will be deleted for you when the request is complete.
1563
/// Otherwise you will need to call this function yourself.
1564
///
···
1
import exception
2
import gleam/bit_array
3
import gleam/bool
4
+
import gleam/bytes_tree.{type BytesTree}
5
import gleam/crypto
6
import gleam/dict.{type Dict}
7
import gleam/dynamic.{type Dynamic}
···
19
import gleam/option.{type Option}
20
import gleam/result
21
import gleam/string
22
+
import gleam/string_tree.{type StringTree}
23
import gleam/uri
24
import logging
25
import marceau
···
35
pub type Body {
36
/// A body of unicode text.
37
///
38
+
/// The body is represented using a `StringTree`. If you have a `String`
39
+
/// you can use the `string_tree.from_string` function to convert it.
40
///
41
+
Text(StringTree)
42
/// A body of binary data.
43
///
44
+
/// The body is represented using a `BytesTree`. If you have a `BitArray`
45
+
/// you can use the `bytes_tree.from_bit_array` function to convert it.
46
///
47
+
Bytes(BytesTree)
48
/// A body of the contents of a file.
49
///
50
/// This will be sent efficiently using the `send_file` function of the
···
146
/// # Examples
147
///
148
/// ```gleam
149
+
/// let content = bytes_tree.from_string("Hello, Joe!")
150
/// response(200)
151
+
/// |> file_download_from_memory(named: "myfile.txt", containing: content)
152
/// // -> Response(
153
/// // 200,
154
/// // [#("content-disposition", "attachment; filename=\"myfile.txt\"")],
···
159
pub fn file_download_from_memory(
160
response: Response,
161
named name: String,
162
+
containing data: BytesTree,
163
) -> Response {
164
let name = uri.percent_encode(name)
165
response
···
178
/// # Examples
179
///
180
/// ```gleam
181
+
/// let body = string_tree.from_string("<h1>Hello, Joe!</h1>")
182
/// html_response(body, 200)
183
/// // -> Response(200, [#("content-type", "text/html")], Text(body))
184
/// ```
185
///
186
+
pub fn html_response(html: StringTree, status: Int) -> Response {
187
HttpResponse(
188
status,
189
[#("content-type", "text/html; charset=utf-8")],
···
199
/// # Examples
200
///
201
/// ```gleam
202
+
/// let body = string_tree.from_string("{\"name\": \"Joe\"}")
203
/// json_response(body, 200)
204
/// // -> Response(200, [#("content-type", "application/json")], Text(body))
205
/// ```
206
///
207
+
pub fn json_response(json: StringTree, status: Int) -> Response {
208
HttpResponse(
209
status,
210
[#("content-type", "application/json; charset=utf-8")],
···
220
/// # Examples
221
///
222
/// ```gleam
223
+
/// let body = string_tree.from_string("<h1>Hello, Joe!</h1>")
224
/// response(201)
225
/// |> html_body(body)
226
/// // -> Response(201, [#("content-type", "text/html; charset=utf-8")], Text(body))
227
/// ```
228
///
229
+
pub fn html_body(response: Response, html: StringTree) -> Response {
230
response
231
|> response.set_body(Text(html))
232
|> response.set_header("content-type", "text/html; charset=utf-8")
···
240
/// # Examples
241
///
242
/// ```gleam
243
+
/// let body = string_tree.from_string("{\"name\": \"Joe\"}")
244
/// response(201)
245
/// |> json_body(body)
246
/// // -> Response(201, [#("content-type", "application/json; charset=utf-8")], Text(body))
247
/// ```
248
///
249
+
pub fn json_body(response: Response, json: StringTree) -> Response {
250
response
251
|> response.set_body(Text(json))
252
|> response.set_header("content-type", "application/json; charset=utf-8")
253
}
254
255
+
/// Set the body of a response to a given string tree.
256
///
257
/// You likely want to also set the request `content-type` header to an
258
/// appropriate value for the format of the content.
···
260
/// # Examples
261
///
262
/// ```gleam
263
+
/// let body = string_tree.from_string("Hello, Joe!")
264
/// response(201)
265
+
/// |> string_tree_body(body)
266
/// // -> Response(201, [], Text(body))
267
/// ```
268
///
269
+
pub fn string_tree_body(response: Response, content: StringTree) -> Response {
270
response
271
|> response.set_body(Text(content))
272
}
273
274
+
/// Set the body of a response to a given string.
275
///
276
/// You likely want to also set the request `content-type` header to an
277
/// appropriate value for the format of the content.
···
285
/// // -> Response(
286
/// // 201,
287
/// // [],
288
+
/// // Text(string_tree.from_string("Hello, Joe"))
289
/// // )
290
/// ```
291
///
292
pub fn string_body(response: Response, content: String) -> Response {
293
response
294
+
|> response.set_body(Text(string_tree.from_string(content)))
295
}
296
297
/// Escape a string so that it can be safely included in a HTML document.
···
721
///
722
/// This limit only applies for files in a multipart body that get streamed to
723
/// disc. For headers and other content that gets read into memory use the
724
+
/// `max_body_size` limit.
725
///
726
pub fn set_max_files_size(request: Request, size: Int) -> Request {
727
internal.Connection(..request.body, max_files_size: size)
···
1473
http.Get, True -> {
1474
let path =
1475
path
1476
+
|> string.drop_start(string.length(prefix))
1477
|> string.replace(each: "..", with: "")
1478
|> internal.join_path(directory, _)
1479
···
1539
1540
/// Create a new temporary directory for the given request.
1541
///
1542
+
/// If you are using the Mist adapter or another compliant web server
1543
/// adapter then this file will be deleted for you when the request is complete.
1544
/// Otherwise you will need to call the `delete_temporary_files` function
1545
/// yourself.
···
1556
1557
/// Delete any temporary files created for the given request.
1558
///
1559
+
/// If you are using the Mist adapter or another compliant web server
1560
/// adapter then this file will be deleted for you when the request is complete.
1561
/// Otherwise you will need to call this function yourself.
1562
///
+3
-3
test/wisp/testing_test.gleam
+3
-3
test/wisp/testing_test.gleam
···
2
import gleam/http/response
3
import gleam/json
4
import gleam/option.{None, Some}
5
-
import gleam/string_builder
6
import gleeunit/should
7
import wisp
8
import wisp/testing
···
502
503
pub fn string_body_text_test() {
504
wisp.ok()
505
-
|> response.set_body(wisp.Text(string_builder.from_string("Hello, Joe!")))
506
|> testing.string_body
507
|> should.equal("Hello, Joe!")
508
}
···
523
524
pub fn bit_array_body_text_test() {
525
wisp.ok()
526
-
|> response.set_body(wisp.Text(string_builder.from_string("Hello, Joe!")))
527
|> testing.bit_array_body
528
|> should.equal(<<"Hello, Joe!":utf8>>)
529
}
···
2
import gleam/http/response
3
import gleam/json
4
import gleam/option.{None, Some}
5
+
import gleam/string_tree
6
import gleeunit/should
7
import wisp
8
import wisp/testing
···
502
503
pub fn string_body_text_test() {
504
wisp.ok()
505
+
|> response.set_body(wisp.Text(string_tree.from_string("Hello, Joe!")))
506
|> testing.string_body
507
|> should.equal("Hello, Joe!")
508
}
···
523
524
pub fn bit_array_body_text_test() {
525
wisp.ok()
526
+
|> response.set_body(wisp.Text(string_tree.from_string("Hello, Joe!")))
527
|> testing.bit_array_body
528
|> should.equal(<<"Hello, Joe!":utf8>>)
529
}
+12
-12
test/wisp_test.gleam
+12
-12
test/wisp_test.gleam
···
11
import gleam/list
12
import gleam/set
13
import gleam/string
14
-
import gleam/string_builder
15
import gleeunit
16
import gleeunit/should
17
import simplifile
···
119
}
120
121
pub fn json_response_test() {
122
-
let body = string_builder.from_string("{\"one\":1,\"two\":2}")
123
let response = wisp.json_response(body, 201)
124
response.status
125
|> should.equal(201)
···
131
}
132
133
pub fn html_response_test() {
134
-
let body = string_builder.from_string("Hello, world!")
135
let response = wisp.html_response(body, 200)
136
response.status
137
|> should.equal(200)
···
143
}
144
145
pub fn html_body_test() {
146
-
let body = string_builder.from_string("Hello, world!")
147
let response =
148
wisp.method_not_allowed([http.Get])
149
|> wisp.html_body(body)
···
751
list.key_find(request.headers, "x-original-method")
752
|> should.equal(header)
753
754
-
string_builder.from_string("Hello!")
755
|> wisp.html_response(201)
756
}
757
···
761
|> should.equal(Response(
762
201,
763
[#("content-type", "text/html; charset=utf-8")],
764
-
wisp.Text(string_builder.from_string("Hello!")),
765
))
766
767
testing.get("/", [])
···
897
|> should.equal(Response(
898
200,
899
[],
900
-
wisp.Text(string_builder.from_string("Hello, world!")),
901
))
902
}
903
904
-
pub fn string_builder_body_test() {
905
wisp.ok()
906
-
|> wisp.string_builder_body(string_builder.from_string("Hello, world!"))
907
|> should.equal(Response(
908
200,
909
[],
910
-
wisp.Text(string_builder.from_string("Hello, world!")),
911
))
912
}
913
914
pub fn json_body_test() {
915
wisp.ok()
916
-
|> wisp.json_body(string_builder.from_string("{\"one\":1,\"two\":2}"))
917
|> should.equal(Response(
918
200,
919
[#("content-type", "application/json; charset=utf-8")],
920
-
wisp.Text(string_builder.from_string("{\"one\":1,\"two\":2}")),
921
))
922
}
923
···
11
import gleam/list
12
import gleam/set
13
import gleam/string
14
+
import gleam/string_tree
15
import gleeunit
16
import gleeunit/should
17
import simplifile
···
119
}
120
121
pub fn json_response_test() {
122
+
let body = string_tree.from_string("{\"one\":1,\"two\":2}")
123
let response = wisp.json_response(body, 201)
124
response.status
125
|> should.equal(201)
···
131
}
132
133
pub fn html_response_test() {
134
+
let body = string_tree.from_string("Hello, world!")
135
let response = wisp.html_response(body, 200)
136
response.status
137
|> should.equal(200)
···
143
}
144
145
pub fn html_body_test() {
146
+
let body = string_tree.from_string("Hello, world!")
147
let response =
148
wisp.method_not_allowed([http.Get])
149
|> wisp.html_body(body)
···
751
list.key_find(request.headers, "x-original-method")
752
|> should.equal(header)
753
754
+
string_tree.from_string("Hello!")
755
|> wisp.html_response(201)
756
}
757
···
761
|> should.equal(Response(
762
201,
763
[#("content-type", "text/html; charset=utf-8")],
764
+
wisp.Text(string_tree.from_string("Hello!")),
765
))
766
767
testing.get("/", [])
···
897
|> should.equal(Response(
898
200,
899
[],
900
+
wisp.Text(string_tree.from_string("Hello, world!")),
901
))
902
}
903
904
+
pub fn string_tree_body_test() {
905
wisp.ok()
906
+
|> wisp.string_tree_body(string_tree.from_string("Hello, world!"))
907
|> should.equal(Response(
908
200,
909
[],
910
+
wisp.Text(string_tree.from_string("Hello, world!")),
911
))
912
}
913
914
pub fn json_body_test() {
915
wisp.ok()
916
+
|> wisp.json_body(string_tree.from_string("{\"one\":1,\"two\":2}"))
917
|> should.equal(Response(
918
200,
919
[#("content-type", "application/json; charset=utf-8")],
920
+
wisp.Text(string_tree.from_string("{\"one\":1,\"two\":2}")),
921
))
922
}
923