1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
use aide::openapi::{OpenApi, SchemaObject, StatusCode};
use axum::http::Method;
use schemars::{gen::SchemaGenerator, schema::Schema, JsonSchema};

pub fn schema_with_properties<T: JsonSchema>(
	generator: &mut SchemaGenerator,
	cb: impl Fn(String, &mut schemars::schema::SchemaObject, usize),
) -> Schema {
	let mut schema = generator.root_schema_for::<T>().schema;
	let metadata = schema.metadata();

	metadata.title = Some(metadata.title.as_ref().map_or_else(
		|| T::schema_name(),
		|title| title.split('_').next().unwrap().to_string(),
	));

	let object = schema.object();
	for (index, (name, property)) in object.properties.clone().into_iter().enumerate() {
		let mut property: schemars::schema::SchemaObject = property.clone().into_object();

		cb(name.clone(), &mut property, index);
		object.properties.insert(name, property.into());
	}

	schemars::schema::Schema::Object(schema)
}

pub fn replace_request_schema(
	api: &mut OpenApi,
	path: &str,
	(method, media_type): (Method, &str),
	schema: schemars::schema::SchemaObject,
) -> Option<()> {
	let paths = api.paths.as_mut()?;
	let item = paths.paths.get_mut(path)?.as_item_mut()?;
	let operation = match method {
		Method::GET => item.get.as_mut()?,
		Method::PUT => item.put.as_mut()?,
		Method::POST => item.post.as_mut()?,
		Method::HEAD => item.head.as_mut()?,
		Method::TRACE => item.trace.as_mut()?,
		Method::DELETE => item.delete.as_mut()?,
		Method::OPTIONS => item.options.as_mut()?,
		_ => return None,
	};

	let body = operation.request_body.as_mut()?.as_item_mut()?;

	body.content.get_mut(media_type)?.schema = Some(SchemaObject {
		example: None,
		external_docs: None,
		json_schema: Schema::Object(schema),
	});

	Some(())
}

pub fn replace_response_schema(
	api: &mut OpenApi,
	path: &str,
	(method, status_code, media_type): (Method, StatusCode, &str),
	json_schema: schemars::schema::SchemaObject,
) -> Option<()> {
	let paths = api.paths.as_mut()?;
	let item = paths.paths.get_mut(path)?.as_item_mut()?;
	let operation = match method {
		Method::GET => item.get.as_mut()?,
		Method::PUT => item.put.as_mut()?,
		Method::POST => item.post.as_mut()?,
		Method::HEAD => item.head.as_mut()?,
		Method::TRACE => item.trace.as_mut()?,
		Method::DELETE => item.delete.as_mut()?,
		Method::OPTIONS => item.options.as_mut()?,
		_ => return None,
	};

	let responses = operation.responses.as_mut()?;
	let response = responses
		.responses
		.get_mut(&status_code)
		.unwrap()
		.as_item_mut()?;

	response.content.get_mut(media_type)?.schema = Some(SchemaObject {
		example: None,
		external_docs: None,
		json_schema: Schema::Object(json_schema),
	});

	Some(())
}