steid

@jamesgill /

40ab5c7feat: /api/me and a shared identity read model1mo
1//! JSON API.
2//!
3//! Not a milestone of its own — every use case gets a second surface here where that
4//! makes sense. Having two consumers is what keeps the application layer honest about
5//! staying transport-neutral.
6
7use serde::Serialize;
8use topcoat::{
9 Result,
10 context::Cx,
11 router::{content::Json, error::unauthorized, route},
12};
13
14use super::context::identity;
15
16/// The authenticated user, as JSON.
17///
18/// A DTO rather than the domain type: serialisation is a wire concern, and deriving
19/// `Serialize` on domain entities lets a field leak into a response the moment someone
20/// adds one.
21#[derive(Debug, Serialize)]
22struct Me {
23 id: String,
24 email: String,
25 handle: String,
26}
27
28/// Who the caller is.
29///
30/// 401 when anonymous, matching the convention that `/me` describes an authenticated
31/// caller and has nothing to say without one.
32#[route(GET "/api/me")]
33async fn me(cx: &Cx) -> Result<Json<Me>> {
34 let identity = identity(cx).await?.ok_or_else(unauthorized)?;
35
36 Ok(Json(Me {
37 id: identity.user_id.to_string(),
38 email: identity.email.to_string(),
39 handle: identity.handle.to_string(),
40 }))
41}