it works
This commit is contained in:
commit
c7b8b6185a
8 changed files with 248 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
build/
|
||||
members.db
|
28
README.md
Normal file
28
README.md
Normal file
|
@ -0,0 +1,28 @@
|
|||
# Wisp Example: Routing
|
||||
|
||||
```sh
|
||||
gleam run # Run the server
|
||||
gleam test # Run the tests
|
||||
```
|
||||
|
||||
This example shows how to route requests to different handlers based on the
|
||||
request path and method.
|
||||
|
||||
This example is based off of the ["Hello, World!" example][hello], so read that
|
||||
one first. The additions are detailed here and commented in the code.
|
||||
|
||||
[hello]: https://github.com/lpil/wisp/tree/main/examples/00-hello-world
|
||||
|
||||
### `app/router` module
|
||||
|
||||
The `handle_request` function now pattern matches on the request and calls other
|
||||
request handler functions depending on where the request should go.
|
||||
|
||||
### `app_test` module
|
||||
|
||||
Tests have been added for each of the routes. The `wisp/testing` module is used
|
||||
to create different requests to test the application with.
|
||||
|
||||
### Other files
|
||||
|
||||
No changes have been made to the other files.
|
15
gleam.toml
Normal file
15
gleam.toml
Normal file
|
@ -0,0 +1,15 @@
|
|||
name = "ring"
|
||||
version = "1.0.0"
|
||||
description = "A Wisp example"
|
||||
gleam = ">= 0.32.0"
|
||||
|
||||
[dependencies]
|
||||
gleam_stdlib = "~> 0.30"
|
||||
gleam_erlang = "~> 0.23"
|
||||
mist = "~> 0.14"
|
||||
gleam_http = "~> 3.5"
|
||||
wisp = "~> 0.14"
|
||||
sqlight = "~> 0.9"
|
||||
|
||||
[dev-dependencies]
|
||||
gleeunit = "~> 1.0"
|
32
manifest.toml
Normal file
32
manifest.toml
Normal file
|
@ -0,0 +1,32 @@
|
|||
# This file was generated by Gleam
|
||||
# You typically do not need to edit this file
|
||||
|
||||
packages = [
|
||||
{ name = "esqlite", version = "0.8.6", build_tools = ["rebar3"], requirements = [], otp_app = "esqlite", source = "hex", outer_checksum = "607E45F4DA42601D8F530979417F57A4CD629AB49085891849302057E68EA188" },
|
||||
{ name = "exception", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "exception", source = "hex", outer_checksum = "F5580D584F16A20B7FCDCABF9E9BE9A2C1F6AC4F9176FA6DD0B63E3B20D450AA" },
|
||||
{ name = "filepath", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "EFB6FF65C98B2A16378ABC3EE2B14124168C0CE5201553DE652E2644DCFDB594" },
|
||||
{ name = "gleam_crypto", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_crypto", source = "hex", outer_checksum = "ADD058DEDE8F0341F1ADE3AAC492A224F15700829D9A3A3F9ADF370F875C51B7" },
|
||||
{ name = "gleam_erlang", version = "0.25.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "054D571A7092D2A9727B3E5D183B7507DAB0DA41556EC9133606F09C15497373" },
|
||||
{ name = "gleam_http", version = "3.6.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_http", source = "hex", outer_checksum = "8C07DF9DF8CC7F054C650839A51C30A7D3C26482AC241C899C1CEA86B22DBE51" },
|
||||
{ name = "gleam_json", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "thoas"], otp_app = "gleam_json", source = "hex", outer_checksum = "8B197DD5D578EA6AC2C0D4BDC634C71A5BCA8E7DB5F47091C263ECB411A60DF3" },
|
||||
{ name = "gleam_otp", version = "0.10.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "0B04FE915ACECE539B317F9652CAADBBC0F000184D586AAAF2D94C100945D72B" },
|
||||
{ name = "gleam_stdlib", version = "0.36.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "C0D14D807FEC6F8A08A7C9EF8DFDE6AE5C10E40E21325B2B29365965D82EB3D4" },
|
||||
{ name = "gleeunit", version = "1.0.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "D364C87AFEB26BDB4FB8A5ABDE67D635DC9FA52D6AB68416044C35B096C6882D" },
|
||||
{ name = "glisten", version = "0.11.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_otp", "gleam_stdlib"], otp_app = "glisten", source = "hex", outer_checksum = "73BC09C8487C2FFC0963BFAB33ED2F0D636FDFA43B966E65C1251CBAB8458099" },
|
||||
{ name = "logging", version = "1.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "logging", source = "hex", outer_checksum = "82C112ED9B6C30C1772A6FE2613B94B13F62EA35F5869A2630D13948D297BD39" },
|
||||
{ name = "marceau", version = "1.1.0", build_tools = ["gleam"], requirements = [], otp_app = "marceau", source = "hex", outer_checksum = "1AAD727A30BE0F95562C3403BB9B27C823797AD90037714255EEBF617B1CDA81" },
|
||||
{ name = "mist", version = "0.17.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_http", "gleam_otp", "gleam_stdlib", "glisten"], otp_app = "mist", source = "hex", outer_checksum = "DA8ACEE52C1E4892A75181B3166A4876D8CBC69D555E4770250BC84C80F75524" },
|
||||
{ name = "simplifile", version = "1.6.1", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "B75D3C64E526D9D7EDEED5F3BA31DAAF5F2B4D80A4183FE17FDB02ED526E4E96" },
|
||||
{ name = "sqlight", version = "0.9.0", build_tools = ["gleam"], requirements = ["esqlite", "gleam_stdlib"], otp_app = "sqlight", source = "hex", outer_checksum = "2D9C9BA420A5E7DCE7DB2DAAE4CAB0BE6218BEB48FD1531C583550B3D1316E94" },
|
||||
{ name = "thoas", version = "0.4.1", build_tools = ["rebar3"], requirements = [], otp_app = "thoas", source = "hex", outer_checksum = "4918D50026C073C4AB1388437132C77A6F6F7C8AC43C60C13758CC0ADCE2134E" },
|
||||
{ name = "wisp", version = "0.14.0", build_tools = ["gleam"], requirements = ["exception", "gleam_crypto", "gleam_erlang", "gleam_http", "gleam_json", "gleam_stdlib", "logging", "marceau", "mist", "simplifile"], otp_app = "wisp", source = "hex", outer_checksum = "9F5453AF1F9275E6F8707BC815D6A6A9DF41551921B16FBDBA52883773BAE684" },
|
||||
]
|
||||
|
||||
[requirements]
|
||||
gleam_erlang = { version = "~> 0.23" }
|
||||
gleam_http = { version = "~> 3.5" }
|
||||
gleam_stdlib = { version = "~> 0.30" }
|
||||
gleeunit = { version = "~> 1.0" }
|
||||
mist = { version = "~> 0.14" }
|
||||
sqlight = { version = "~> 0.9"}
|
||||
wisp = { version = "~> 0.14" }
|
17
src/ring.gleam
Normal file
17
src/ring.gleam
Normal file
|
@ -0,0 +1,17 @@
|
|||
import gleam/erlang/process
|
||||
import mist
|
||||
import wisp
|
||||
import ring/router
|
||||
|
||||
pub fn main() {
|
||||
wisp.configure_logger()
|
||||
let secret_key_base = wisp.random_string(64)
|
||||
|
||||
let assert Ok(_) =
|
||||
wisp.mist_handler(router.handle_request, secret_key_base)
|
||||
|> mist.new
|
||||
|> mist.port(8000)
|
||||
|> mist.start_http
|
||||
|
||||
process.sleep_forever()
|
||||
}
|
66
src/ring/router.gleam
Normal file
66
src/ring/router.gleam
Normal file
|
@ -0,0 +1,66 @@
|
|||
import wisp.{type Request, type Response}
|
||||
import gleam/string_builder
|
||||
import gleam/http.{Get}
|
||||
import gleam/io
|
||||
import gleam/dynamic
|
||||
import ring/web
|
||||
import sqlight
|
||||
|
||||
pub fn handle_request(req: Request) -> Response {
|
||||
use req <- web.middleware(req)
|
||||
|
||||
case wisp.path_segments(req) {
|
||||
[] -> home_page(req)
|
||||
|
||||
[hash, "previous"] -> handle_previous(hash)
|
||||
[hash, "next"] -> handle_next(hash)
|
||||
|
||||
_ -> wisp.not_found()
|
||||
}
|
||||
}
|
||||
|
||||
type Row {
|
||||
Row(String)
|
||||
}
|
||||
|
||||
fn handle_previous(hash) {
|
||||
let db_path = "members.db"
|
||||
use conn <- sqlight.with_connection(db_path)
|
||||
let previous =
|
||||
sqlight.query(
|
||||
"select previous from ring where hash = ?",
|
||||
on: conn,
|
||||
with: [sqlight.text(hash)],
|
||||
expecting: dynamic.decode1(Row, dynamic.element(0, dynamic.string)),
|
||||
)
|
||||
case previous {
|
||||
Ok([Row(previous_link)]) -> wisp.redirect(previous_link)
|
||||
_ -> wisp.not_found()
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_next(hash) {
|
||||
let db_path = "members.db"
|
||||
use conn <- sqlight.with_connection(db_path)
|
||||
let next =
|
||||
sqlight.query(
|
||||
"select next from ring where hash = ?",
|
||||
on: conn,
|
||||
with: [sqlight.text(hash)],
|
||||
expecting: dynamic.decode1(Row, dynamic.element(0, dynamic.string)),
|
||||
)
|
||||
case next {
|
||||
Ok([Row(next_link)]) -> wisp.redirect(next_link)
|
||||
_ -> wisp.not_found()
|
||||
}
|
||||
}
|
||||
|
||||
fn home_page(req: Request) -> Response {
|
||||
// The home page can only be accessed via GET requests, so this middleware is
|
||||
// used to return a 405: Method Not Allowed response for all other methods.
|
||||
use <- wisp.require_method(req, Get)
|
||||
|
||||
let html = string_builder.from_string("Hello, Joe!")
|
||||
wisp.ok()
|
||||
|> wisp.html_body(html)
|
||||
}
|
13
src/ring/web.gleam
Normal file
13
src/ring/web.gleam
Normal file
|
@ -0,0 +1,13 @@
|
|||
import wisp
|
||||
|
||||
pub fn middleware(
|
||||
req: wisp.Request,
|
||||
handle_request: fn(wisp.Request) -> wisp.Response,
|
||||
) -> wisp.Response {
|
||||
let req = wisp.method_override(req)
|
||||
use <- wisp.log_request(req)
|
||||
use <- wisp.rescue_crashes
|
||||
use req <- wisp.handle_head(req)
|
||||
|
||||
handle_request(req)
|
||||
}
|
75
test/app_test.gleam
Normal file
75
test/app_test.gleam
Normal file
|
@ -0,0 +1,75 @@
|
|||
import gleeunit
|
||||
import gleeunit/should
|
||||
import wisp/testing
|
||||
import app/router
|
||||
|
||||
pub fn main() {
|
||||
gleeunit.main()
|
||||
}
|
||||
|
||||
pub fn get_home_page_test() {
|
||||
let request = testing.get("/", [])
|
||||
let response = router.handle_request(request)
|
||||
|
||||
response.status
|
||||
|> should.equal(200)
|
||||
|
||||
response.headers
|
||||
|> should.equal([#("content-type", "text/html")])
|
||||
|
||||
response
|
||||
|> testing.string_body
|
||||
|> should.equal("Hello, Joe!")
|
||||
}
|
||||
|
||||
pub fn post_home_page_test() {
|
||||
let request = testing.post("/", [], "a body")
|
||||
let response = router.handle_request(request)
|
||||
response.status
|
||||
|> should.equal(405)
|
||||
}
|
||||
|
||||
pub fn page_not_found_test() {
|
||||
let request = testing.get("/nothing-here", [])
|
||||
let response = router.handle_request(request)
|
||||
response.status
|
||||
|> should.equal(404)
|
||||
}
|
||||
|
||||
pub fn get_comments_test() {
|
||||
let request = testing.get("/comments", [])
|
||||
let response = router.handle_request(request)
|
||||
response.status
|
||||
|> should.equal(200)
|
||||
}
|
||||
|
||||
pub fn post_comments_test() {
|
||||
let request = testing.post("/comments", [], "")
|
||||
let response = router.handle_request(request)
|
||||
response.status
|
||||
|> should.equal(201)
|
||||
}
|
||||
|
||||
pub fn delete_comments_test() {
|
||||
let request = testing.delete("/comments", [], "")
|
||||
let response = router.handle_request(request)
|
||||
response.status
|
||||
|> should.equal(405)
|
||||
}
|
||||
|
||||
pub fn get_comment_test() {
|
||||
let request = testing.get("/comments/123", [])
|
||||
let response = router.handle_request(request)
|
||||
response.status
|
||||
|> should.equal(200)
|
||||
response
|
||||
|> testing.string_body
|
||||
|> should.equal("Comment with id 123")
|
||||
}
|
||||
|
||||
pub fn delete_comment_test() {
|
||||
let request = testing.delete("/comments/123", [], "")
|
||||
let response = router.handle_request(request)
|
||||
response.status
|
||||
|> should.equal(405)
|
||||
}
|
Loading…
Reference in a new issue