summaryrefslogtreecommitdiff
path: root/src/message
diff options
context:
space:
mode:
authorOwen Jacobson <owen@grimoire.ca>2025-06-17 02:11:45 -0400
committerOwen Jacobson <owen@grimoire.ca>2025-06-18 18:31:40 -0400
commit4e3d5ccac99b24934c972e088cd7eb02bb95df06 (patch)
treec94f5a42f7e734b81892c1289a1d2b566706ba7c /src/message
parent5ed96f8e8b9d9f19ee249f5c73a5a21ef6bca09f (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/message')
-rw-r--r--src/message/handlers/delete/mod.rs55
-rw-r--r--src/message/handlers/delete/test.rs (renamed from src/message/routes/message/test.rs)13
-rw-r--r--src/message/handlers/mod.rs3
-rw-r--r--src/message/mod.rs2
-rw-r--r--src/message/routes/message/mod.rs61
-rw-r--r--src/message/routes/mod.rs1
6 files changed, 65 insertions, 70 deletions
diff --git a/src/message/handlers/delete/mod.rs b/src/message/handlers/delete/mod.rs
new file mode 100644
index 0000000..5eac4eb
--- /dev/null
+++ b/src/message/handlers/delete/mod.rs
@@ -0,0 +1,55 @@
+use axum::{
+ extract::{Json, Path, State},
+ http::StatusCode,
+ response::{self, IntoResponse},
+};
+
+use crate::{
+ app::App,
+ clock::RequestedAt,
+ error::{Internal, NotFound},
+ message::{self, app::DeleteError},
+ token::extract::Identity,
+};
+
+#[cfg(test)]
+mod test;
+
+pub async fn handler(
+ State(app): State<App>,
+ Path(message): Path<message::Id>,
+ RequestedAt(deleted_at): RequestedAt,
+ identity: Identity,
+) -> Result<Response, Error> {
+ app.messages()
+ .delete(&identity.user, &message, &deleted_at)
+ .await?;
+
+ Ok(Response { id: message })
+}
+
+#[derive(Debug, serde::Serialize)]
+pub struct Response {
+ pub id: message::Id,
+}
+
+impl IntoResponse for Response {
+ fn into_response(self) -> response::Response {
+ (StatusCode::ACCEPTED, Json(self)).into_response()
+ }
+}
+
+#[derive(Debug, thiserror::Error)]
+#[error(transparent)]
+pub struct Error(#[from] pub DeleteError);
+
+impl IntoResponse for Error {
+ fn into_response(self) -> response::Response {
+ let Self(error) = self;
+ match error {
+ DeleteError::NotSender(_) => (StatusCode::FORBIDDEN, error.to_string()).into_response(),
+ DeleteError::NotFound(_) | DeleteError::Deleted(_) => NotFound(error).into_response(),
+ DeleteError::Database(_) => Internal::from(error).into_response(),
+ }
+ }
+}
diff --git a/src/message/routes/message/test.rs b/src/message/handlers/delete/test.rs
index 1888be7..15aa2c2 100644
--- a/src/message/routes/message/test.rs
+++ b/src/message/handlers/delete/test.rs
@@ -1,6 +1,5 @@
use axum::extract::{Path, State};
-use super::delete;
use crate::{message::app, test::fixtures};
#[tokio::test]
@@ -14,7 +13,7 @@ pub async fn delete_message() {
// Send the request
- let response = delete::handler(
+ let response = super::handler(
State(app.clone()),
Path(message.id.clone()),
fixtures::now(),
@@ -43,7 +42,7 @@ pub async fn delete_invalid_message_id() {
let deleter = fixtures::identity::create(&app, &fixtures::now()).await;
let message = fixtures::message::fictitious();
- let delete::Error(error) = delete::handler(
+ let super::Error(error) = super::handler(
State(app.clone()),
Path(message.clone()),
fixtures::now(),
@@ -74,7 +73,7 @@ pub async fn delete_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(message.id.clone()),
fixtures::now(),
@@ -105,7 +104,7 @@ pub async fn delete_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(message.id.clone()),
fixtures::now(),
@@ -141,7 +140,7 @@ pub async fn delete_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(message.id.clone()),
fixtures::now(),
@@ -167,7 +166,7 @@ pub async fn delete_not_sender() {
// 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(message.id.clone()),
fixtures::now(),
diff --git a/src/message/handlers/mod.rs b/src/message/handlers/mod.rs
new file mode 100644
index 0000000..7e78475
--- /dev/null
+++ b/src/message/handlers/mod.rs
@@ -0,0 +1,3 @@
+mod delete;
+
+pub use delete::handler as delete;
diff --git a/src/message/mod.rs b/src/message/mod.rs
index fbaa4a3..e1643e6 100644
--- a/src/message/mod.rs
+++ b/src/message/mod.rs
@@ -1,10 +1,10 @@
pub mod app;
mod body;
pub mod event;
+pub mod handlers;
mod history;
mod id;
pub mod repo;
-pub mod routes;
mod snapshot;
pub use self::{body::Body, event::Event, history::History, id::Id, snapshot::Message};
diff --git a/src/message/routes/message/mod.rs b/src/message/routes/message/mod.rs
deleted file mode 100644
index a05d344..0000000
--- a/src/message/routes/message/mod.rs
+++ /dev/null
@@ -1,61 +0,0 @@
-#[cfg(test)]
-mod test;
-
-pub mod delete {
- use axum::{
- extract::{Json, Path, State},
- http::StatusCode,
- response::{self, IntoResponse},
- };
-
- use crate::{
- app::App,
- clock::RequestedAt,
- error::{Internal, NotFound},
- message::{self, app::DeleteError},
- token::extract::Identity,
- };
-
- pub async fn handler(
- State(app): State<App>,
- Path(message): Path<message::Id>,
- RequestedAt(deleted_at): RequestedAt,
- identity: Identity,
- ) -> Result<Response, Error> {
- app.messages()
- .delete(&identity.user, &message, &deleted_at)
- .await?;
-
- Ok(Response { id: message })
- }
-
- #[derive(Debug, serde::Serialize)]
- pub struct Response {
- pub id: message::Id,
- }
-
- impl IntoResponse for Response {
- fn into_response(self) -> response::Response {
- (StatusCode::ACCEPTED, Json(self)).into_response()
- }
- }
-
- #[derive(Debug, thiserror::Error)]
- #[error(transparent)]
- pub struct Error(#[from] pub DeleteError);
-
- impl IntoResponse for Error {
- fn into_response(self) -> response::Response {
- let Self(error) = self;
- match error {
- DeleteError::NotSender(_) => {
- (StatusCode::FORBIDDEN, error.to_string()).into_response()
- }
- DeleteError::NotFound(_) | DeleteError::Deleted(_) => {
- NotFound(error).into_response()
- }
- DeleteError::Database(_) => Internal::from(error).into_response(),
- }
- }
- }
-}
diff --git a/src/message/routes/mod.rs b/src/message/routes/mod.rs
deleted file mode 100644
index e216a50..0000000
--- a/src/message/routes/mod.rs
+++ /dev/null
@@ -1 +0,0 @@
-pub mod message;