From 43ff6dc9d395707dcd1d20f8f6145901ed057d06 Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Wed, 24 Jul 2024 15:44:08 +0200 Subject: [PATCH] doc: auto-generate the API schema in the documentation --- crates/handlers/src/bin/api-schema.rs | 72 +++++++++++++++++++++++++++ docs/api.schema.json | 50 +++++++++++++++++++ misc/update.sh | 2 + 3 files changed, 124 insertions(+) create mode 100644 crates/handlers/src/bin/api-schema.rs create mode 100644 docs/api.schema.json diff --git a/crates/handlers/src/bin/api-schema.rs b/crates/handlers/src/bin/api-schema.rs new file mode 100644 index 00000000..788560b0 --- /dev/null +++ b/crates/handlers/src/bin/api-schema.rs @@ -0,0 +1,72 @@ +// Copyright 2022 The Matrix.org Foundation C.I.C. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![forbid(unsafe_code)] +#![deny( + clippy::all, + clippy::str_to_string, + rustdoc::broken_intra_doc_links, + clippy::future_not_send +)] +#![warn(clippy::pedantic)] + +use std::io::Write; + +/// This is a dummy state, it should never be used. +/// +/// We use it to generate the API schema, which doesn't execute any request. +#[derive(Clone)] +struct DummyState; + +macro_rules! impl_from_request_parts { + ($type:ty) => { + #[axum::async_trait] + impl axum::extract::FromRequestParts for $type { + type Rejection = std::convert::Infallible; + + async fn from_request_parts( + _parts: &mut axum::http::request::Parts, + _state: &DummyState, + ) -> Result { + unimplemented!("This is a dummy state, it should never be used") + } + } + }; +} + +macro_rules! impl_from_ref { + ($type:ty) => { + impl axum::extract::FromRef for $type { + fn from_ref(_input: &DummyState) -> Self { + unimplemented!("This is a dummy state, it should never be used") + } + } + }; +} + +impl_from_request_parts!(mas_storage::BoxRepository); +impl_from_request_parts!(mas_storage::BoxClock); +impl_from_request_parts!(mas_handlers::BoundActivityTracker); +impl_from_ref!(mas_keystore::Keystore); + +fn main() -> Result<(), Box> { + let (api, _) = mas_handlers::admin_api_router::(); + let mut stdout = std::io::stdout(); + serde_json::to_writer_pretty(&mut stdout, &api)?; + + // Make sure we end with a newline + stdout.write_all(b"\n")?; + + Ok(()) +} diff --git a/docs/api.schema.json b/docs/api.schema.json new file mode 100644 index 00000000..33e9c21a --- /dev/null +++ b/docs/api.schema.json @@ -0,0 +1,50 @@ +{ + "openapi": "3.1.0", + "info": { + "title": "Matrix Authentication Service admin API", + "version": "" + }, + "servers": [ + { + "url": "{base}", + "variables": { + "base": { + "default": "/", + "description": null + } + } + } + ], + "paths": {}, + "components": { + "securitySchemes": { + "oauth2": { + "type": "oauth2", + "flows": { + "clientCredentials": { + "refreshUrl": "/oauth2/token", + "tokenUrl": "/oauth2/token", + "scopes": { + "urn:mas:admin": "Grant access to the admin API" + } + }, + "authorizationCode": { + "authorizationUrl": "/authorize", + "tokenUrl": "/oauth2/token", + "refreshUrl": "/oauth2/token", + "scopes": { + "urn:mas:admin": "Grant access to the admin API" + } + } + } + } + } + }, + "security": [ + { + "oauth2": [ + "urn:mas:admin" + ] + } + ] +} diff --git a/misc/update.sh b/misc/update.sh index 0ad0f61b..9f9f26ab 100644 --- a/misc/update.sh +++ b/misc/update.sh @@ -5,12 +5,14 @@ set -eu export SQLX_OFFLINE=1 BASE_DIR="$(dirname "$0")/.." CONFIG_SCHEMA="${BASE_DIR}/docs/config.schema.json" +API_SCHEMA="${BASE_DIR}/docs/api.schema.json" GRAPHQL_SCHEMA="${BASE_DIR}/frontend/schema.graphql" POLICIES_SCHEMA="${BASE_DIR}/policies/schema/" set -x cargo run -p mas-config > "${CONFIG_SCHEMA}" cargo run -p mas-handlers --bin graphql-schema > "${GRAPHQL_SCHEMA}" +cargo run -p mas-handlers --bin api-schema > "${API_SCHEMA}" cargo run -p mas-i18n-scan -- --update "${BASE_DIR}/templates/" "${BASE_DIR}/translations/en.json" OUT_DIR="${POLICIES_SCHEMA}" cargo run -p mas-policy --features jsonschema