diff options
| author | ojacobson <ojacobson@noreply.codeberg.org> | 2025-06-21 04:22:52 +0200 |
|---|---|---|
| committer | ojacobson <ojacobson@noreply.codeberg.org> | 2025-06-21 04:22:52 +0200 |
| commit | cd1dc0dab4b46bc5712070812192d5ce34071470 (patch) | |
| tree | c94f5a42f7e734b81892c1289a1d2b566706ba7c /src/channel | |
| parent | d84ba5cd09b713fac2f193d5c05af7415ea6742d (diff) | |
| parent | 4e3d5ccac99b24934c972e088cd7eb02bb95df06 (diff) | |
Reorganize and consolidate HTTP routes.
HTTP routes are now defined in a single, unified module, pulling them out of the topical modules they were formerly part of.
This is intended to improve the navigability of the codebase. Previously, finding the handler corresponding to a specific endpoint required prior familiarity, though in practice you could usually guess from topic area. Now, all routes are defined in one place; if you know the path, you can read down the list to find the handler.
Handlers themselves live with the domain they are most appropriately "part of," generally (in this version, universally) in a `handlers` submodule. The handlers themselves have been flattened down; rather than representing a path and a method, they now represent a named operation (which is suspiciously similar to the path in most cases). This means that we no longer have constructs like `crate::ui::routes::ch::channel` - it's now `crate::ui::handlers::channel` instead.
## Disclaimer
I Solemnly Swear I Didn't Change Any Handlers.
## Prior art
I've inadvertently reinvented Django's `urls.py` convention, and I've opted to lean into that.
Merges flatter-routes-reorg into main.
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 | 4 | ||||
| -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 | 19 |
11 files changed, 66 insertions, 77 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 d5ba828..bbaf33e 100644 --- a/src/channel/mod.rs +++ b/src/channel/mod.rs @@ -1,10 +1,10 @@ pub mod app; pub mod event; +pub mod handlers; mod history; mod id; pub mod repo; -mod routes; mod snapshot; mod validate; -pub use self::{event::Event, history::History, id::Id, routes::router, snapshot::Channel}; +pub use self::{event::Event, history::History, id::Id, snapshot::Channel}; 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 c917348..0000000 --- a/src/channel/routes/mod.rs +++ /dev/null @@ -1,19 +0,0 @@ -use axum::{ - Router, - routing::{delete, post}, -}; - -use crate::app::App; - -mod channel; -mod post; - -#[cfg(test)] -mod test; - -pub fn router() -> Router<App> { - Router::new() - .route("/api/channels", post(post::handler)) - .route("/api/channels/{channel}", post(channel::post::handler)) - .route("/api/channels/{channel}", delete(channel::delete::handler)) -} |
