openehr-its 0.0.128

openEHR ITS (Implementation Technology Specifications): canonical JSON + canonical XML serialization of the RM, the generated ITS-REST 1.1.0 API contract, and the OPT 1.4 and AOM2 archetype XML codecs
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
// @generated by openehr-codegen (emit-rest) — DO NOT EDIT.
// SPDX-FileCopyrightText: Cadasto B.V.
// SPDX-FileCopyrightText: openEHR Foundation
// SPDX-License-Identifier: Apache-2.0
//! ITS-REST contract for the `admin` API group: DTOs, per-operation
//! param structs, per-response headers structs, the `server` and
//! `client` halves, and the route table.

#![allow(
    clippy::all,
    clippy::pedantic,
    clippy::nursery,
    dead_code,
    unused_imports,
    unused_variables,
    reason = "mechanically generated contract text: the OAS is emitted in full (every DTO, param struct and route, whether or not this workspace consumes it yet), so style and dead-code lints do not apply — the hand-written runtime and the implementing adapter carry the lint bar"
)]
use serde::{Deserialize, Serialize};

/// Parameters for `admin_ehr_delete` (path/query/header).
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AdminEhrDeleteParams {
    /// `ehr_id` (path)
    pub ehr_id: String,
}

impl AdminEhrDeleteParams {
    /// The parameters of `admin_ehr_delete`, one per field, in field order.
    pub const PARAMS: &'static [crate::rest::routes::Param] = &[crate::rest::routes::Param {
        name: "ehr_id",
        location: crate::rest::routes::ParamLocation::Path,
        required: true,
        explode: false,
        kind: crate::rest::routes::ParamKind::Uuid,
        identifier: Some(crate::rest::routes::IdentifierClass::HierObject),
    }];

    /// Decodes the parameters of `admin_ehr_delete` from a request [`crate::rest::routes::lookup`]
    /// matched to it: its path parameters, its query string without the `?`, and its
    /// headers, exactly as the generated router decodes them.
    ///
    /// # Errors
    /// Returns [`crate::rest::runtime::ApiError::BadRequest`] naming the parameter that is
    /// missing, repeated where a single value is declared, not text, or not a valid value.
    pub fn from_request(
        matched: &crate::rest::routes::RouteMatch,
        _query: Option<&str>,
        _headers: &http::HeaderMap,
    ) -> Result<Self, crate::rest::runtime::ApiError> {
        let path = crate::rest::decode::PathValues::from_route(matched)?;
        Self::from_parts(&path)
    }

    /// Decodes the parameters of `admin_ehr_delete` from the request's decoded parts.
    pub(crate) fn from_parts(
        path: &crate::rest::decode::PathValues,
    ) -> Result<Self, crate::rest::runtime::ApiError> {
        Ok(Self {
            ehr_id: path.value("ehr_id")?,
        })
    }
}

/// Parameters for `admin_ehr_delete_all` (path/query/header).
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AdminEhrDeleteAllParams {
    #[serde(skip_serializing_if = "Option::is_none")]
    /// `ehr_id` (query)
    pub ehr_id: Option<String>,
}

impl AdminEhrDeleteAllParams {
    /// The parameters of `admin_ehr_delete_all`, one per field, in field order.
    pub const PARAMS: &'static [crate::rest::routes::Param] = &[crate::rest::routes::Param {
        name: "ehr_id",
        location: crate::rest::routes::ParamLocation::Query,
        required: false,
        explode: true,
        kind: crate::rest::routes::ParamKind::Uuid,
        identifier: None,
    }];

    /// Decodes the parameters of `admin_ehr_delete_all` from a request [`crate::rest::routes::lookup`]
    /// matched to it: its path parameters, its query string without the `?`, and its
    /// headers, exactly as the generated router decodes them.
    ///
    /// # Errors
    /// Returns [`crate::rest::runtime::ApiError::BadRequest`] naming the parameter that is
    /// missing, repeated where a single value is declared, not text, or not a valid value.
    pub fn from_request(
        _matched: &crate::rest::routes::RouteMatch,
        query: Option<&str>,
        _headers: &http::HeaderMap,
    ) -> Result<Self, crate::rest::runtime::ApiError> {
        let query = crate::rest::decode::QueryPairs::parse(query)?;
        Self::from_parts(&query)
    }

    /// Decodes the parameters of `admin_ehr_delete_all` from the request's decoded parts.
    pub(crate) fn from_parts(
        query: &crate::rest::decode::QueryPairs,
    ) -> Result<Self, crate::rest::runtime::ApiError> {
        Ok(Self {
            ehr_id: query.optional("ehr_id")?,
        })
    }
}

