diff options
| author | Owen Jacobson <owen@grimoire.ca> | 2025-06-17 02:11:45 -0400 |
|---|---|---|
| committer | Owen Jacobson <owen@grimoire.ca> | 2025-06-18 18:31:40 -0400 |
| commit | 4e3d5ccac99b24934c972e088cd7eb02bb95df06 (patch) | |
| tree | c94f5a42f7e734b81892c1289a1d2b566706ba7c /src/channel | |
| parent | 5ed96f8e8b9d9f19ee249f5c73a5a21ef6bca09f (diff) | |
Handlers are _named operations_, which can be exposed via routes.
Each domain module that exposes handlers does so through a `handlers` child module, ideally as a top-level symbol that can be plugged directly into Axum's `MethodRouter`. Modules could make exceptions to this - kill the doctrinaire inside yourself, after all - but none of the API modules that actually exist need such exceptions, and consistency is useful.
The related details of request types, URL types, response types, errors, &c &c are then organized into modules under `handlers`, along with their respective tests.
Diffstat (limited to 'src/channel')
| -rw-r--r-- | src/channel/handlers/create/mod.rs (renamed from src/channel/routes/post.rs) | 3 | ||||
| -rw-r--r-- | src/channel/handlers/create/test.rs (renamed from src/channel/routes/test.rs) | 53 | ||||
| -rw-r--r-- | src/channel/handlers/delete/mod.rs (renamed from src/channel/routes/channel/delete.rs) | 7 | ||||
| -rw-r--r-- | src/channel/handlers/delete/test.rs (renamed from src/channel/routes/channel/test/delete.rs) | 17 | ||||
| -rw-r--r-- | src/channel/handlers/mod.rs | 9 | ||||
| -rw-r--r-- | src/channel/handlers/send/mod.rs (renamed from src/channel/routes/channel/post.rs) | 6 | ||||
| -rw-r--r-- | src/channel/handlers/send/test.rs (renamed from src/channel/routes/channel/test/post.rs) | 14 | ||||
| -rw-r--r-- | src/channel/mod.rs | 2 | ||||
| -rw-r--r-- | src/channel/routes/channel/mod.rs | 9 | ||||
| -rw-r--r-- | src/channel/routes/channel/test/mod.rs | 2 | ||||
| -rw-r--r-- | src/channel/routes/mod.rs | 5 |
11 files changed, 65 insertions, 62 deletions
diff --git a/src/channel/routes/post.rs b/src/channel/handlers/create/mod.rs index 6ea9b61..2c860fc 100644 --- a/src/channel/routes/post.rs +++ b/src/channel/handlers/create/mod.rs @@ -13,6 +13,9 @@ use crate::{ token::extract::Identity, }; +#[cfg(test)] +mod test; + pub async fn handler( State(app): State<App>, _: Identity, // requires auth, but doesn't actually care who you are diff --git a/src/channel/routes/test.rs b/src/channel/handlers/create/test.rs index cba8f2e..3c770cf 100644 --- a/src/channel/routes/test.rs +++ b/src/channel/handlers/create/test.rs @@ -3,7 +3,6 @@ use std::future; use axum::extract::{Json, State}; use futures::stream::StreamExt as _; -use super::post; use crate::{ channel::app, name::Name, @@ -21,9 +20,9 @@ async fn new_channel() { // Call the endpoint let name = fixtures::channel::propose(); - let request = post::Request { name: name.clone() }; - let post::Response(response) = - post::handler(State(app.clone()), creator, fixtures::now(), Json(request)) + let request = super::Request { name: name.clone() }; + let super::Response(response) = + super::handler(State(app.clone()), creator, fixtures::now(), Json(request)) .await .expect("creating a channel in an empty app succeeds"); @@ -67,11 +66,11 @@ async fn duplicate_name() { // Call the endpoint - let request = post::Request { + let request = super::Request { name: channel.name.clone(), }; - let post::Error(error) = - post::handler(State(app.clone()), creator, fixtures::now(), Json(request)) + let super::Error(error) = + super::handler(State(app.clone()), creator, fixtures::now(), Json(request)) .await .expect_err("duplicate channel name should fail the request"); @@ -100,11 +99,11 @@ async fn conflicting_canonical_name() { // Call the endpoint - let request = post::Request { + let request = super::Request { name: conflicting_name.clone(), }; - let post::Error(error) = - post::handler(State(app.clone()), creator, fixtures::now(), Json(request)) + let super::Error(error) = + super::handler(State(app.clone()), creator, fixtures::now(), Json(request)) .await .expect_err("duplicate channel name should fail the request"); @@ -126,11 +125,15 @@ async fn invalid_name() { // Call the endpoint let name = fixtures::channel::propose_invalid_name(); - let request = post::Request { name: name.clone() }; - let post::Error(error) = - post::handler(State(app.clone()), creator, fixtures::now(), Json(request)) - .await - .expect_err("invalid channel name should fail the request"); + let request = super::Request { name: name.clone() }; + let super::Error(error) = crate::channel::handlers::create::handler( + State(app.clone()), + creator, + fixtures::now(), + Json(request), + ) + .await + .expect_err("invalid channel name should fail the request"); // Verify the structure of the response @@ -150,8 +153,8 @@ async fn name_reusable_after_delete() { // Call the endpoint (first time) - let request = post::Request { name: name.clone() }; - let post::Response(response) = post::handler( + let request = super::Request { name: name.clone() }; + let super::Response(response) = super::handler( State(app.clone()), creator.clone(), fixtures::now(), @@ -169,9 +172,9 @@ async fn name_reusable_after_delete() { // Call the endpoint (second time) - let request = post::Request { name: name.clone() }; - let post::Response(response) = - post::handler(State(app.clone()), creator, fixtures::now(), Json(request)) + let request = super::Request { name: name.clone() }; + let super::Response(response) = + super::handler(State(app.clone()), creator, fixtures::now(), Json(request)) .await .expect("creation succeeds after original channel deleted"); @@ -199,8 +202,8 @@ async fn name_reusable_after_expiry() { // Call the endpoint (first time) - let request = post::Request { name: name.clone() }; - let post::Response(_) = post::handler( + let request = super::Request { name: name.clone() }; + let super::Response(_) = super::handler( State(app.clone()), creator.clone(), fixtures::ancient(), @@ -218,9 +221,9 @@ async fn name_reusable_after_expiry() { // Call the endpoint (second time) - let request = post::Request { name: name.clone() }; - let post::Response(response) = - post::handler(State(app.clone()), creator, fixtures::now(), Json(request)) + let request = super::Request { name: name.clone() }; + let super::Response(response) = + super::handler(State(app.clone()), creator, fixtures::now(), Json(request)) .await .expect("creation succeeds after original channel expired"); diff --git a/src/channel/routes/channel/delete.rs b/src/channel/handlers/delete/mod.rs index 3db7772..b986bec 100644 --- a/src/channel/routes/channel/delete.rs +++ b/src/channel/handlers/delete/mod.rs @@ -6,15 +6,18 @@ use axum::{ use crate::{ app::App, - channel::{self, app}, + channel::{self, app, handlers::PathInfo}, clock::RequestedAt, error::{Internal, NotFound}, token::extract::Identity, }; +#[cfg(test)] +mod test; + pub async fn handler( State(app): State<App>, - Path(channel): Path<super::PathInfo>, + Path(channel): Path<PathInfo>, RequestedAt(deleted_at): RequestedAt, _: Identity, ) -> Result<Response, Error> { diff --git a/src/channel/routes/channel/test/delete.rs b/src/channel/handlers/delete/test.rs index bd9261d..b1e42ea 100644 --- a/src/channel/routes/channel/test/delete.rs +++ b/src/channel/handlers/delete/test.rs @@ -1,9 +1,6 @@ use axum::extract::{Path, State}; -use crate::{ - channel::{app, routes::channel::delete}, - test::fixtures, -}; +use crate::{channel::app, test::fixtures}; #[tokio::test] pub async fn valid_channel() { @@ -15,7 +12,7 @@ pub async fn valid_channel() { // Send the request let deleter = fixtures::identity::create(&app, &fixtures::now()).await; - let response = delete::handler( + let response = super::handler( State(app.clone()), Path(channel.id.clone()), fixtures::now(), @@ -44,7 +41,7 @@ pub async fn invalid_channel_id() { let deleter = fixtures::identity::create(&app, &fixtures::now()).await; let channel = fixtures::channel::fictitious(); - let delete::Error(error) = delete::handler( + let super::Error(error) = super::handler( State(app.clone()), Path(channel.clone()), fixtures::now(), @@ -73,7 +70,7 @@ pub async fn channel_deleted() { // Send the request let deleter = fixtures::identity::create(&app, &fixtures::now()).await; - let delete::Error(error) = delete::handler( + let super::Error(error) = super::handler( State(app.clone()), Path(channel.id.clone()), fixtures::now(), @@ -102,7 +99,7 @@ pub async fn channel_expired() { // Send the request let deleter = fixtures::identity::create(&app, &fixtures::now()).await; - let delete::Error(error) = delete::handler( + let super::Error(error) = super::handler( State(app.clone()), Path(channel.id.clone()), fixtures::now(), @@ -136,7 +133,7 @@ pub async fn channel_purged() { // Send the request let deleter = fixtures::identity::create(&app, &fixtures::now()).await; - let delete::Error(error) = delete::handler( + let super::Error(error) = super::handler( State(app.clone()), Path(channel.id.clone()), fixtures::now(), @@ -162,7 +159,7 @@ pub async fn channel_not_empty() { // Send the request let deleter = fixtures::identity::create(&app, &fixtures::now()).await; - let delete::Error(error) = delete::handler( + let super::Error(error) = super::handler( State(app.clone()), Path(channel.id.clone()), fixtures::now(), diff --git a/src/channel/handlers/mod.rs b/src/channel/handlers/mod.rs new file mode 100644 index 0000000..f2ffd0d --- /dev/null +++ b/src/channel/handlers/mod.rs @@ -0,0 +1,9 @@ +mod create; +mod delete; +mod send; + +pub use create::handler as create; +pub use delete::handler as delete; +pub use send::handler as send; + +type PathInfo = crate::channel::Id; diff --git a/src/channel/routes/channel/post.rs b/src/channel/handlers/send/mod.rs index 2547122..aa241e2 100644 --- a/src/channel/routes/channel/post.rs +++ b/src/channel/handlers/send/mod.rs @@ -4,6 +4,7 @@ use axum::{ response::{self, IntoResponse}, }; +use crate::channel::handlers::PathInfo; use crate::{ app::App, clock::RequestedAt, @@ -12,9 +13,12 @@ use crate::{ token::extract::Identity, }; +#[cfg(test)] +mod test; + pub async fn handler( State(app): State<App>, - Path(channel): Path<super::PathInfo>, + Path(channel): Path<PathInfo>, RequestedAt(sent_at): RequestedAt, identity: Identity, Json(request): Json<Request>, diff --git a/src/channel/routes/channel/test/post.rs b/src/channel/handlers/send/test.rs index d9527ac..f43f901 100644 --- a/src/channel/routes/channel/test/post.rs +++ b/src/channel/handlers/send/test.rs @@ -2,7 +2,7 @@ use axum::extract::{Json, Path, State}; use futures::stream::{self, StreamExt as _}; use crate::{ - channel::{self, routes::channel::post}, + channel, event::Sequenced, message::app::SendError, test::fixtures::{self, future::Expect as _}, @@ -25,9 +25,9 @@ async fn messages_in_order() { ]; for (sent_at, body) in &requests { - let request = post::Request { body: body.clone() }; + let request = super::Request { body: body.clone() }; - let _ = post::handler( + let _ = super::handler( State(app.clone()), Path(channel.id.clone()), sent_at.clone(), @@ -71,10 +71,10 @@ async fn nonexistent_channel() { let sent_at = fixtures::now(); let channel = channel::Id::generate(); - let request = post::Request { + let request = super::Request { body: fixtures::message::propose(), }; - let post::Error(error) = post::handler( + let super::Error(error) = super::handler( State(app), Path(channel.clone()), sent_at, @@ -109,10 +109,10 @@ async fn deleted_channel() { let sent_at = fixtures::now(); let channel = channel::Id::generate(); - let request = post::Request { + let request = super::Request { body: fixtures::message::propose(), }; - let post::Error(error) = post::handler( + let super::Error(error) = super::handler( State(app), Path(channel.clone()), sent_at, diff --git a/src/channel/mod.rs b/src/channel/mod.rs index feb00a9..bbaf33e 100644 --- a/src/channel/mod.rs +++ b/src/channel/mod.rs @@ -1,9 +1,9 @@ pub mod app; pub mod event; +pub mod handlers; mod history; mod id; pub mod repo; -pub mod routes; mod snapshot; mod validate; diff --git a/src/channel/routes/channel/mod.rs b/src/channel/routes/channel/mod.rs deleted file mode 100644 index 31a9142..0000000 --- a/src/channel/routes/channel/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -use crate::channel::Id; - -pub mod delete; -pub mod post; - -#[cfg(test)] -mod test; - -type PathInfo = Id; diff --git a/src/channel/routes/channel/test/mod.rs b/src/channel/routes/channel/test/mod.rs deleted file mode 100644 index 78bf86e..0000000 --- a/src/channel/routes/channel/test/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -mod delete; -mod post; diff --git a/src/channel/routes/mod.rs b/src/channel/routes/mod.rs deleted file mode 100644 index bd90721..0000000 --- a/src/channel/routes/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub mod channel; -pub mod post; - -#[cfg(test)] -mod test; |
