diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index d0b76502..f3e97ef8 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -71,5 +71,5 @@ jobs: elif [[ "${{ matrix.testset }}" == "utoipa-gen" ]] && [[ ${{ steps.changes.outputs.gen_changed }} == true ]]; then cargo test -p utoipa-gen --features actix_extras elif [[ "${{ matrix.testset }}" == "utoipa-swagger-ui" ]] && [[ ${{ steps.changes.outputs.swagger_changed }} == true ]]; then - cargo test -p utoipa-swagger-ui --features actix-web + cargo test -p utoipa-swagger-ui --features actix-web,rocket fi diff --git a/README.md b/README.md index 04cb13d9..1d7f5448 100644 --- a/README.md +++ b/README.md @@ -31,8 +31,7 @@ Existing [examples](./examples) for following frameworks: * **actix-web** * **warp** * **tide** - -**actix-web** has support support for actix specific parsing via **actix_extras** feature. +* **rocket** Even if there is no example for your favourite framework `utoipa` can be used with any web framework which supports decorating functions with macros similarly to **warp** and **tide** examples. @@ -49,10 +48,11 @@ and the `ipa` is _api_ reversed. Aaand... `ipa` is also awesome type of beer :be enabled by default. * **yaml** Enables **serde_yaml** serialization of OpenApi objects. * **actix_extras** Enhances [actix-web](https://github.com/actix/actix-web/) intgration with being able to - parse `path` and `path parameters` from actix web path attribute macros. See the - [path attribute macro](https://docs.rs/utoipa/0.1.2/utoipa/attr.path.html) for more details. + parse `path` and `path parameters` from actix web path attribute macros. See + [docs](https://docs.rs/utoipa/0.1.2/utoipa/attr.path.html#actix_extras-support-for-actix-web) or [examples](./examples) for more details. * **rocket_extras** Enhances [rocket](https://github.com/SergioBenitez/Rocket) framework integration with being - able to parse `path`, `path and query parameters` from rocket path attribute macros. + able to parse `path`, `path and query parameters` from rocket path attribute macros. See [docs](https://docs.rs/utoipa/0.1.2/utoipa/attr.path.html#rocket_extras-support-for-rocket) + or [examples](./examples) for more details. * **debug** Add extra traits such as debug traits to openapi definitions and elsewhere. * **chrono_types** Add support for [chrono](https://crates.io/crates/chrono) `DateTime`, `Date` and `Duration` types. By default these types are parsed to `string` types without additional format. If you want to have formats added to the types diff --git a/src/lib.rs b/src/lib.rs index 648537a6..940d2690 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -28,8 +28,7 @@ //! * **actix-web** //! * **warp** //! * **tide** -//! -//! **actix-web** has support support for actix specific parsing via **actix_extras** feature. +//! * **rocket** //! //! Even if there is no example for your favourite framework `utoipa` can be used with any //! web framework which supports decorating functions with macros similarly to **warp** and **tide** examples. @@ -46,10 +45,11 @@ //! This is enabled by default. //! * **yaml** Enables **serde_yaml** serialization of OpenApi objects. //! * **actix_extras** Enhances [actix-web](https://github.com/actix/actix-web/) intgration with being able to -//! parse `path` and `path parameters` from actix web path attribute macros. See [`utoipa::path(...)`][path] -//! for more details. +//! parse `path` and `path parameters` from actix web path attribute macros. See [actix extras support][actix_path] or +//! [examples](https://github.com/juhaku/utoipa/tree/master/examples) for more details. //! * **rocket_extras** Enhances [rocket](https://github.com/SergioBenitez/Rocket) framework integration with being -//! able to parse `path`, `path and query parameters` from rocket path attribute macros. +//! able to parse `path`, `path and query parameters` from rocket path attribute macros. See [rocket extras support][rocket_path] +//! or [examples](https://github.com/juhaku/utoipa/tree/master/examples) for more details //! * **debug** Add extra traits such as debug traits to openapi definitions and elsewhere. //! * **chrono_types** Add support for [chrono](https://crates.io/crates/chrono) `DateTime`, `Date` and `Duration` types. By default these types //! are parsed to `string` types without @@ -188,6 +188,8 @@ //! * More about OpenAPI security in [security documentation][security]. //! //! [path]: attr.path.html +//! [rocket_path]: attr.path.html#rocket_extras-support-for-rocket +//! [actix_path]: attr.path.html#actix_extras-support-for-actix-web //! //! [security]: openapi/security/index.html //! [component_derive]: derive.Component.html diff --git a/utoipa-gen/src/lib.rs b/utoipa-gen/src/lib.rs index 54e0aade..c504fb72 100644 --- a/utoipa-gen/src/lib.rs +++ b/utoipa-gen/src/lib.rs @@ -386,6 +386,65 @@ pub fn derive_component(input: TokenStream) -> TokenStream { /// Leaving empty _`()`_ creates an empty [`SecurityRequirement`][security] this is useful when /// security requirement is optional for operation. /// +/// # actix_extras support for actix-web +/// +/// **actix_extas** feature gives **utoipa** ability to use **actix-web** path operation macros such as `#[get(...)]` to +/// resolve path for `#[utoipa::path]`. Also it is able to parse the the `path` parameters with types from function arguments +/// of operation which are defined within type `web::Path<...>`. Allowing you leave out types of parameters in `params(...)` +/// section of even leave out the section if description is not needed for parameters. Utoipa is only able to resolve +/// [primitive types][primitive] and [`String`] type. Using other types is undefined behaviour. +/// +/// See the **actix_extras** in action in examples [todo-actix](https://github.com/juhaku/utoipa/tree/master/examples/todo-actix). +/// +/// With **actix_extras** feature enabled the you can leave out definitions for **path**, **operation** and **parmater types** [^actix_extras]. +/// ```rust +/// use actix_web::{get, web, HttpResponse, Responder}; +/// use serde_json::json; +/// +/// /// Get Pet by id +/// #[utoipa::path( +/// responses( +/// (status = 200, description = "Pet found from database") +/// ), +/// params( +/// ("id", description = "Pet id"), +/// ) +/// )] +/// #[get("/pet/{id}")] +/// async fn get_pet_by_id(id: web::Path) -> impl Responder { +/// HttpResponse::Ok().json(json!({ "pet": format!("{:?}", &id.into_inner()) })) +/// } +/// ``` +/// +/// With **actix_extras** you may also not to list any _**parmas**_ if you do not want to specify any description for them. Params are resolved from +/// path and the argument types of handler. [^actix_extras] +/// ```rust +/// use actix_web::{get, web, HttpResponse, Responder}; +/// use serde_json::json; +/// +/// /// Get Pet by id +/// #[utoipa::path( +/// responses( +/// (status = 200, description = "Pet found from database") +/// ) +/// )] +/// #[get("/pet/{id}")] +/// async fn get_pet_by_id(id: web::Path) -> impl Responder { +/// HttpResponse::Ok().json(json!({ "pet": format!("{:?}", &id.into_inner()) })) +/// } +/// ``` +/// +/// # rocket_extras support for rocket +/// +/// **rocket_extras** feature give **utoipa** ability to use **rocket** path operation macros such as `#[get(...)]` to +/// resolve path for `#[utoipa::path]`. Also it is able to parse the `path` and `query` parameters from path operation macro +/// combined with function arguments of the operation. Allowing you leave out types from parameters in `params(...)` section +/// or even leave out the section if description is not needed for parameters. Utoipa is only able to parse parameter types +/// for [primitive types][primitive], [`String`], [`Vec`], [`Option`] or [`std::path::PathBuf`] type. Other function arguments are +/// simply ignored. +/// +/// See the **rocket_extras** in action in examples [rocket-todo](https://github.com/juhaku/utoipa/tree/master/examples/rocket-todo). +/// /// # Examples /// /// Example with all possible arguments. @@ -456,44 +515,6 @@ pub fn derive_component(input: TokenStream) -> TokenStream { /// } /// ``` /// -/// With **actix_extras** feature enabled the you can leave out definitions for **path**, **operation** and **parmater types** [^actix_extras]. -/// ```rust -/// use actix_web::{get, web, HttpResponse, Responder}; -/// use serde_json::json; -/// -/// /// Get Pet by id -/// #[utoipa::path( -/// responses( -/// (status = 200, description = "Pet found from database") -/// ), -/// params( -/// ("id", description = "Pet id"), -/// ) -/// )] -/// #[get("/pet/{id}")] -/// async fn get_pet_by_id(id: web::Path) -> impl Responder { -/// HttpResponse::Ok().json(json!({ "pet": format!("{:?}", &id.into_inner()) })) -/// } -/// ``` -/// -/// With **actix_extras** you may also not to list any _**parmas**_ if you do not want to specify any description for them. Params are resolved from -/// path and the argument types of handler. -/// ```rust -/// use actix_web::{get, web, HttpResponse, Responder}; -/// use serde_json::json; -/// -/// /// Get Pet by id -/// #[utoipa::path( -/// responses( -/// (status = 200, description = "Pet found from database") -/// ) -/// )] -/// #[get("/pet/{id}")] -/// async fn get_pet_by_id(id: web::Path) -> impl Responder { -/// HttpResponse::Ok().json(json!({ "pet": format!("{:?}", &id.into_inner()) })) -/// } -/// ``` -/// /// Use of Rust's own `#[deprecated]` attribute will refect to the generated OpenAPI spec and mark this operation as deprecated. /// ```rust /// # use actix_web::{get, web, HttpResponse, Responder}; diff --git a/utoipa-swagger-ui/Cargo.toml b/utoipa-swagger-ui/Cargo.toml index fe8a5b15..5a90c774 100644 --- a/utoipa-swagger-ui/Cargo.toml +++ b/utoipa-swagger-ui/Cargo.toml @@ -23,7 +23,7 @@ rocket = { version = "0.5.0-rc.1", features = ["json"], optional = true } utoipa = { version = "0.1", path = "..", default-features = false, features = [] } [package.metadata.docs.rs] -features = ["actix-web"] +features = ["actix-web", "rocket"] [build-dependencies] zip = "0.6" diff --git a/utoipa-swagger-ui/README.md b/utoipa-swagger-ui/README.md index 58f0bb0d..4a9b5146 100644 --- a/utoipa-swagger-ui/README.md +++ b/utoipa-swagger-ui/README.md @@ -11,6 +11,7 @@ works as a bridge for serving the OpenAPI documetation created with **Currently implemented boiler plate for:** * **actix-web** `version >= 4` +* **rocket** `version >=0.5.0-rc.1` Serving Swagger UI is framework independant thus this crate also supports serving the Swagger UI with other frameworks as well. With other frameworks there is bit more manual implementation to be done. See @@ -21,6 +22,8 @@ more details at [serve](https://docs.rs/utoipa-swagger-ui/0.2.0/utoipa_swagger_u * **actix-web** Enables actix-web integration with pre-configured SwaggerUI service factory allowing users to use the Swagger UI without a hazzle. +* **rocket** Enables rocket integration with with pre-configured routes for serving the Swagger UI + and api doc without a hazzle. # Install @@ -54,6 +57,19 @@ HttpServer::new(move || { ``` **actix-web** feature need to be enabled. +Serve Swagger UI with api doc via rocket. +```rust +#[rocket::launch] +fn rocket() -> Rocket { + rocket::build() + .mount( + "/", + SwaggerUi::new("/swagger-ui/<_..>").url("/api-doc/openapi.json", ApiDoc::openapi()), + ) +} +``` +**rocket** feature need to be enabled. + # License Licensed under either of [Apache 2.0](LICENSE-APACHE) or [MIT](LICENSE-MIT) license at your option. diff --git a/utoipa-swagger-ui/src/lib.rs b/utoipa-swagger-ui/src/lib.rs index 0e7f14c6..e5c98ceb 100644 --- a/utoipa-swagger-ui/src/lib.rs +++ b/utoipa-swagger-ui/src/lib.rs @@ -7,6 +7,7 @@ //! **Currently implemented boiler plate for:** //! //! * **actix-web** +//! * **rocket** `version >=0.5.0-rc.1` //! //! Serving Swagger UI is framework independant thus this crate also supports serving the Swagger UI with //! other frameworks as well. With other frameworks there is bit more manual implementation to be done. See @@ -18,6 +19,8 @@ //! //! * **actix-web** Enables actix-web integration with pre-configured SwaggerUI service factory allowing //! users to use the Swagger UI without a hazzle. +//! * **rocket** Enables rocket integration with with pre-configured routes for serving the Swagger UI +//! and api doc without a hazzle. //! //! # Install //! @@ -56,12 +59,36 @@ //! .bind((Ipv4Addr::UNSPECIFIED, 8989)).unwrap() //! .run(); //! ``` +//! +//! Serve Swagger UI with api doc via rocket [^rocket] +//! ```no_run +//! # use rocket::{Build, Rocket}; +//! # use utoipa_swagger_ui::SwaggerUi; +//! # use utoipa::OpenApi; +//! #[rocket::launch] +//! fn rocket() -> Rocket { +//! # +//! # #[derive(OpenApi)] +//! # #[openapi()] +//! # struct ApiDoc; +//! # +//! rocket::build() +//! .mount( +//! "/", +//! SwaggerUi::new("/swagger-ui/<_..>").url("/api-doc/openapi.json", ApiDoc::openapi()), +//! ) +//! } +//! ``` +//! //! [^actix]: **actix-web** feature need to be enabled. +//! +//! [^rocket]: **rocket** feature need to be enabled. use std::{borrow::Cow, error::Error, io::Cursor, sync::Arc}; #[cfg(feature = "actix-web")] use actix_web::{ - dev::HttpServiceFactory, guard::Get, web, web::Data, HttpResponse, Resource, Responder, + dev::HttpServiceFactory, guard::Get, web, web::Data, HttpResponse, Resource, + Responder as ActixResponder, }; #[cfg(feature = "rocket")] @@ -69,11 +96,11 @@ use rocket::{ http::{Header, Status}, response::{ status::{self, NotFound}, - Responder, + Responder as RocketResponder, }, route::{Handler, Outcome}, serde::json::Json, - Data, Request, Response, Route, + Data as RocketData, Request, Response, Route, }; use rust_embed::RustEmbed; @@ -211,7 +238,7 @@ impl HttpServiceFactory for SwaggerUi { #[cfg(feature = "actix-web")] fn register_api_doc_url_resource(url: &str, api: OpenApi, config: &mut actix_web::dev::AppService) { - pub async fn get_api_doc(api_doc: web::Data) -> impl Responder { + pub async fn get_api_doc(api_doc: web::Data) -> impl ActixResponder { HttpResponse::Ok().json(api_doc.as_ref()) } @@ -255,7 +282,7 @@ struct ServeApiDoc(utoipa::openapi::OpenApi); #[cfg(feature = "rocket")] #[rocket::async_trait] impl Handler for ServeApiDoc { - async fn handle<'r>(&self, request: &'r Request<'_>, _: Data<'r>) -> Outcome<'r> { + async fn handle<'r>(&self, request: &'r Request<'_>, _: RocketData<'r>) -> Outcome<'r> { Outcome::from(request, Json(self.0.clone())) } } @@ -267,7 +294,7 @@ struct ServeSwagger(Cow<'static, str>, Arc>); #[cfg(feature = "rocket")] #[rocket::async_trait] impl Handler for ServeSwagger { - async fn handle<'r>(&self, request: &'r Request<'_>, _: Data<'r>) -> Outcome<'r> { + async fn handle<'r>(&self, request: &'r Request<'_>, _: RocketData<'r>) -> Outcome<'r> { let mut path = self.0.as_ref(); if let Some(index) = self.0.find('<') { path = &path[..index]; @@ -286,7 +313,7 @@ impl Handler for ServeSwagger { } #[cfg(feature = "rocket")] -impl<'r, 'o: 'r> Responder<'r, 'o> for SwaggerFile<'o> { +impl<'r, 'o: 'r> RocketResponder<'r, 'o> for SwaggerFile<'o> { fn respond_to(self, _: &'r Request<'_>) -> rocket::response::Result<'o> { rocket::response::Result::Ok( Response::build()