api/routes/test/mod.rs
1//! Test-only routes (mounted under `/api/test` in non-production envs).
2//!
3//! These endpoints exist solely for E2E/integration tests (seed, lookup, teardown).
4//! They must never be exposed in production.
5//!
6//! # Endpoints
7//! - POST `/api/test/users` – Create or update a user (idempotent, returns `id`).
8//! - GET `/api/test/users?username=NAME` – Fetch a user by username.
9//! - DELETE `/api/test/users/{id}` – Delete a user by numeric ID.
10
11use axum::{
12 routing::{delete, post},
13 Router,
14};
15use util::state::AppState;
16
17mod common;
18mod get;
19mod post;
20mod delete;
21
22pub use common::{TestUserResponse, UpsertUserRequest};
23pub use get::get_user;
24pub use post::upsert_user;
25pub use delete::delete_user;
26
27/// Registers the test routes on a `Router<AppState>`.
28///
29/// Why mount here (not in `main`):
30/// - Keeps env-conditional test endpoints colocated with handlers and types.
31/// - Avoids changing the router type in `main` (prevents trait-bound surprises).
32/// - Improves discoverability and maintenance of the test API surface.
33///
34/// ## Available routes
35/// - **POST** `/api/test/users`
36/// Create or update a test user. Idempotent — if `username` exists, updates instead.
37/// Always returns the `id` so it can be deleted in teardown.
38/// - **GET** `/api/test/users?username=NAME`
39/// Fetch a test user by their username.
40/// - **DELETE** `/api/test/users/{id}`
41/// Delete a test user by numeric ID.
42pub fn test_routes(app_state: AppState) -> Router<AppState> {
43 Router::new()
44 .route("/users", post(upsert_user).get(get_user))
45 .route("/users/{user_id}", delete(delete_user))
46 .with_state(app_state)
47}