cratestack_axum/envelope_layer/policy_request.rs
1//! [`PolicyRequest`]: what an [`super::EnvelopePolicy`] sees of a request.
2
3use http::Method;
4
5/// The op a request addresses, as an [`super::EnvelopePolicy`] sees it.
6///
7/// Deliberately **no headers** and no body (API-review decision,
8/// 2026-09-26): a policy that could read a header could be talked into a
9/// weaker mode by whoever writes that header. What it gets is the op:
10///
11/// - REST: the route template the schema declares (`/widgets/{id}`).
12/// - RPC unary: the op id (`procedure.ping`).
13/// - RPC subscription: the **bare** op id (`model.Widget.subscribe`), with
14/// [`is_subscription`](Self::is_subscription) set, so a policy keyed on
15/// op ids covers subscriptions without knowing their route (decision B1).
16/// - RPC batch: asked once for `batch` itself, and once per frame with the
17/// frame's op id and [`is_batch_frame`](Self::is_batch_frame) set; the
18/// call runs under the strictest answer (decision B1).
19#[derive(Debug, Clone, Copy)]
20pub struct PolicyRequest<'a> {
21 method: &'a Method,
22 op: &'a str,
23 subscription: bool,
24 batch_frame: bool,
25}
26
27impl<'a> PolicyRequest<'a> {
28 /// A request for `op`, as the layer describes it. Public so a policy
29 /// can be unit-tested; the layer builds its own.
30 pub fn new(method: &'a Method, op: &'a str) -> Self {
31 Self {
32 method,
33 op,
34 subscription: false,
35 batch_frame: false,
36 }
37 }
38
39 /// The same request, marked as a subscription.
40 pub fn subscription(self) -> Self {
41 Self {
42 subscription: true,
43 ..self
44 }
45 }
46
47 /// The same request, marked as one frame of a `/rpc/batch` call.
48 pub fn batch_frame(self) -> Self {
49 Self {
50 batch_frame: true,
51 ..self
52 }
53 }
54
55 /// The HTTP method (`POST` for every batch frame).
56 pub fn method(&self) -> &'a Method {
57 self.method
58 }
59
60 /// The op: a REST route template or an RPC op id (see the type docs).
61 pub fn op(&self) -> &'a str {
62 self.op
63 }
64
65 /// An RPC subscription (`/rpc/subscribe/{op_id}`).
66 pub fn is_subscription(&self) -> bool {
67 self.subscription
68 }
69
70 /// One frame of a `/rpc/batch` call.
71 pub fn is_batch_frame(&self) -> bool {
72 self.batch_frame
73 }
74}