🧚 A practical web framework for Gleam

charset=utf-8

Closes https://github.com/gleam-wisp/wisp/issues/86

+5
CHANGELOG.md
··· 1 # Changelog 2 3 ## v0.15.0 - 2024-05-12 4 5 - The `mist` version constraint has been increased to >= 1.2.0.
··· 1 # Changelog 2 3 + ## v0.16.0 - Unreleased 4 + 5 + - HTML and JSON body functions now include `charset=utf-8` in the content-type 6 + header. 7 + 8 ## v0.15.0 - 2024-05-12 9 10 - The `mist` version constraint has been increased to >= 1.2.0.
+20 -7
src/wisp.gleam
··· 268 /// ``` 269 /// 270 pub fn html_response(html: StringBuilder, status: Int) -> Response { 271 - HttpResponse(status, [#("content-type", "text/html")], Text(html)) 272 } 273 274 /// Create a JSON response. ··· 285 /// ``` 286 /// 287 pub fn json_response(json: StringBuilder, status: Int) -> Response { 288 - HttpResponse(status, [#("content-type", "application/json")], Text(json)) 289 } 290 291 /// Set the body of a response to a given HTML document, and set the ··· 299 /// let body = string_builder.from_string("<h1>Hello, Joe!</h1>") 300 /// response(201) 301 /// |> html_body(body) 302 - /// // -> Response(201, [#("content-type", "text/html")], Text(body)) 303 /// ``` 304 /// 305 pub fn html_body(response: Response, html: StringBuilder) -> Response { 306 response 307 |> response.set_body(Text(html)) 308 - |> response.set_header("content-type", "text/html") 309 } 310 311 /// Set the body of a response to a given JSON document, and set the ··· 319 /// let body = string_builder.from_string("{\"name\": \"Joe\"}") 320 /// response(201) 321 /// |> json_body(body) 322 - /// // -> Response(201, [#("content-type", "application/json")], Text(body)) 323 /// ``` 324 /// 325 pub fn json_body(response: Response, json: StringBuilder) -> Response { 326 response 327 |> response.set_body(Text(json)) 328 - |> response.set_header("content-type", "application/json") 329 } 330 331 /// Set the body of a response to a given string builder. ··· 1598 |> result.unwrap("") 1599 |> marceau.extension_to_mime_type 1600 1601 case simplifile.is_file(path) { 1602 Ok(True) -> 1603 response.new(200) 1604 - |> response.set_header("content-type", mime_type) 1605 |> response.set_body(File(path)) 1606 _ -> handler() 1607 }
··· 268 /// ``` 269 /// 270 pub fn html_response(html: StringBuilder, status: Int) -> Response { 271 + HttpResponse( 272 + status, 273 + [#("content-type", "text/html; charset=utf-8")], 274 + Text(html), 275 + ) 276 } 277 278 /// Create a JSON response. ··· 289 /// ``` 290 /// 291 pub fn json_response(json: StringBuilder, status: Int) -> Response { 292 + HttpResponse( 293 + status, 294 + [#("content-type", "application/json; charset=utf-8")], 295 + Text(json), 296 + ) 297 } 298 299 /// Set the body of a response to a given HTML document, and set the ··· 307 /// let body = string_builder.from_string("<h1>Hello, Joe!</h1>") 308 /// response(201) 309 /// |> html_body(body) 310 + /// // -> Response(201, [#("content-type", "text/html; charset=utf-8")], Text(body)) 311 /// ``` 312 /// 313 pub fn html_body(response: Response, html: StringBuilder) -> Response { 314 response 315 |> response.set_body(Text(html)) 316 + |> response.set_header("content-type", "text/html; charset=utf-8") 317 } 318 319 /// Set the body of a response to a given JSON document, and set the ··· 327 /// let body = string_builder.from_string("{\"name\": \"Joe\"}") 328 /// response(201) 329 /// |> json_body(body) 330 + /// // -> Response(201, [#("content-type", "application/json; charset=utf-8")], Text(body)) 331 /// ``` 332 /// 333 pub fn json_body(response: Response, json: StringBuilder) -> Response { 334 response 335 |> response.set_body(Text(json)) 336 + |> response.set_header("content-type", "application/json; charset=utf-8") 337 } 338 339 /// Set the body of a response to a given string builder. ··· 1606 |> result.unwrap("") 1607 |> marceau.extension_to_mime_type 1608 1609 + let content_type = case mime_type { 1610 + "application/json" | "text/" <> _ -> mime_type <> "; charset=utf-8" 1611 + _ -> mime_type 1612 + } 1613 + 1614 case simplifile.is_file(path) { 1615 Ok(True) -> 1616 response.new(200) 1617 + |> response.set_header("content-type", content_type) 1618 |> response.set_body(File(path)) 1619 _ -> handler() 1620 }
test/fixture.dat

This is a binary file and will not be displayed.

