mas_handlers/admin/v1/policy_data/
get.rs1use aide::{OperationIo, transform::TransformOperation};
6use axum::{Json, response::IntoResponse};
7use hyper::StatusCode;
8use mas_axum_utils::record_error;
9use ulid::Ulid;
10
11use crate::{
12 admin::{
13 call_context::CallContext,
14 model::PolicyData,
15 params::UlidPathParam,
16 response::{ErrorResponse, SingleResponse},
17 },
18 impl_from_error_for_route,
19};
20
21#[derive(Debug, thiserror::Error, OperationIo)]
22#[aide(output_with = "Json<ErrorResponse>")]
23pub enum RouteError {
24 #[error(transparent)]
25 Internal(Box<dyn std::error::Error + Send + Sync + 'static>),
26
27 #[error("Policy data with ID {0} not found")]
28 NotFound(Ulid),
29}
30
31impl_from_error_for_route!(mas_storage::RepositoryError);
32
33impl IntoResponse for RouteError {
34 fn into_response(self) -> axum::response::Response {
35 let error = ErrorResponse::from_error(&self);
36 let sentry_event_id = record_error!(self, Self::Internal(_));
37 let status = match self {
38 Self::Internal(_) => StatusCode::INTERNAL_SERVER_ERROR,
39 Self::NotFound(_) => StatusCode::NOT_FOUND,
40 };
41 (status, sentry_event_id, Json(error)).into_response()
42 }
43}
44
45pub fn doc(operation: TransformOperation) -> TransformOperation {
46 operation
47 .id("getPolicyData")
48 .summary("Get policy data by ID")
49 .tag("policy-data")
50 .response_with::<200, Json<SingleResponse<PolicyData>>, _>(|t| {
51 let [sample, ..] = PolicyData::samples();
52 let response = SingleResponse::new_canonical(sample);
53 t.description("Policy data was found").example(response)
54 })
55 .response_with::<404, RouteError, _>(|t| {
56 let response = ErrorResponse::from_error(&RouteError::NotFound(Ulid::nil()));
57 t.description("Policy data was not found").example(response)
58 })
59}
60
61#[tracing::instrument(name = "handler.admin.v1.policy_data.get", skip_all)]
62pub async fn handler(
63 CallContext { mut repo, .. }: CallContext,
64 id: UlidPathParam,
65) -> Result<Json<SingleResponse<PolicyData>>, RouteError> {
66 let policy_data = repo
67 .policy_data()
68 .get()
69 .await?
70 .ok_or(RouteError::NotFound(*id))?;
71
72 Ok(Json(SingleResponse::new_canonical(policy_data.into())))
73}
74
75#[cfg(test)]
76mod tests {
77 use hyper::{Request, StatusCode};
78 use insta::assert_json_snapshot;
79 use sqlx::PgPool;
80 use ulid::Ulid;
81
82 use crate::test_utils::{RequestBuilderExt, ResponseExt, TestState, setup};
83
84 #[sqlx::test(migrator = "mas_storage_pg::MIGRATOR")]
85 async fn test_get(pool: PgPool) {
86 setup();
87 let mut state = TestState::from_pool(pool).await.unwrap();
88 let token = state.token_with_scope("urn:mas:admin").await;
89
90 let mut rng = state.rng();
91 let mut repo = state.repository().await.unwrap();
92
93 let policy_data = repo
94 .policy_data()
95 .set(
96 &mut rng,
97 &state.clock,
98 serde_json::json!({"hello": "world"}),
99 )
100 .await
101 .unwrap();
102
103 repo.save().await.unwrap();
104
105 let request = Request::get(format!("/api/admin/v1/policy-data/{}", policy_data.id))
106 .bearer(&token)
107 .empty();
108 let response = state.request(request).await;
109 response.assert_status(StatusCode::OK);
110 let body: serde_json::Value = response.json();
111 assert_json_snapshot!(body, @r###"
112 {
113 "data": {
114 "type": "policy-data",
115 "id": "01FSHN9AG0MZAA6S4AF7CTV32E",
116 "attributes": {
117 "created_at": "2022-01-16T14:40:00Z",
118 "data": {
119 "hello": "world"
120 }
121 },
122 "links": {
123 "self": "/api/admin/v1/policy-data/01FSHN9AG0MZAA6S4AF7CTV32E"
124 }
125 },
126 "links": {
127 "self": "/api/admin/v1/policy-data/01FSHN9AG0MZAA6S4AF7CTV32E"
128 }
129 }
130 "###);
131 }
132
133 #[sqlx::test(migrator = "mas_storage_pg::MIGRATOR")]
134 async fn test_get_not_found(pool: PgPool) {
135 setup();
136 let mut state = TestState::from_pool(pool).await.unwrap();
137 let token = state.token_with_scope("urn:mas:admin").await;
138
139 let request = Request::get(format!("/api/admin/v1/policy-data/{}", Ulid::nil()))
140 .bearer(&token)
141 .empty();
142 let response = state.request(request).await;
143 response.assert_status(StatusCode::NOT_FOUND);
144 let body: serde_json::Value = response.json();
145 assert_json_snapshot!(body, @r###"
146 {
147 "errors": [
148 {
149 "title": "Policy data with ID 00000000000000000000000000 not found"
150 }
151 ]
152 }
153 "###);
154 }
155}