Skip to main content

toolkit_contract/ir/
binding.rs

1use serde::{Deserialize, Serialize};
2
3/// HTTP binding projection for a contract.
4///
5/// Deliberately NOT `#[non_exhaustive]` (see [`super::contract::ContractIr`]'s
6/// doc): `#[toolkit::rest_contract]` emits a struct-literal `HttpBindingIr { .. }`
7/// into the SDK crate's generated `<trait>_http_binding()` function.
8#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct HttpBindingIr {
10    /// Base path prefix.
11    pub base_path: String,
12    /// Per-method HTTP bindings.
13    pub methods: Vec<HttpMethodBindingIr>,
14}
15
16impl HttpBindingIr {
17    /// Find the binding for a specific method by name.
18    #[must_use]
19    pub fn find_method(&self, method_name: &str) -> Option<&HttpMethodBindingIr> {
20        self.methods.iter().find(|m| m.method_name == method_name)
21    }
22}
23
24/// HTTP binding for a single method.
25#[derive(Debug, Clone, Serialize, Deserialize)]
26pub struct HttpMethodBindingIr {
27    /// Method name, matching a `MethodIr.name` in the contract.
28    pub method_name: String,
29    /// HTTP method.
30    pub http_method: HttpMethod,
31    /// Path template relative to `base_path`.
32    pub path_template: String,
33    /// How each input field maps to the HTTP request.
34    pub field_bindings: Vec<HttpFieldBinding>,
35    /// Whether the client may retry this call automatically when the
36    /// transport fails or the response is a retryable HTTP status.
37    #[serde(default)]
38    pub retryable: bool,
39    /// Whether this binding represents a server-streaming endpoint
40    /// (Server-Sent Events).
41    #[serde(default)]
42    pub streaming: bool,
43    /// Whether the underlying contract method has a default body (peers
44    /// MAY omit this endpoint). Mirrors `MethodIr.optional`.
45    #[serde(default)]
46    pub optional: bool,
47}
48
49/// HTTP method verb.
50#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
51#[non_exhaustive]
52pub enum HttpMethod {
53    /// HTTP GET.
54    Get,
55    /// HTTP POST.
56    Post,
57    /// HTTP PUT.
58    Put,
59    /// HTTP PATCH.
60    Patch,
61    /// HTTP DELETE.
62    Delete,
63}
64
65/// How an input field is bound to the HTTP request.
66///
67/// `#[non_exhaustive]` at the enum level only: codegen only ever constructs
68/// the variants that exist today (`Path`/`Query`/`Body`), so this doesn't
69/// block macro-generated construction — it only forces downstream `match`
70/// arms to include a wildcard, so adding a future binding kind isn't a
71/// breaking change for crates that match on this type.
72#[derive(Debug, Clone, Serialize, Deserialize)]
73#[non_exhaustive]
74pub enum HttpFieldBinding {
75    /// Field value goes into a URL path parameter.
76    Path {
77        /// Name of the field in `InputShape`.
78        field: String,
79        /// Name of the path parameter in the template.
80        param: String,
81    },
82    /// Field value goes into a query parameter.
83    Query {
84        /// Name of the field in `InputShape`.
85        field: String,
86        /// Name of the query parameter.
87        param: String,
88    },
89    /// Field value goes into the request body.
90    Body,
91}