Skip to content
This repository was archived by the owner on Sep 10, 2024. It is now read-only.

Commit f1bf85e

Browse files
committed
Tweak the schema generation and use a common definition for ULIDs
1 parent 2716fb0 commit f1bf85e

File tree

5 files changed

+116
-92
lines changed

5 files changed

+116
-92
lines changed

crates/handlers/src/admin/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ mod call_context;
3737
mod model;
3838
mod params;
3939
mod response;
40+
mod schema;
4041
mod v1;
4142

4243
use self::call_context::CallContext;
@@ -48,6 +49,10 @@ where
4849
Templates: FromRef<S>,
4950
UrlBuilder: FromRef<S>,
5051
{
52+
aide::gen::in_context(|ctx| {
53+
ctx.schema = schemars::gen::SchemaGenerator::new(schemars::gen::SchemaSettings::openapi3());
54+
});
55+
5156
let mut api = OpenApi::default();
5257
let router = ApiRouter::<S>::new()
5358
.nest("/api/admin/v1", self::v1::router())

crates/handlers/src/admin/params.rs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,8 @@ impl IntoResponse for UlidPathParamRejection {
5252

5353
#[derive(JsonSchema, Debug, Clone, Copy, Deserialize)]
5454
struct UlidInPath {
55-
#[schemars(
56-
with = "String",
57-
title = "ULID",
58-
description = "A ULID as per https://github.com/ulid/spec",
59-
regex(pattern = r"^[0123456789ABCDEFGHJKMNPQRSTVWXYZ]{26}$")
60-
)]
55+
/// # The ID of the resource
56+
#[schemars(with = "super::schema::Ulid")]
6157
id: Ulid,
6258
}
6359

