blog/backend/server/src/api_doc.rs
SquidSpirit e255e076dc
All checks were successful
Frontend CI / build (push) Successful in 1m8s
BLOG-103 Add API documentation with Utoipa (#106)
### Description

This PR integrates the **`utoipa`** and **`utoipa-redoc`** crates to automatically generate OpenAPI-compliant API documentation for the backend project.

#### Overview

To improve development efficiency and API maintainability, this change introduces `utoipa` to automate the API documentation process. By adding specific attribute macros to the source code, we can generate detailed API specifications directly and serve them through an interactive UI provided by `utoipa-redoc`.

#### Key Changes

* **Dependencies Added**
    * Added `utoipa`, `utoipa-gen`, and `utoipa-redoc` to `Cargo.toml`.
    * `utoipa` is used to define OpenAPI objects.
    * `utoipa-redoc` is used to serve the ReDoc documentation UI.

* **Code Refactoring**
    * **HTTP handler logic** in each feature (`auth`, `image`, `post`) has been extracted from the `..._web_routes.rs` files into their own dedicated files (e.g., `get_post_by_id_handler.rs`). This makes the code structure cleaner and simplifies adding documentation attributes to each handler.
    * Renamed the `PostController` method from `get_full_post` to `get_post_by_id` for a more RESTful-compliant naming convention.

* **API Doc Annotation**
    * Added `#[derive(ToSchema)]` or `#[derive(IntoParams)]` to all DTOs (Data Transfer Objects) so they can be recognized by `utoipa` to generate the corresponding schemas.
    * Added the `#[utoipa::path]` macro to all HTTP handler functions, describing the API's path, HTTP method, tags, summary, expected responses, and security settings.

* **Doc Aggregation & Serving**
    * Added an `..._api_doc.rs` file in each feature module to aggregate all API paths within that module.
    * Added a new `api_doc.rs` file in the `server` crate to merge the OpenAPI documents from all features, set global information (like title, version, and the OAuth2 security scheme), and serve the documentation page on the `/redoc` route using `Redoc::with_url`.

### Package Changes

```toml
utoipa = { version = "5.4.0", features = ["actix_extras"] }
utoipa-redoc = { version = "6.0.0", features = ["actix-web"] }
```

### Screenshots

![image.png](/attachments/f5b4b268-f550-4d9e-9321-49a00f6b8e1a)

### Reference

Resolves #103

### Checklist

- [x] A milestone is set
- [x] The related issuse has been linked to this branch

Reviewed-on: #106
Co-authored-by: SquidSpirit <squid@squidspirit.com>
Co-committed-by: SquidSpirit <squid@squidspirit.com>
2025-08-02 06:51:37 +08:00

47 lines
1.3 KiB
Rust

use actix_web::web;
use auth::framework::web::auth_api_doc;
use image::framework::web::image_api_doc;
use post::framework::web::post_api_doc;
use utoipa::{
OpenApi,
openapi::{
Components, InfoBuilder, OpenApiBuilder,
security::{AuthorizationCode, Flow, OAuth2, Scopes, SecurityScheme},
},
};
use utoipa_redoc::{Redoc, Servable};
pub struct ApiDoc;
impl utoipa::OpenApi for ApiDoc {
fn openapi() -> utoipa::openapi::OpenApi {
let mut components = Components::new();
components.add_security_scheme(
"oauth2",
SecurityScheme::OAuth2(OAuth2::new(vec![Flow::AuthorizationCode(
AuthorizationCode::new("/auth/login", "/auth/callback", Scopes::new()),
)])),
);
OpenApiBuilder::new()
.info(
InfoBuilder::new()
.title("SquidSpirit API")
.version(env!("CARGO_PKG_VERSION"))
.build(),
)
.components(Some(components))
.build()
}
}
pub fn configure_api_doc_routes(cfg: &mut web::ServiceConfig) {
let openapi = ApiDoc::openapi()
.merge_from(auth_api_doc::openapi())
.merge_from(image_api_doc::openapi())
.merge_from(post_api_doc::openapi());
cfg.service(Redoc::with_url("/redoc", openapi));
}