Skip to content

Commit 937e383

Browse files
committed
Improve OpenAPI documentation for GET /api/v1/me/tokens endpoint
1 parent 58f9d76 commit 937e383

File tree

6 files changed

+135
-5
lines changed

6 files changed

+135
-5
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/crates_io_database/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ sha2 = "=0.10.8"
2525
thiserror = "=2.0.12"
2626
tracing = "=0.1.41"
2727
unicode-xid = "=0.2.6"
28+
utoipa = "=5.3.1"
2829

2930
[dev-dependencies]
3031
claims = "=0.8.0"

crates/crates_io_database/src/models/token.rs

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,21 +39,43 @@ impl NewApiToken {
3939
}
4040

4141
/// The model representing a row in the `api_tokens` database table.
42-
#[derive(Debug, Identifiable, Queryable, Selectable, Associations, serde::Serialize)]
42+
#[derive(
43+
Debug, Identifiable, Queryable, Selectable, Associations, serde::Serialize, utoipa::ToSchema,
44+
)]
4345
#[diesel(belongs_to(User))]
4446
pub struct ApiToken {
47+
/// An opaque unique identifier for the token.
48+
#[schema(example = 42)]
4549
pub id: i32,
50+
4651
#[serde(skip)]
4752
pub user_id: i32,
53+
54+
/// The name of the token.
55+
#[schema(example = "Example API Token")]
4856
pub name: String,
57+
58+
/// The date and time when the token was created.
59+
#[schema(example = "2017-01-06T14:23:11Z")]
4960
pub created_at: DateTime<Utc>,
61+
62+
/// The date and time when the token was last used.
63+
#[schema(example = "2021-10-26T11:32:12Z")]
5064
pub last_used_at: Option<DateTime<Utc>>,
65+
5166
#[serde(skip)]
5267
pub revoked: bool,
53-
/// `None` or a list of crate scope patterns (see RFC #2947)
68+
69+
/// `None` or a list of crate scope patterns (see RFC #2947).
70+
#[schema(value_type = Option<Vec<String>>, example = json!(["serde"]))]
5471
pub crate_scopes: Option<Vec<CrateScope>>,
55-
/// A list of endpoint scopes or `None` for the `legacy` endpoint scope (see RFC #2947)
72+
73+
/// A list of endpoint scopes or `None` for the `legacy` endpoint scope (see RFC #2947).
74+
#[schema(example = json!(["publish-update"]))]
5675
pub endpoint_scopes: Option<Vec<EndpointScope>>,
76+
77+
/// The date and time when the token will expire, or `null`.
78+
#[schema(example = "2030-10-26T11:32:12Z")]
5779
pub expired_at: Option<DateTime<Utc>>,
5880
}
5981

crates/crates_io_database/src/models/token/scopes.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ use diesel::serialize::{self, IsNull, Output, ToSql};
55
use diesel::sql_types::Text;
66
use std::io::Write;
77

8-
#[derive(Clone, Copy, Debug, PartialEq, Eq, diesel::AsExpression, serde::Serialize)]
8+
#[derive(
9+
Clone, Copy, Debug, PartialEq, Eq, diesel::AsExpression, serde::Serialize, utoipa::ToSchema,
10+
)]
911
#[diesel(sql_type = Text)]
1012
#[serde(rename_all = "kebab-case")]
1113
pub enum EndpointScope {

src/controllers/token.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,18 @@ impl GetParams {
3737
}
3838
}
3939

40+
#[derive(Debug, Serialize, utoipa::ToSchema)]
41+
pub struct ListResponse {
42+
pub api_tokens: Vec<ApiToken>,
43+
}
44+
4045
/// List all API tokens of the authenticated user.
4146
#[utoipa::path(
4247
get,
4348
path = "/api/v1/me/tokens",
4449
security(("cookie" = [])),
4550
tag = "api_tokens",
46-
responses((status = 200, description = "Successful Response")),
51+
responses((status = 200, description = "Successful Response", body = inline(ListResponse))),
4752
)]
4853
pub async fn list_api_tokens(
4954
app: AppState,

src/snapshots/crates_io__openapi__tests__openapi_snapshot.snap

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,78 @@ expression: response.json()
55
{
66
"components": {
77
"schemas": {
8+
"ApiToken": {
9+
"description": "The model representing a row in the `api_tokens` database table.",
10+
"properties": {
11+
"crate_scopes": {
12+
"description": "`None` or a list of crate scope patterns (see RFC #2947).",
13+
"example": [
14+
"serde"
15+
],
16+
"items": {
17+
"type": "string"
18+
},
19+
"type": [
20+
"array",
21+
"null"
22+
]
23+
},
24+
"created_at": {
25+
"description": "The date and time when the token was created.",
26+
"example": "2017-01-06T14:23:11Z",
27+
"format": "date-time",
28+
"type": "string"
29+
},
30+
"endpoint_scopes": {
31+
"description": "A list of endpoint scopes or `None` for the `legacy` endpoint scope (see RFC #2947).",
32+
"example": [
33+
"publish-update"
34+
],
35+
"items": {
36+
"$ref": "#/components/schemas/EndpointScope"
37+
},
38+
"type": [
39+
"array",
40+
"null"
41+
]
42+
},
43+
"expired_at": {
44+
"description": "The date and time when the token will expire, or `null`.",
45+
"example": "2030-10-26T11:32:12Z",
46+
"format": "date-time",
47+
"type": [
48+
"string",
49+
"null"
50+
]
51+
},
52+
"id": {
53+
"description": "An opaque unique identifier for the token.",
54+
"example": 42,
55+
"format": "int32",
56+
"type": "integer"
57+
},
58+
"last_used_at": {
59+
"description": "The date and time when the token was last used.",
60+
"example": "2021-10-26T11:32:12Z",
61+
"format": "date-time",
62+
"type": [
63+
"string",
64+
"null"
65+
]
66+
},
67+
"name": {
68+
"description": "The name of the token.",
69+
"example": "Example API Token",
70+
"type": "string"
71+
}
72+
},
73+
"required": [
74+
"id",
75+
"name",
76+
"created_at"
77+
],
78+
"type": "object"
79+
},
880
"AuthenticatedUser": {
981
"properties": {
1082
"avatar": {
@@ -497,6 +569,15 @@ expression: response.json()
497569
],
498570
"type": "object"
499571
},
572+
"EndpointScope": {
573+
"enum": [
574+
"publish-new",
575+
"publish-update",
576+
"yank",
577+
"change-owners"
578+
],
579+
"type": "string"
580+
},
500581
"Keyword": {
501582
"properties": {
502583
"crates_cnt": {
@@ -3551,6 +3632,24 @@ expression: response.json()
35513632
"operationId": "list_api_tokens",
35523633
"responses": {
35533634
"200": {
3635+
"content": {
3636+
"application/json": {
3637+
"schema": {
3638+
"properties": {
3639+
"api_tokens": {
3640+
"items": {
3641+
"$ref": "#/components/schemas/ApiToken"
3642+
},
3643+
"type": "array"
3644+
}
3645+
},
3646+
"required": [
3647+
"api_tokens"
3648+
],
3649+
"type": "object"
3650+
}
3651+
}
3652+
},
35543653
"description": "Successful Response"
35553654
}
35563655
},

0 commit comments

Comments
 (0)