@@ -81,12 +77,12 @@ const DEFAULT_PAGE_SIZE: usize = 10;
8177
struct PaginationParams {
8278
/// Retrieve the items before the given ID
8379
#[serde(rename = "page[before]")]
84-
#[schemars(with = "Option<String>")]
80+
#[schemars(with = "Option<super::schema::Ulid>")]
8581
before: Option<Ulid>,
8682

8783
/// Retrieve the items after the given ID
8884
#[serde(rename = "page[after]")]
89-
#[schemars(with = "Option<String>")]
85+
#[schemars(with = "Option<super::schema::Ulid>")]
9086
after: Option<Ulid>,
9187

9288
/// Retrieve the first N items

crates/handlers/src/admin/response.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ struct SingleResource<T> {
143143
type_: &'static str,
144144

145145
/// The ID of the resource
146-
#[schemars(with = "String")]
146+
#[schemars(with = "super::schema::Ulid")]
147147
id: Ulid,
148148

149149
/// The attributes of the resource
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// Copyright 2024 The Matrix.org Foundation C.I.C.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
//! Common schema definitions
16+
17+
use schemars::{
18+
gen::SchemaGenerator,
19+
schema::{InstanceType, Metadata, Schema, SchemaObject, StringValidation},
20+
JsonSchema,
21+
};
22+
23+
/// A type to use for schema definitions of ULIDs
24+
///
25+
/// Use with `#[schemars(with = "crate::admin::schema::Ulid")]`
26+
pub struct Ulid;
27+
28+
impl JsonSchema for Ulid {
29+
fn schema_name() -> String {
30+
"ULID".to_owned()
31+
}
32+
33+
fn json_schema(_gen: &mut SchemaGenerator) -> Schema {
34+
SchemaObject {
35+
instance_type: Some(InstanceType::String.into()),
36+
37+
metadata: Some(Box::new(Metadata {
38+
title: Some("ULID".into()),
39+
description: Some("A ULID as per https://github.com/ulid/spec".into()),
40+
examples: vec![
41+
"01ARZ3NDEKTSV4RRFFQ69G5FAV".into(),
42+
"01J41912SC8VGAQDD50F6APK91".into(),
43+
],
44+
..Metadata::default()
45+
})),
46+
47+
string: Some(Box::new(StringValidation {
48+
pattern: Some(r"^[0123456789ABCDEFGHJKMNPQRSTVWXYZ]{26}$".into()),
49+
..StringValidation::default()
50+
})),
51+
52+
..SchemaObject::default()
53+
}
54+
.into()
55+
}
56+
}

docs/api/spec.json

Lines changed: 50 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,8 @@
2929
"description": "Retrieve the items before the given ID",
3030
"schema": {
3131
"description": "Retrieve the items before the given ID",
32-
"type": [
33-
"string",
34-
"null"
35-
]
32+
"$ref": "#/components/schemas/ULID",
33+
"nullable": true
3634
},
3735
"style": "form"
3836
},
@@ -42,10 +40,8 @@
4240
"description": "Retrieve the items after the given ID",
4341
"schema": {
4442
"description": "Retrieve the items after the given ID",
45-
"type": [
46-
"string",
47-
"null"
48-
]
43+
"$ref": "#/components/schemas/ULID",
44+
"nullable": true
4945
},
5046
"style": "form"
5147
},
@@ -55,12 +51,10 @@
5551
"description": "Retrieve the first N items",
5652
"schema": {
5753
"description": "Retrieve the first N items",
58-
"type": [
59-
"integer",
60-
"null"
61-
],
54+
"type": "integer",
6255
"format": "uint",
63-
"minimum": 1.0
56+
"minimum": 1.0,
57+
"nullable": true
6458
},
6559
"style": "form"
6660
},
@@ -70,38 +64,28 @@
7064
"description": "Retrieve the last N items",
7165
"schema": {
7266
"description": "Retrieve the last N items",
73-
"type": [
74-
"integer",
75-
"null"
76-
],
67+
"type": "integer",
7768
"format": "uint",
78-
"minimum": 1.0
69+
"minimum": 1.0,
70+
"nullable": true
7971
},
8072
"style": "form"
8173
},
8274
{
8375
"in": "query",
8476
"name": "filter[can_request_admin]",
8577
"schema": {
86-
"type": [
87-
"boolean",
88-
"null"
89-
]
78+
"type": "boolean",
79+
"nullable": true
9080
},
9181
"style": "form"
9282
},
9383
{
9484
"in": "query",
9585
"name": "filter[status]",
9686
"schema": {
97-
"anyOf": [
98-
{
99-
"$ref": "#/components/schemas/UserStatus"
100-
},
101-
{
102-
"type": "null"
103-
}
104-
]
87+
"$ref": "#/components/schemas/UserStatus",
88+
"nullable": true
10589
},
10690
"style": "form"
10791
}
@@ -182,13 +166,10 @@
182166
{
183167
"in": "path",
184168
"name": "id",
185-
"description": "A ULID as per https://github.com/ulid/spec",
186169
"required": true,
187170
"schema": {
188-
"title": "ULID",
189-
"description": "A ULID as per https://github.com/ulid/spec",
190-
"type": "string",
191-
"pattern": "^[0123456789ABCDEFGHJKMNPQRSTVWXYZ]{26}$"
171+
"title": "The ID of the resource",
172+
"$ref": "#/components/schemas/ULID"
192173
},
193174
"style": "simple"
194175
}
@@ -340,56 +321,50 @@
340321
"properties": {
341322
"page[before]": {
342323
"description": "Retrieve the items before the given ID",
343-
"type": [
344-
"string",
345-
"null"
346-
]
324+
"$ref": "#/components/schemas/ULID",
325+
"nullable": true
347326
},
348327
"page[after]": {
349328
"description": "Retrieve the items after the given ID",
350-
"type": [
351-
"string",
352-
"null"
353-
]
329+
"$ref": "#/components/schemas/ULID",
330+
"nullable": true
354331
},
355332
"page[first]": {
356333
"description": "Retrieve the first N items",
357-
"type": [
358-
"integer",
359-
"null"
360-
],
334+
"type": "integer",
361335
"format": "uint",
362-
"minimum": 1.0
336+
"minimum": 1.0,
337+
"nullable": true
363338
},
364339
"page[last]": {
365340
"description": "Retrieve the last N items",
366-
"type": [
367-
"integer",
368-
"null"
369-
],
341+
"type": "integer",
370342
"format": "uint",
371-
"minimum": 1.0
343+
"minimum": 1.0,
344+
"nullable": true
372345
}
373346
}
374347
},
348+
"ULID": {
349+
"title": "ULID",
350+
"description": "A ULID as per https://github.com/ulid/spec",
351+
"examples": [
352+
"01ARZ3NDEKTSV4RRFFQ69G5FAV",
353+
"01J41912SC8VGAQDD50F6APK91"
354+
],
355+
"type": "string",
356+
"pattern": "^[0123456789ABCDEFGHJKMNPQRSTVWXYZ]{26}$"
357+
},
375358
"FilterParams": {
376359
"type": "object",
377360
"properties": {
378361
"filter[can_request_admin]": {
379-
"type": [
380-
"boolean",
381-
"null"
382-
]
362+
"type": "boolean",
363+
"nullable": true
383364
},
384365
"filter[status]": {
385-
"anyOf": [
386-
{
387-
"$ref": "#/components/schemas/UserStatus"
388-
},
389-
{
390-
"type": "null"
391-
}
392-
]
366+
"$ref": "#/components/schemas/UserStatus",
367+
"nullable": true
393368
}
394369
}
395370
},
@@ -467,7 +442,7 @@
467442
},
468443
"id": {
469444
"description": "The ID of the resource",
470-
"type": "string"
445+
"$ref": "#/components/schemas/ULID"
471446
},
472447
"attributes": {
473448
"description": "The attributes of the resource",
@@ -499,11 +474,9 @@
499474
},
500475
"locked_at": {
501476
"description": "When the user was locked. If null, the user is not locked.",
502-
"type": [
503-
"string",
504-
"null"
505-
],
506-
"format": "date-time"
477+
"type": "string",
478+
"format": "date-time",
479+
"nullable": true
507480
},
508481
"can_request_admin": {
509482
"description": "Whether the user can request admin privileges.",
@@ -547,17 +520,13 @@
547520
},
548521
"next": {
549522
"description": "The link to the next page of results\n\nOnly present if there is a next page",
550-
"type": [
551-
"string",
552-
"null"
553-
]
523+
"type": "string",
524+
"nullable": true
554525
},
555526
"prev": {
556527
"description": "The link to the previous page of results\n\nOnly present if there is a previous page",
557-
"type": [
558-
"string",
559-
"null"
560-
]
528+
"type": "string",
529+
"nullable": true
561530
}
562531
}
563532
},
@@ -597,10 +566,8 @@
597566
],
598567
"properties": {
599568
"id": {
600-
"title": "ULID",
601-
"description": "A ULID as per https://github.com/ulid/spec",
602-
"type": "string",
603-
"pattern": "^[0123456789ABCDEFGHJKMNPQRSTVWXYZ]{26}$"
569+
"title": "The ID of the resource",
570+
"$ref": "#/components/schemas/ULID"
604571
}
605572
}
606573
},

0 commit comments

Comments
 (0)