+28 -10
test/wisp_test.gleam
··· 123 response.status 124 |> should.equal(201) 125 response.headers 126 - |> should.equal([#("content-type", "application/json")]) 127 response 128 |> testing.string_body 129 |> should.equal("{\"one\":1,\"two\":2}") ··· 135 response.status 136 |> should.equal(200) 137 response.headers 138 - |> should.equal([#("content-type", "text/html")]) 139 response 140 |> testing.string_body 141 |> should.equal("Hello, world!") ··· 149 response.status 150 |> should.equal(405) 151 response.headers 152 - |> should.equal([#("allow", "GET"), #("content-type", "text/html")]) 153 response 154 |> testing.string_body 155 |> should.equal("Hello, world!") ··· 359 response.status 360 |> should.equal(200) 361 response.headers 362 - |> should.equal([#("content-type", "text/plain")]) 363 response.body 364 |> should.equal(wisp.File("./test/fixture.txt")) 365 ··· 370 response.status 371 |> should.equal(200) 372 response.headers 373 - |> should.equal([#("content-type", "application/json")]) 374 response.body 375 |> should.equal(wisp.File("./test/fixture.json")) 376 377 // Get something not handled by the static file server 378 let response = 379 testing.get("/stuff/this-does-not-exist", []) ··· 397 response.status 398 |> should.equal(200) 399 response.headers 400 - |> should.equal([#("content-type", "text/plain")]) 401 response.body 402 |> should.equal(wisp.File("./test/fixture.txt")) 403 } ··· 413 response.status 414 |> should.equal(200) 415 response.headers 416 - |> should.equal([#("content-type", "text/plain")]) 417 response.body 418 |> should.equal(wisp.File("./test/fixture.txt")) 419 } ··· 733 |> handler(Error(Nil)) 734 |> should.equal(Response( 735 201, 736 - [#("content-type", "text/html")], 737 wisp.Text(string_builder.from_string("Hello!")), 738 )) 739 740 testing.get("/", []) 741 |> request.set_method(http.Head) 742 |> handler(Ok("HEAD")) 743 - |> should.equal(Response(201, [#("content-type", "text/html")], wisp.Empty)) 744 745 testing.get("/", []) 746 |> request.set_method(http.Post) ··· 885 |> wisp.json_body(string_builder.from_string("{\"one\":1,\"two\":2}")) 886 |> should.equal(Response( 887 200, 888 - [#("content-type", "application/json")], 889 wisp.Text(string_builder.from_string("{\"one\":1,\"two\":2}")), 890 )) 891 }
··· 123 response.status 124 |> should.equal(201) 125 response.headers 126 + |> should.equal([#("content-type", "application/json; charset=utf-8")]) 127 response 128 |> testing.string_body 129 |> should.equal("{\"one\":1,\"two\":2}") ··· 135 response.status 136 |> should.equal(200) 137 response.headers 138 + |> should.equal([#("content-type", "text/html; charset=utf-8")]) 139 response 140 |> testing.string_body 141 |> should.equal("Hello, world!") ··· 149 response.status 150 |> should.equal(405) 151 response.headers 152 + |> should.equal([ 153 + #("allow", "GET"), 154 + #("content-type", "text/html; charset=utf-8"), 155 + ]) 156 response 157 |> testing.string_body 158 |> should.equal("Hello, world!") ··· 362 response.status 363 |> should.equal(200) 364 response.headers 365 + |> should.equal([#("content-type", "text/plain; charset=utf-8")]) 366 response.body 367 |> should.equal(wisp.File("./test/fixture.txt")) 368 ··· 373 response.status 374 |> should.equal(200) 375 response.headers 376 + |> should.equal([#("content-type", "application/json; charset=utf-8")]) 377 response.body 378 |> should.equal(wisp.File("./test/fixture.json")) 379 380 + // Get some other file 381 + let response = 382 + testing.get("/stuff/test/fixture.dat", []) 383 + |> handler 384 + response.status 385 + |> should.equal(200) 386 + response.headers 387 + |> should.equal([#("content-type", "application/octet-stream")]) 388 + response.body 389 + |> should.equal(wisp.File("./test/fixture.dat")) 390 + 391 // Get something not handled by the static file server 392 let response = 393 testing.get("/stuff/this-does-not-exist", []) ··· 411 response.status 412 |> should.equal(200) 413 response.headers 414 + |> should.equal([#("content-type", "text/plain; charset=utf-8")]) 415 response.body 416 |> should.equal(wisp.File("./test/fixture.txt")) 417 } ··· 427 response.status 428 |> should.equal(200) 429 response.headers 430 + |> should.equal([#("content-type", "text/plain; charset=utf-8")]) 431 response.body 432 |> should.equal(wisp.File("./test/fixture.txt")) 433 } ··· 747 |> handler(Error(Nil)) 748 |> should.equal(Response( 749 201, 750 + [#("content-type", "text/html; charset=utf-8")], 751 wisp.Text(string_builder.from_string("Hello!")), 752 )) 753 754 testing.get("/", []) 755 |> request.set_method(http.Head) 756 |> handler(Ok("HEAD")) 757 + |> should.equal(Response( 758 + 201, 759 + [#("content-type", "text/html; charset=utf-8")], 760 + wisp.Empty, 761 + )) 762 763 testing.get("/", []) 764 |> request.set_method(http.Post) ··· 903 |> wisp.json_body(string_builder.from_string("{\"one\":1,\"two\":2}")) 904 |> should.equal(Response( 905 200, 906 + [#("content-type", "application/json; charset=utf-8")], 907 wisp.Text(string_builder.from_string("{\"one\":1,\"two\":2}")), 908 )) 909 }