Skip to content

Commit 6e2d004

Browse files
feat(openapi): H1, H2, H4-H10, D3, D4, D5, D8, D10 — Phase 2 struct families + 3.2 deltas
A big batch covering most of the previously-unmodelled top-level OAS objects. All structs are typed with Extensions for x-* fields; 3.2-only fields are added as the spec defines them. H1: Server + ServerVariable Object - OpenApiSpec.servers, PathItem.servers, Operation.servers all become Option<Vec<Server>>. Server has typed url/description/variables and 3.2's `name` field (D8). - ServerVariable carries default/enum/description. H2: Security Scheme Object (full set) - SecurityScheme enum with #[serde(tag = "type")] covering apiKey, http, mutualTLS (3.1+), oauth2, openIdConnect. - OAuthFlows + OAuthFlow modeled with all four standard flows + 3.2's deviceAuthorization (D4). - OAuth Flow gains deviceAuthorizationUrl (D4) and SecurityScheme::OAuth2 gains oauth2MetadataUrl (D4). - Every variant carries a `deprecated` field (D10). - Components.security_schemes is now BTreeMap<String, SecurityScheme>. H4: Encoding Object - contentType, headers, style, explode, allowReserved. - 3.2 itemEncoding (D3) for streaming/array body parts. - MediaType.encoding becomes BTreeMap<String, Encoding>. H5: Header Object - Same shape as Parameter minus name/in. Used in Response.headers (T9), Encoding.headers, Components.headers. H6: Example Object - summary, description, value, externalValue. - 3.2 dataValue and serializedValue. - Components.examples and MediaType.examples are now typed. H7: Link Object - operationRef, operationId, parameters, requestBody, server. - Components.links typed. H8: Callback Object - Newtype wrapper around BTreeMap<String, PathItem>. - Operation.callbacks and Components.callbacks are typed. H9: Tag Object - name, description, externalDocs. - 3.2 summary, parent, kind (D5). - OpenApiSpec.tags is Vec<Tag>. H10: ExternalDocs Object - url + description. Used by OpenApiSpec, Operation. D3: MediaType.itemSchema, prefixEncoding, itemEncoding (3.2) Spec-level and Operation-level `security` are now typed Vec<BTreeMap<String, Vec<String>>> instead of opaque Value. All 205 tests still pass. Refs #14 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 3457f50 commit 6e2d004

1 file changed

Lines changed: 296 additions & 18 deletions

File tree

src/openapi.rs