/// The server half of the `admin` API group (ITS-REST): the `AdminApi`
/// trait an implementation provides, one success-answer enum per operation,
/// and `router`, which binds every operation of the route table to its
/// trait method over axum.
#[cfg(feature = "rest-server")]
pub mod server {
    use super::*;

    /// The answers `DELETE /admin/ehr/{ehr_id}` succeeds with: one variant per `2xx`/`3xx` status
    /// the OAS documents (an error is a [`crate::rest::runtime::Refusal`]).
    #[derive(Debug, Clone)]
    pub enum AdminEhrDeleteResponse {
        /// The `202` answer.
        Accepted,
        /// The `204` answer.
        NoContent,
    }

    /// The answers `DELETE /admin/ehr/all{?ehr_id*}` succeeds with: one variant per `2xx`/`3xx` status
    /// the OAS documents (an error is a [`crate::rest::runtime::Refusal`]).
    #[derive(Debug, Clone)]
    pub enum AdminEhrDeleteAllResponse {
        /// The `202` answer.
        Accepted,
        /// The `204` answer.
        NoContent,
    }

    /// Server contract for the `admin` API group (ITS-REST).
    ///
    /// Every method defaults to refusing with `ApiError::NotImplemented` (`501`),
    /// so an implementor overrides only the operations it supports; `router`
    /// serves an implementation over axum. A method refuses with a
    /// [`crate::rest::runtime::Refusal`]: `?` turns an `ApiError` into one,
    /// and `Refusal::with_headers` adds the headers the OAS declares for the
    /// answer (the `ETag` of a `412`, for one).
    #[async_trait::async_trait]
    pub trait AdminApi {
        /// `DELETE /admin/ehr/{ehr_id}`
        async fn admin_ehr_delete(
            &self,
            params: AdminEhrDeleteParams,
        ) -> Result<AdminEhrDeleteResponse, crate::rest::runtime::Refusal> {
            Err(crate::rest::runtime::ApiError::NotImplemented.into())
        }
        /// `DELETE /admin/ehr/all{?ehr_id*}`
        async fn admin_ehr_delete_all(
            &self,
            params: AdminEhrDeleteAllParams,
        ) -> Result<AdminEhrDeleteAllResponse, crate::rest::runtime::Refusal> {
            Err(crate::rest::runtime::ApiError::NotImplemented.into())
        }
    }

    /// The axum router serving every operation of the `admin` group over `api`.
    ///
    /// Each route is bound at its OAS path relative to the API base (an RFC 6570
    /// query expansion dropped, path captures named by segment position). A
    /// handler decodes the request into the operation's params struct and body
    /// — a missing or unparseable parameter answers `400` naming it, a
    /// canonical-JSON body sent as another `Content-Type` answers `415` — and
    /// encodes the trait method's answer, or its `Refusal` as the ITS-REST
    /// `Error` body with the refusal's headers. Mount it under the base path
    /// with `axum::Router::nest`.
    ///
    /// The router carries no fallback, so group routers merge freely (axum
    /// refuses to merge two routers that both carry one); finish the merged
    /// router with `crate::rest::server::with_fallbacks` for the `404` and `405`
    /// answers, or take `crate::rest::server::router`, which does both.
    ///
    /// The typed bodies are canonical JSON only: a server that also serves
    /// canonical XML or a Simplified Format routes those requests itself, and
    /// the `accept` parameter reaches the trait method, which answers
    /// `ApiError::NotAcceptable` for a representation it does not serve.
    pub fn router<S>(api: std::sync::Arc<S>) -> axum::Router
    where
        S: AdminApi + Send + Sync + 'static,
    {
        axum::Router::new()
            .route(
                "/admin/ehr/{p3}",
                axum::routing::on(
                    axum::routing::MethodFilter::DELETE,
                    handle_admin_ehr_delete::<S>,
                ),
            )
            .route(
                "/admin/ehr/all",
                axum::routing::on(
                    axum::routing::MethodFilter::DELETE,
                    handle_admin_ehr_delete_all::<S>,
                ),
            )
            .with_state(api)
    }

