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}