Skip to content

Commit 6ae0c4e

Browse files
authored
feat: Upgrade to schemars 0.9.0 (#223)
1 parent 5874867 commit 6ae0c4e

File tree

11 files changed

+142
-135
lines changed

11 files changed

+142
-135
lines changed

crates/aide/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "aide"
3-
version = "0.14.2"
3+
version = "0.15.0"
44
authors = ["tamasfe"]
55
edition = "2021"
66
keywords = ["generate", "api", "openapi", "documentation", "specification"]
@@ -11,7 +11,7 @@ readme = "README.md"
1111

1212
[dependencies]
1313
indexmap = { version = "2.1", features = ["serde"] }
14-
schemars = { version = "0.8.16", features = ["impl_json_schema", "indexmap2"] }
14+
schemars = { version = "0.9.0", features = ["indexmap2"] }
1515
serde = { version = "1.0.144", features = ["derive"] }
1616
serde_json = "1"
1717
thiserror = "2.0"

crates/aide/src/axum/inputs.rs

Lines changed: 32 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,7 @@ use axum::{
1212
};
1313

1414
use indexmap::IndexMap;
15-
use schemars::{
16-
schema::{ArrayValidation, InstanceType, Schema, SingleOrVec},
17-
JsonSchema,
18-
};
15+
use schemars::{json_schema, JsonSchema, Schema};
1916
use serde_json::json;
2017

2118
use crate::{
@@ -75,22 +72,22 @@ fn operation_input_json<T: JsonSchema>(
7572
ctx: &mut crate::generate::GenContext,
7673
operation: &mut Operation,
7774
) {
78-
let schema = ctx.schema.subschema_for::<T>().into_object();
79-
let resolved_schema = ctx.resolve_schema(&schema);
75+
let json_schema = ctx.schema.subschema_for::<T>();
76+
let resolved_schema = ctx.resolve_schema(&json_schema);
8077

8178
set_body(
8279
ctx,
8380
operation,
8481
RequestBody {
8582
description: resolved_schema
86-
.metadata
87-
.as_ref()
88-
.and_then(|m| m.description.clone()),
83+
.get("description")
84+
.and_then(|d| d.as_str())
85+
.map(String::from),
8986
content: IndexMap::from_iter([(
9087
"application/json".into(),
9188
MediaType {
9289
schema: Some(SchemaObject {
93-
json_schema: schema.into(),
90+
json_schema,
9491
example: None,
9592
external_docs: None,
9693
}),
@@ -129,17 +126,17 @@ where
129126
T: JsonSchema,
130127
{
131128
fn operation_input(ctx: &mut crate::generate::GenContext, operation: &mut Operation) {
132-
let schema = ctx.schema.subschema_for::<T>().into_object();
129+
let schema = ctx.schema.subschema_for::<T>();
133130
let resolved_schema = ctx.resolve_schema(&schema);
134131

135132
set_body(
136133
ctx,
137134
operation,
138135
RequestBody {
139136
description: resolved_schema
140-
.metadata
141-
.as_ref()
142-
.and_then(|m| m.description.clone()),
137+
.get("description")
138+
.and_then(|d| d.as_str())
139+
.map(String::from),
143140
content: IndexMap::from_iter([(
144141
"application/x-www-form-urlencoded".into(),
145142
MediaType {
@@ -163,7 +160,7 @@ where
163160
T: JsonSchema,
164161
{
165162
fn operation_input(ctx: &mut crate::generate::GenContext, operation: &mut Operation) {
166-
let schema = ctx.schema.subschema_for::<T>().into_object();
163+
let schema = ctx.schema.subschema_for::<T>();
167164
let params = parameters_from_schema(ctx, schema, ParamLocation::Path);
168165
add_parameters(ctx, operation, params);
169166
}
@@ -175,7 +172,7 @@ where
175172
T: JsonSchema,
176173
{
177174
fn operation_input(ctx: &mut crate::generate::GenContext, operation: &mut Operation) {
178-
let schema = ctx.schema.subschema_for::<T>().into_object();
175+
let schema = ctx.schema.subschema_for::<T>();
179176
let params = parameters_from_schema(ctx, schema, ParamLocation::Query);
180177
add_parameters(ctx, operation, params);
181178
}
@@ -207,13 +204,10 @@ impl OperationInput for axum::extract::ws::WebSocketUpgrade {
207204
deprecated: None,
208205
format: crate::openapi::ParameterSchemaOrContent::Schema(
209206
SchemaObject {
210-
json_schema: Schema::Object(schemars::schema::SchemaObject {
211-
instance_type: Some(SingleOrVec::Single(Box::new(
212-
InstanceType::String,
213-
))),
214-
enum_values: Some(vec![json!("upgrade")]),
215-
const_value: Some(json!("upgrade")),
216-
..Default::default()
207+
json_schema: json_schema!({
208+
"type": "string",
209+
"enum": ["upgrade"],
210+
"const": "upgrade",
217211
}),
218212
external_docs: None,
219213
example: Some(json!("upgrade")),
@@ -233,13 +227,10 @@ impl OperationInput for axum::extract::ws::WebSocketUpgrade {
233227
deprecated: None,
234228
format: crate::openapi::ParameterSchemaOrContent::Schema(
235229
SchemaObject {
236-
json_schema: Schema::Object(schemars::schema::SchemaObject {
237-
instance_type: Some(SingleOrVec::Single(Box::new(
238-
InstanceType::String,
239-
))),
240-
enum_values: Some(vec![json!("websocket")]),
241-
const_value: Some(json!("websocket")),
242-
..Default::default()
230+
json_schema: json_schema!({
231+
"type": "string",
232+
"enum": ["websocket"],
233+
"const": "websocket",
243234
}),
244235
external_docs: None,
245236
example: Some(json!("websocket")),
@@ -259,11 +250,8 @@ impl OperationInput for axum::extract::ws::WebSocketUpgrade {
259250
deprecated: None,
260251
format: crate::openapi::ParameterSchemaOrContent::Schema(
261252
SchemaObject {
262-
json_schema: Schema::Object(schemars::schema::SchemaObject {
263-
instance_type: Some(SingleOrVec::Single(Box::new(
264-
InstanceType::String,
265-
))),
266-
..Default::default()
253+
json_schema: json_schema!({
254+
"type": "string",
267255
}),
268256
external_docs: None,
269257
example: None,
@@ -283,11 +271,8 @@ impl OperationInput for axum::extract::ws::WebSocketUpgrade {
283271
deprecated: None,
284272
format: crate::openapi::ParameterSchemaOrContent::Schema(
285273
SchemaObject {
286-
json_schema: Schema::Object(schemars::schema::SchemaObject {
287-
instance_type: Some(SingleOrVec::Single(Box::new(
288-
InstanceType::String,
289-
))),
290-
..Default::default()
274+
json_schema: json_schema!({
275+
"type": "string",
291276
}),
292277
external_docs: None,
293278
example: None,
@@ -321,11 +306,8 @@ impl OperationInput for axum::extract::Multipart {
321306
"multipart/form-data".into(),
322307
MediaType {
323308
schema: Some(SchemaObject {
324-
json_schema: Schema::Object(schemars::schema::SchemaObject {
325-
instance_type: Some(SingleOrVec::Single(Box::new(
326-
InstanceType::Array,
327-
))),
328-
..Default::default()
309+
json_schema: json_schema!({
310+
"type": "array",
329311
}),
330312
external_docs: None,
331313
example: None,
@@ -384,17 +366,17 @@ mod extra {
384366
T: JsonSchema,
385367
{
386368
fn operation_input(ctx: &mut crate::generate::GenContext, operation: &mut Operation) {
387-
let schema = ctx.schema.subschema_for::<T>().into_object();
369+
let schema = ctx.schema.subschema_for::<T>();
388370
let resolved_schema = ctx.resolve_schema(&schema);
389371

390372
set_body(
391373
ctx,
392374
operation,
393375
RequestBody {
394376
description: resolved_schema
395-
.metadata
396-
.as_ref()
397-
.and_then(|m| m.description.clone()),
377+
.get("description")
378+
.and_then(|d| d.as_str())
379+
.map(String::from),
398380
content: IndexMap::from_iter([(
399381
"application/x-www-form-urlencoded".into(),
400382
MediaType {
@@ -418,7 +400,7 @@ mod extra {
418400
T: JsonSchema,
419401
{
420402
fn operation_input(ctx: &mut crate::generate::GenContext, operation: &mut Operation) {
421-
let schema = ctx.schema.subschema_for::<T>().into_object();
403+
let schema = ctx.schema.subschema_for::<T>();
422404
let params = parameters_from_schema(ctx, schema, ParamLocation::Query);
423405
add_parameters(ctx, operation, params);
424406
}

crates/aide/src/axum/mod.rs

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -439,30 +439,29 @@ where
439439

440440
let _ = transform(TransformOpenApi::new(api));
441441

442-
let needs_reset =
443-
in_context(|ctx| {
444-
if !ctx.extract_schemas {
445-
return false;
446-
}
442+
let needs_reset = in_context(|ctx| {
443+
if !ctx.extract_schemas {
444+
return false;
445+
}
447446

448-
let components = api.components.get_or_insert_with(Default::default);
449-
components
450-
.schemas
451-
.extend(ctx.schema.take_definitions().into_iter().map(
452-
|(name, json_schema)| {
453-
(
454-
name,
455-
SchemaObject {
456-
json_schema,
457-
example: None,
458-
external_docs: None,
459-
},
460-
)
461-
},
462-
));
463-
464-
true
465-
});
447+
let components = api.components.get_or_insert_with(Default::default);
448+
components
449+
.schemas
450+
.extend(ctx.schema.take_definitions(true).into_iter().map(
451+
|(name, json_schema)| {
452+
(
453+
name,
454+
SchemaObject {
455+
json_schema: json_schema.try_into().expect("Invalid schema"),
456+
example: None,
457+
external_docs: None,
458+
},
459+
)
460+
},
461+
));
462+
463+
true
464+
});
466465
if needs_reset {
467466
generate::reset_context();
468467
}

crates/aide/src/axum/outputs.rs

Lines changed: 18 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use axum::response::{Html, NoContent, Redirect};
1010
#[cfg(any(feature = "axum-json", feature = "axum-form"))]
1111
use http::StatusCode;
1212
use indexmap::IndexMap;
13-
use schemars::schema::{InstanceType, SingleOrVec};
13+
use schemars::json_schema;
1414
#[cfg(any(feature = "axum-form", feature = "axum-json"))]
1515
use schemars::JsonSchema;
1616

@@ -39,21 +39,20 @@ where
3939
type Inner = T;
4040

4141
fn operation_response(ctx: &mut GenContext, _operation: &mut Operation) -> Option<Response> {
42-
let schema = ctx.schema.subschema_for::<T>().into_object();
42+
let json_schema = ctx.schema.subschema_for::<T>();
43+
let resolved_schema = ctx.resolve_schema(&json_schema);
4344

4445
Some(Response {
45-
description: ctx
46-
.resolve_schema(&schema)
47-
.metadata
48-
.as_ref()
49-
.and_then(|metadata| metadata.description.as_ref())
50-
.cloned()
46+
description: resolved_schema
47+
.get("description")
48+
.and_then(|d| d.as_str())
49+
.map(String::from)
5150
.unwrap_or_default(),
5251
content: IndexMap::from_iter([(
5352
"application/json".into(),
5453
MediaType {
5554
schema: Some(SchemaObject {
56-
json_schema: schema.into(),
55+
json_schema,
5756
example: None,
5857
external_docs: None,
5958
}),
@@ -94,21 +93,20 @@ where
9493
type Inner = T;
9594

9695
fn operation_response(ctx: &mut GenContext, _operation: &mut Operation) -> Option<Response> {
97-
let schema = ctx.schema.subschema_for::<T>().into_object();
96+
let json_schema = ctx.schema.subschema_for::<T>();
97+
let resolved_schema = ctx.resolve_schema(&json_schema);
9898

9999
Some(Response {
100-
description: ctx
101-
.resolve_schema(&schema)
102-
.metadata
103-
.as_ref()
104-
.and_then(|metadata| metadata.description.as_ref())
105-
.cloned()
100+
description: resolved_schema
101+
.get("description")
102+
.and_then(|d| d.as_str())
103+
.map(String::from)
106104
.unwrap_or_default(),
107105
content: IndexMap::from_iter([(
108106
"application/x-www-form-urlencoded".into(),
109107
MediaType {
110108
schema: Some(SchemaObject {
111-
json_schema: schema.into(),
109+
json_schema: json_schema.into(),
112110
example: None,
113111
external_docs: None,
114112
}),
@@ -151,13 +149,9 @@ impl<T> OperationOutput for Html<T> {
151149
"text/html".into(),
152150
MediaType {
153151
schema: Some(SchemaObject {
154-
json_schema: schemars::schema::SchemaObject {
155-
instance_type: Some(SingleOrVec::Single(Box::new(
156-
InstanceType::String,
157-
))),
158-
..Default::default()
159-
}
160-
.into(),
152+
json_schema: json_schema!({
153+
"type": "string",
154+
}),
161155
example: None,
162156
external_docs: None,
163157
}),

crates/aide/src/axum/routing/typed.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,11 @@ where
145145
{
146146
fn operation_input(ctx: &mut crate::generate::GenContext, operation: &mut Operation) {
147147
// `subschema_for` `description` is none, while `root_schema_for` is some
148-
let schema = ctx.schema.root_schema_for::<T>().schema;
149-
operation.description = schema.metadata.as_ref().and_then(|x| x.description.clone());
148+
let schema = ctx.schema.root_schema_for::<T>();
149+
operation.description = schema
150+
.get("description")
151+
.and_then(|d| d.as_str())
152+
.map(String::from);
150153
let params = parameters_from_schema(ctx, schema, ParamLocation::Path);
151154
add_parameters(ctx, operation, params);
152155
}

crates/aide/src/generate.rs

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,8 @@
33
use std::cell::RefCell;
44

55
use cfg_if::cfg_if;
6-
use schemars::{
7-
gen::{SchemaGenerator, SchemaSettings},
8-
schema::SchemaObject,
9-
};
6+
use schemars::{generate::SchemaSettings, Schema, SchemaGenerator};
7+
use serde_json::Value;
108

119
use crate::error::Error;
1210

@@ -186,18 +184,15 @@ impl GenContext {
186184
/// if [`extract_schemas`] is enabled, in which case most generated
187185
/// schema objects are references.
188186
#[must_use]
189-
pub fn resolve_schema<'s>(&'s self, schema_or_ref: &'s SchemaObject) -> &'s SchemaObject {
190-
match &schema_or_ref.reference {
191-
Some(r) => self
187+
pub fn resolve_schema<'s>(&'s self, schema_or_ref: &'s Schema) -> &'s Schema {
188+
match &schema_or_ref.as_object().and_then(|o| o.get("$ref")) {
189+
Some(Value::String(r)) => self
192190
.schema
193191
.definitions()
194192
.get(r.strip_prefix("#/components/schemas/").unwrap_or(r))
195-
.and_then(|s| match s {
196-
schemars::schema::Schema::Bool(_) => None,
197-
schemars::schema::Schema::Object(o) => Some(o),
198-
})
193+
.and_then(|s| Into::<serde_json::Result<&Schema>>::into(s.try_into()).ok())
199194
.unwrap_or(schema_or_ref),
200-
None => schema_or_ref,
195+
_ => schema_or_ref,
201196
}
202197
}
203198
}

0 commit comments

Comments
 (0)