    /// Serves `DELETE /admin/ehr/{ehr_id}` through [`AdminApi::admin_ehr_delete`].
    async fn handle_admin_ehr_delete<S>(
        axum::extract::State(api): axum::extract::State<std::sync::Arc<S>>,
        path: Result<
            axum::extract::RawPathParams,
            axum::extract::rejection::RawPathParamsRejection,
        >,
    ) -> axum::response::Response
    where
        S: AdminApi + Send + Sync + 'static,
    {
        let served: Result<axum::response::Response, crate::rest::runtime::Refusal> = async {
            let path = crate::rest::server::path_captures(path, &[("p3", "ehr_id")])?;
            let params = AdminEhrDeleteParams::from_parts(&path)?;
            let reply: crate::rest::server::Reply = match api.admin_ehr_delete(params).await? {
                AdminEhrDeleteResponse::Accepted => {
                    crate::rest::server::Reply::new(http::StatusCode::ACCEPTED)
                }
                AdminEhrDeleteResponse::NoContent => {
                    crate::rest::server::Reply::new(http::StatusCode::NO_CONTENT)
                }
            };
            Ok(reply.finish())
        }
        .await;
        crate::rest::server::respond(served)
    }

    /// Serves `DELETE /admin/ehr/all{?ehr_id*}` through [`AdminApi::admin_ehr_delete_all`].
    async fn handle_admin_ehr_delete_all<S>(
        axum::extract::State(api): axum::extract::State<std::sync::Arc<S>>,
        axum::extract::RawQuery(query): axum::extract::RawQuery,
    ) -> axum::response::Response
    where
        S: AdminApi + Send + Sync + 'static,
    {
        let served: Result<axum::response::Response, crate::rest::runtime::Refusal> = async {
            let query = crate::rest::decode::QueryPairs::parse(query.as_deref())?;
            let params = AdminEhrDeleteAllParams::from_parts(&query)?;
            let reply: crate::rest::server::Reply = match api.admin_ehr_delete_all(params).await? {
                AdminEhrDeleteAllResponse::Accepted => {
                    crate::rest::server::Reply::new(http::StatusCode::ACCEPTED)
                }
                AdminEhrDeleteAllResponse::NoContent => {
                    crate::rest::server::Reply::new(http::StatusCode::NO_CONTENT)
                }
            };
            Ok(reply.finish())
        }
        .await;
        crate::rest::server::respond(served)
    }
}

/// The client half of the `admin` API group (ITS-REST): one method per
/// operation over a [`crate::rest::client::Client`], answering an outcome
/// enum with one variant per status the OAS documents for it.
#[cfg(feature = "rest-client")]
pub mod client {
    use super::*;

    /// The outcome of `DELETE /admin/ehr/{ehr_id}`: one variant per status the OAS documents.
    /// A status outside this set is a [`crate::rest::client::ClientError`].
    #[derive(Debug, Clone)]
    pub enum AdminEhrDeleteOutcome {
        /// The `202` answer.
        Accepted,
        /// The `204` answer.
        NoContent,
        /// The `404` answer.
        NotFound {
            /// The error body as received, decoded as the ITS-REST `Error` when it is one.
            body: crate::rest::client::ErrorBody,
        },
    }

    /// The outcome of `DELETE /admin/ehr/all{?ehr_id*}`: one variant per status the OAS documents.
    /// A status outside this set is a [`crate::rest::client::ClientError`].
    #[derive(Debug, Clone)]
    pub enum AdminEhrDeleteAllOutcome {
        /// The `202` answer.
        Accepted,
        /// The `204` answer.
        NoContent,
        /// The `404` answer.
        NotFound {
            /// The error body as received, decoded as the ITS-REST `Error` when it is one.
            body: crate::rest::client::ErrorBody,
        },
        /// The `405` answer.
        MethodNotAllowed {
            /// The error body as received, decoded as the ITS-REST `Error` when it is one.
            body: crate::rest::client::ErrorBody,
        },
    }