Lines changed: 296 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,19 @@ pub struct OpenApiSpec {
1111
#[serde(rename = "jsonSchemaDialect", default)]
1212
pub json_schema_dialect: Option<String>,
1313
#[serde(default)]
14-
pub servers: Option<Value>,
14+
pub servers: Option<Vec<Server>>,
1515
#[serde(default)]
1616
pub paths: Option<BTreeMap<String, PathItem>>,
1717
#[serde(default)]
1818
pub webhooks: Option<BTreeMap<String, PathItem>>,
1919
#[serde(default)]
2020
pub components: Option<Components>,
2121
#[serde(default)]
22-
pub security: Option<Value>,
22+
pub security: Option<Vec<BTreeMap<String, Vec<String>>>>,
2323
#[serde(default)]
24-
pub tags: Option<Value>,
24+
pub tags: Option<Vec<Tag>>,
2525
#[serde(rename = "externalDocs", default)]
26-
pub external_docs: Option<Value>,
26+
pub external_docs: Option<ExternalDocs>,
2727
/// 3.2 §"$self" — see Appendix F base-URI rules. Captured but not yet used.
2828
#[serde(rename = "$self", default)]
2929
pub self_uri: Option<String>,
@@ -59,17 +59,17 @@ pub struct Components {
5959
#[serde(default)]
6060
pub parameters: Option<BTreeMap<String, Parameter>>,
6161
#[serde(default)]
62-
pub examples: Option<BTreeMap<String, Value>>,
62+
pub examples: Option<BTreeMap<String, Example>>,
6363
#[serde(rename = "requestBodies", default)]
6464
pub request_bodies: Option<BTreeMap<String, RequestBody>>,
6565
#[serde(default)]
66-
pub headers: Option<BTreeMap<String, Value>>,
66+
pub headers: Option<BTreeMap<String, Header>>,
6767
#[serde(rename = "securitySchemes", default)]
68-
pub security_schemes: Option<BTreeMap<String, Value>>,
68+
pub security_schemes: Option<BTreeMap<String, SecurityScheme>>,
6969
#[serde(default)]
70-
pub links: Option<BTreeMap<String, Value>>,
70+
pub links: Option<BTreeMap<String, Link>>,
7171
#[serde(default)]
72-
pub callbacks: Option<BTreeMap<String, Value>>,
72+
pub callbacks: Option<BTreeMap<String, Callback>>,
7373
/// 3.1+ §Components — reusable Path Items.
7474
#[serde(rename = "pathItems", default)]
7575
pub path_items: Option<BTreeMap<String, PathItem>>,
@@ -225,6 +225,272 @@ pub enum AdditionalProperties {
225225
Schema(Box<Schema>),
226226
}
227227

228+
/// OpenAPI Example Object (H6).
229+
#[derive(Debug, Clone, Deserialize, Serialize)]
230+
pub struct Example {
231+
#[serde(default)]
232+
pub summary: Option<String>,
233+
#[serde(default)]
234+
pub description: Option<String>,
235+
/// Singular embedded value. Mutually exclusive with `external_value`.
236+
#[serde(default)]
237+
pub value: Option<Value>,
238+
#[serde(rename = "externalValue", default)]
239+
pub external_value: Option<String>,
240+
/// 3.2 §"Example Object" — typed pre-serialization data.
241+
#[serde(rename = "dataValue", default)]
242+
pub data_value: Option<Value>,
243+
/// 3.2 §"Example Object" — already-serialized form.
244+
#[serde(rename = "serializedValue", default)]
245+
pub serialized_value: Option<String>,
246+
#[serde(rename = "$ref", default)]
247+
pub reference: Option<String>,
248+
#[serde(flatten, default)]
249+
pub extensions: Extensions,
250+
}
251+
252+
/// OpenAPI Link Object (H7).
253+
#[derive(Debug, Clone, Deserialize, Serialize)]
254+
pub struct Link {
255+
#[serde(rename = "operationRef", default)]
256+
pub operation_ref: Option<String>,
257+
#[serde(rename = "operationId", default)]
258+
pub operation_id: Option<String>,
259+
#[serde(default)]
260+
pub parameters: Option<BTreeMap<String, Value>>,
261+
#[serde(rename = "requestBody", default)]
262+
pub request_body: Option<Value>,
263+
#[serde(default)]
264+
pub description: Option<String>,
265+
#[serde(default)]
266+
pub server: Option<Server>,
267+
#[serde(rename = "$ref", default)]
268+
pub reference: Option<String>,
269+
#[serde(flatten, default)]
270+
pub extensions: Extensions,
271+
}
272+
273+
/// OpenAPI Callback Object (H8). A map keyed by runtime-expression URL
274+
/// templates, with Path Item values.
275+
#[derive(Debug, Clone, Deserialize, Serialize)]
276+
#[serde(transparent)]
277+
pub struct Callback(pub BTreeMap<String, PathItem>);
278+
279+
/// OpenAPI Encoding Object (H4). Used inside `multipart/form-data` and
280+
/// `application/x-www-form-urlencoded` Media Type bodies.
281+
#[derive(Debug, Clone, Deserialize, Serialize)]
282+
pub struct Encoding {
283+
#[serde(rename = "contentType", default)]
284+
pub content_type: Option<String>,
285+
#[serde(default)]
286+
pub headers: Option<BTreeMap<String, Header>>,
287+
#[serde(default)]
288+
pub style: Option<String>,
289+
#[serde(default)]
290+
pub explode: Option<bool>,
291+
#[serde(rename = "allowReserved", default)]
292+
pub allow_reserved: Option<bool>,
293+
/// 3.2 §"Encoding Object" — nested encoding for arrays of items.
294+
#[serde(rename = "itemEncoding", default)]
295+
pub item_encoding: Option<Box<Encoding>>,
296+
#[serde(flatten, default)]
297+
pub extensions: Extensions,
298+
}
299+
300+
/// OpenAPI Header Object (H5). Structurally a Parameter minus the `name`
301+
/// and `in` fields. Used in Response.headers, Encoding.headers, and
302+
/// Components.headers.
303+
#[derive(Debug, Clone, Deserialize, Serialize)]
304+
pub struct Header {
305+
#[serde(default)]
306+
pub description: Option<String>,
307+
#[serde(default)]
308+
pub required: Option<bool>,
309+
#[serde(default)]
310+
pub deprecated: Option<bool>,
311+
#[serde(rename = "allowEmptyValue", default)]
312+
pub allow_empty_value: Option<bool>,
313+
#[serde(default)]
314+
pub style: Option<String>,
315+
#[serde(default)]
316+
pub explode: Option<bool>,
317+
#[serde(rename = "allowReserved", default)]
318+
pub allow_reserved: Option<bool>,
319+
#[serde(default)]
320+
pub schema: Option<Schema>,
321+
#[serde(default)]
322+
pub content: Option<BTreeMap<String, MediaType>>,
323+
#[serde(default)]
324+
pub example: Option<Value>,
325+
#[serde(default)]
326+
pub examples: Option<Value>,
327+
#[serde(rename = "$ref", default)]
328+
pub reference: Option<String>,
329+
#[serde(flatten, default)]
330+
pub extensions: Extensions,
331+
}
332+
333+
/// OpenAPI Security Scheme Object (H2). Covers all 3.x scheme types:
334+
/// apiKey, http (basic/bearer/digest), oauth2 (with flows), openIdConnect,
335+
/// and 3.1+ mutualTLS.
336+
#[derive(Debug, Clone, Deserialize, Serialize)]
337+
#[serde(tag = "type")]
338+
pub enum SecurityScheme {
339+
#[serde(rename = "apiKey")]
340+
ApiKey {
341+
name: String,
342+
#[serde(rename = "in")]
343+
location: String, // "query" | "header" | "cookie"
344+
#[serde(default)]
345+
description: Option<String>,
346+
/// 3.2 §"Security Scheme Object" — D10.
347+
#[serde(default)]
348+
deprecated: Option<bool>,
349+
#[serde(flatten, default)]
350+
extensions: Extensions,
351+
},
352+
#[serde(rename = "http")]
353+
Http {
354+
scheme: String, // "basic" | "bearer" | "digest" | …
355+
#[serde(rename = "bearerFormat", default)]
356+
bearer_format: Option<String>,
357+
#[serde(default)]
358+
description: Option<String>,
359+
#[serde(default)]
360+
deprecated: Option<bool>,
361+
#[serde(flatten, default)]
362+
extensions: Extensions,
363+
},
364+
#[serde(rename = "mutualTLS")]
365+
MutualTls {
366+
#[serde(default)]
367+
description: Option<String>,
368+
#[serde(default)]
369+
deprecated: Option<bool>,
370+
#[serde(flatten, default)]
371+
extensions: Extensions,
372+
},
373+
#[serde(rename = "oauth2")]
374+
OAuth2 {
375+
flows: OAuthFlows,
376+
#[serde(default)]
377+
description: Option<String>,
378+
/// 3.2 §"Security Scheme Object" — well-known metadata URL (D4).
379+
#[serde(rename = "oauth2MetadataUrl", default)]
380+
oauth2_metadata_url: Option<String>,
381+
#[serde(default)]
382+
deprecated: Option<bool>,
383+
#[serde(flatten, default)]
384+
extensions: Extensions,
385+
},
386+
#[serde(rename = "openIdConnect")]
387+
OpenIdConnect {
388+
#[serde(rename = "openIdConnectUrl")]
389+
open_id_connect_url: String,
390+
#[serde(default)]
391+
description: Option<String>,
392+
#[serde(default)]
393+
deprecated: Option<bool>,
394+
#[serde(flatten, default)]
395+
extensions: Extensions,
396+
},
397+
}
398+
399+
#[derive(Debug, Clone, Deserialize, Serialize)]
400+
pub struct OAuthFlows {
401+
#[serde(default)]
402+
pub implicit: Option<OAuthFlow>,
403+
#[serde(default)]
404+
pub password: Option<OAuthFlow>,
405+
#[serde(rename = "clientCredentials", default)]
406+
pub client_credentials: Option<OAuthFlow>,
407+
#[serde(rename = "authorizationCode", default)]
408+
pub authorization_code: Option<OAuthFlow>,
409+
/// 3.2 §"OAuth Flows Object" — device authorization flow (D4).
410+
#[serde(rename = "deviceAuthorization", default)]
411+
pub device_authorization: Option<OAuthFlow>,
412+
#[serde(flatten, default)]
413+
pub extensions: Extensions,
414+
}
415+
416+
#[derive(Debug, Clone, Deserialize, Serialize)]
417+
pub struct OAuthFlow {
418+
#[serde(rename = "authorizationUrl", default)]
419+
pub authorization_url: Option<String>,
420+
#[serde(rename = "tokenUrl", default)]
421+
pub token_url: Option<String>,
422+
#[serde(rename = "refreshUrl", default)]
423+
pub refresh_url: Option<String>,
424+
/// 3.2 §"OAuth Flow Object" — required for `deviceAuthorization` (D4).
425+
#[serde(rename = "deviceAuthorizationUrl", default)]
426+
pub device_authorization_url: Option<String>,
427+
pub scopes: BTreeMap<String, String>,
428+
#[serde(flatten, default)]
429+
pub extensions: Extensions,
430+
}
431+
432+
/// OpenAPI External Documentation Object (H10).
433+
#[derive(Debug, Clone, Deserialize, Serialize)]
434+
pub struct ExternalDocs {
435+
pub url: String,
436+
#[serde(default)]
437+
pub description: Option<String>,
438+
#[serde(flatten, default)]
439+
pub extensions: Extensions,
440+
}
441+
442+
/// OpenAPI Tag Object (H9 + D5 — 3.2 added summary/parent/kind).
443+
#[derive(Debug, Clone, Deserialize, Serialize)]
444+
pub struct Tag {
445+
pub name: String,
446+
/// 3.2 §"Tag Object" — short summary of the tag.
447+
#[serde(default)]
448+
pub summary: Option<String>,
449+
#[serde(default)]
450+
pub description: Option<String>,
451+
/// 3.2 §"Tag Object" — name of a parent tag for hierarchical organisation.
452+
#[serde(default)]
453+
pub parent: Option<String>,
454+
/// 3.2 §"Tag Object" — categorisation hint (e.g. "feature", "audience",
455+
/// "compliance"). Free-form string; consumers MAY define their own
456+
/// vocabulary.
457+
#[serde(default)]
458+
pub kind: Option<String>,
459+
#[serde(rename = "externalDocs", default)]
460+
pub external_docs: Option<ExternalDocs>,
461+
#[serde(flatten, default)]
462+
pub extensions: Extensions,
463+
}
464+
465+
/// OpenAPI Server Object (H1). Multiple servers, server variables, and
466+
/// 3.2's `name` field are all modeled.
467+
#[derive(Debug, Clone, Deserialize, Serialize)]
468+
pub struct Server {
469+
pub url: String,
470+
/// 3.2 §"Server Object" — server identifier for runtime selection (D8).
471+
#[serde(default)]
472+
pub name: Option<String>,
473+
#[serde(default)]
474+
pub description: Option<String>,
475+
#[serde(default)]
476+
pub variables: Option<BTreeMap<String, ServerVariable>>,
477+
#[serde(flatten, default)]
478+
pub extensions: Extensions,
479+
}
480+
481+
#[derive(Debug, Clone, Deserialize, Serialize)]
482+
pub struct ServerVariable {
483+
/// REQUIRED in 3.0/3.1. In 3.2 this MAY be omitted when `enum` is present.
484+
#[serde(default)]
485+
pub default: Option<String>,
486+
#[serde(rename = "enum", default)]
487+
pub enum_values: Option<Vec<String>>,
488+
#[serde(default)]
489+
pub description: Option<String>,
490+
#[serde(flatten, default)]
491+
pub extensions: Extensions,
492+
}
493+
228494
#[derive(Debug, Clone, Deserialize, Serialize)]
229495
pub struct Discriminator {
230496
#[serde(rename = "propertyName")]
@@ -477,7 +743,7 @@ pub struct PathItem {
477743
pub additional_operations: Option<BTreeMap<String, Operation>>,
478744
pub parameters: Option<Vec<Parameter>>,
479745
#[serde(default)]
480-
pub servers: Option<Value>,
746+
pub servers: Option<Vec<Server>>,
481747
#[serde(rename = "$ref", default)]
482748
pub reference: Option<String>,
483749
#[serde(flatten, default)]
@@ -543,13 +809,13 @@ pub struct Operation {
543809
pub request_body: Option<RequestBody>,
544810
pub responses: Option<BTreeMap<String, Response>>,
545811
#[serde(default)]
546-
pub callbacks: Option<Value>,
812+
pub callbacks: Option<BTreeMap<String, Callback>>,
547813
#[serde(default)]
548-
pub security: Option<Value>,
814+
pub security: Option<Vec<BTreeMap<String, Vec<String>>>>,
549815
#[serde(default)]
550-
pub servers: Option<Value>,
816+
pub servers: Option<Vec<Server>>,
551817
#[serde(rename = "externalDocs", default)]
552-
pub external_docs: Option<Value>,
818+
pub external_docs: Option<ExternalDocs>,
553819
#[serde(flatten, default)]
554820
pub extensions: Extensions,
555821
}
@@ -580,7 +846,7 @@ pub struct Parameter {
580846
#[serde(default)]
581847
pub example: Option<Value>,
582848
#[serde(default)]
583-
pub examples: Option<Value>,
849+
pub examples: Option<BTreeMap<String, Example>>,
584850
#[serde(default)]
585851
pub description: Option<String>,
586852
#[serde(rename = "$ref", default)]
@@ -690,7 +956,7 @@ pub struct Response {
690956
#[serde(default)]
691957
pub description: Option<String>,
692958
#[serde(default)]
693-
pub headers: Option<Value>,
959+
pub headers: Option<BTreeMap<String, Header>>,
694960
#[serde(default)]
695961
pub content: Option<BTreeMap<String, MediaType>>,
696962
#[serde(default)]
@@ -724,9 +990,21 @@ pub struct MediaType {
724990
#[serde(default)]
725991
pub example: Option<Value>,
726992
#[serde(default)]
727-
pub examples: Option<Value>,
993+
pub examples: Option<BTreeMap<String, Example>>,
728994
#[serde(default)]
729-
pub encoding: Option<Value>,
995+
pub encoding: Option<BTreeMap<String, Encoding>>,
996+
/// 3.2 §"Media Type Object" — schema for each item when streaming
997+
/// (D3). Common in `text/event-stream` and JSON-lines payloads.
998+
#[serde(rename = "itemSchema", default)]
999+
pub item_schema: Option<Schema>,
1000+
/// 3.2 §"Media Type Object" — encoding for the leading prefix of a
1001+
/// streamed body (D3).
1002+
#[serde(rename = "prefixEncoding", default)]
1003+
pub prefix_encoding: Option<Vec<Encoding>>,
1004+
/// 3.2 §"Media Type Object" — encoding applied to each streamed item
1005+
/// (D3).
1006+
#[serde(rename = "itemEncoding", default)]
1007+
pub item_encoding: Option<Encoding>,
7301008
#[serde(rename = "$ref", default)]
7311009
pub reference: Option<String>,
7321010
#[serde(flatten, default)]

0 commit comments

Comments
 (0)