    /// The `admin` API group over one configured CDR.
    #[derive(Debug, Clone)]
    pub struct AdminClient<'c, T> {
        client: &'c crate::rest::client::Client<T>,
        options: crate::rest::client::CallOptions,
    }

    impl<'c, T: crate::rest::client::Transport> AdminClient<'c, T> {
        /// The `admin` API group over `client`.
        #[must_use]
        pub fn new(client: &'c crate::rest::client::Client<T>) -> Self {
            Self {
                client,
                options: crate::rest::client::CallOptions::default(),
            }
        }

        /// This group client applying `options` (a deadline, extra headers) to
        /// every call it makes.
        #[must_use]
        pub fn with_options(mut self, options: crate::rest::client::CallOptions) -> Self {
            self.options = options;
            self
        }

        /// `DELETE /admin/ehr/{ehr_id}`
        ///
        /// # Errors
        /// A status the OAS does not document for this operation, a refused
        /// credential, a service failure, an undecodable body, or a request
        /// that could not be sent — see [`crate::rest::client::ClientError`].
        pub async fn admin_ehr_delete(
            &self,
            params: &AdminEhrDeleteParams,
        ) -> Result<AdminEhrDeleteOutcome, crate::rest::client::ClientError> {
            let mut request = crate::rest::client::Request::new(
                http::Method::DELETE,
                format!(
                    "/admin/ehr/{}",
                    crate::rest::client::path_segment(&params.ehr_id)
                ),
            );
            request.apply_options(&self.options);
            let answer = self.client.execute(request).await?;
            match answer.status() {
                http::StatusCode::ACCEPTED => Ok(AdminEhrDeleteOutcome::Accepted),
                http::StatusCode::NO_CONTENT => Ok(AdminEhrDeleteOutcome::NoContent),
                http::StatusCode::NOT_FOUND => Ok(AdminEhrDeleteOutcome::NotFound {
                    body: answer.error_body(),
                }),
                _ => Err(answer.into_undocumented()),
            }
        }

        /// `DELETE /admin/ehr/all{?ehr_id*}`
        ///
        /// # Errors
        /// A status the OAS does not document for this operation, a refused
        /// credential, a service failure, an undecodable body, or a request
        /// that could not be sent — see [`crate::rest::client::ClientError`].
        pub async fn admin_ehr_delete_all(
            &self,
            params: &AdminEhrDeleteAllParams,
        ) -> Result<AdminEhrDeleteAllOutcome, crate::rest::client::ClientError> {
            let mut request = crate::rest::client::Request::new(
                http::Method::DELETE,
                String::from("/admin/ehr/all"),
            );
            if let Some(value) = params.ehr_id.as_ref() {
                request.query("ehr_id", value);
            }
            request.apply_options(&self.options);
            let answer = self.client.execute(request).await?;
            match answer.status() {
                http::StatusCode::ACCEPTED => Ok(AdminEhrDeleteAllOutcome::Accepted),
                http::StatusCode::NO_CONTENT => Ok(AdminEhrDeleteAllOutcome::NoContent),
                http::StatusCode::NOT_FOUND => Ok(AdminEhrDeleteAllOutcome::NotFound {
                    body: answer.error_body(),
                }),
                http::StatusCode::METHOD_NOT_ALLOWED => {
                    Ok(AdminEhrDeleteAllOutcome::MethodNotAllowed {
                        body: answer.error_body(),
                    })
                }
                _ => Err(answer.into_undocumented()),
            }
        }
    }
}
/// The operations of this group as `(method, path, operation_id)`, in OAS
/// document order: `server::router` binds each to its trait method, and
/// `crate::rest::routes::lookup` matches a request path against them.
pub const ROUTES: &[(&str, &str, &str)] = &[
    ("DELETE", "/admin/ehr/{ehr_id}", "admin_ehr_delete"),
    ("DELETE", "/admin/ehr/all{?ehr_id*}", "admin_ehr_delete_all"),
];

/// The declared parameters of each operation, index-aligned with [`ROUTES`]:
/// the operation's `*Params::PARAMS`, empty when it declares none.
pub const ROUTE_PARAMS: &[&[crate::rest::routes::Param]] = &[
    AdminEhrDeleteParams::PARAMS,
    AdminEhrDeleteAllParams::PARAMS,
];

const _: () = assert!(
    ROUTE_PARAMS.len() == ROUTES.len(),
    "ROUTE_PARAMS carries one row per ROUTES entry"
);

/// The request-body media types of each operation, index-aligned with
/// [`ROUTES`]: the `requestBody.content` keys of the OAS, in document order,
/// empty when the operation takes no body.
pub const ROUTE_REQUEST_MEDIA: &[&[&str]] = &[&[], &[]];

const _: () = assert!(
    ROUTE_REQUEST_MEDIA.len() == ROUTES.len(),
    "ROUTE_REQUEST_MEDIA carries one row per ROUTES entry"
);