Skip to content

Commit

Permalink
open api and swagger-ui support
Browse files Browse the repository at this point in the history
  • Loading branch information
rdcm committed Oct 14, 2023
1 parent 1e07c94 commit 3986ab8
Show file tree
Hide file tree
Showing 8 changed files with 65 additions and 14 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Web api application prototype written in rust
- Crud api endpoints with actix-web and mongodb driver
- Integration tests
- Workspaces usage
- OpenApi and Swagger-UI
- Code coverage report
- Static analysis report

Expand Down
3 changes: 2 additions & 1 deletion app/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ edition = "2021"
actix-web = "4.4.0"
serde = "1.0.188"
serde_derive = "1.0.188"
domain = { path = "../domain" }
domain = { path = "../domain" }
utoipa = { version = "4", features = ["actix_extras"] }
33 changes: 28 additions & 5 deletions app/src/endpoints.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,21 @@
use crate::models::{CreateUserRequest, CreatedUserIdResponse, UserResponse};
use crate::models::{CreateUserRequest, CreatedUserIdResponse, ErrorResponse, UserResponse};
use actix_web::web::{Data, Json, Path};
use actix_web::HttpResponse;
use actix_web::{get, post, HttpResponse};
use domain::commands::{CreateUserCommand, ICommandHandler};
use domain::queries::{GetUserQuery, IQueryHandler, User};

/// Get user
///
/// Get user by id
#[utoipa::path(
get,
path = "/user/{user_id}",
responses(
(status = 200, description = "User created successfully", body = UserResponse),
(status = 400, description = "Something going wrong", body = ErrorResponse)
)
)]
#[get("/user/{user_id}")]
pub async fn get_user(
handler: Data<dyn IQueryHandler<GetUserQuery, Option<User>>>,
path: Path<String>,
Expand All @@ -20,10 +32,21 @@ pub async fn get_user(
age: user.age,
id: path.to_string(),
}),
None => HttpResponse::NotFound().body(format!("No user found with id {}", path)),
None => HttpResponse::BadRequest().json(ErrorResponse { code: 101 }),
}
}

/// Create user
///
/// Create user
#[utoipa::path(
request_body = CreateUserRequest,
responses(
(status = 201, description = "User created successfully", body = CreatedUserIdResponse),
(status = 400, description = "Something going wrong", body = ErrorResponse)
)
)]
#[post("/user")]
pub async fn create_user(
handler: Data<dyn ICommandHandler<CreateUserCommand, Option<String>>>,
request: Json<CreateUserRequest>,
Expand All @@ -36,7 +59,7 @@ pub async fn create_user(
let option = handler.handle(command).await;

match option {
Some(id) => HttpResponse::Ok().json(CreatedUserIdResponse { id }),
None => HttpResponse::BadRequest().body(()),
Some(id) => HttpResponse::Created().json(CreatedUserIdResponse { id }),
None => HttpResponse::BadRequest().json(ErrorResponse { code: 102 }),
}
}
12 changes: 9 additions & 3 deletions app/src/models.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
use serde_derive::{Deserialize, Serialize};
use utoipa::ToSchema;

#[derive(Serialize, Deserialize)]
#[derive(Serialize, Deserialize, ToSchema)]
pub struct CreateUserRequest {
pub name: String,
pub age: u8,
}

#[derive(Serialize, Deserialize)]
#[derive(Serialize, Deserialize, ToSchema)]
pub struct CreatedUserIdResponse {
pub id: String,
}

#[derive(Serialize, Deserialize)]
#[derive(Serialize, Deserialize, ToSchema)]
pub struct UserResponse {
pub name: String,
pub age: u8,
pub id: String,
}

#[derive(Serialize, Deserialize, ToSchema)]
pub struct ErrorResponse {
pub code: i32,
}
2 changes: 2 additions & 0 deletions host/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ mongodb = "2.7.0"
serde = "1.0.188"
serde_derive = "1.0.188"
async-trait = "0.1.73"
utoipa = { version = "4", features = ["actix_extras"] }
utoipa-swagger-ui = { version = "4", features = ["actix-web"] }

app = { path = "../app" }
domain = { path = "../domain" }
Expand Down
25 changes: 21 additions & 4 deletions host/src/factory.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,36 @@
use actix_web::dev::Server;
use actix_web::web::{get, post, Data};
use actix_web::web::Data;
use actix_web::{App, HttpServer};
use mongodb::{Client, Collection};
use std::net::SocketAddr;
use std::sync::Arc;
use utoipa::OpenApi;
use utoipa_swagger_ui::SwaggerUi;

use app::endpoints::{create_user, get_user};
use app::models::*;
use domain::commands::{CreateUserCommand, ICommandHandler};
use domain::queries::{GetUserQuery, IQueryHandler, User};
use domain_impl::handlers::{CreateUserCommandHandler, GetUserQueryHandler};
use infra::repositories::UserRepository;

#[derive(OpenApi)]
#[openapi(
paths(app::endpoints::create_user, app::endpoints::get_user),
components(
schemas(CreateUserRequest, CreatedUserIdResponse, ErrorResponse),
schemas(UserResponse, ErrorResponse)
)
)]
struct ApiDoc;

pub struct ServerInfo {
pub server: Server,
pub addrs: Vec<SocketAddr>,
}

pub async fn create_server(port: i32) -> Result<ServerInfo, std::io::Error> {
let user_repository_arc = Arc::new(create_user_repository().await);

let command_handler: Arc<dyn ICommandHandler<CreateUserCommand, Option<String>>> =
Arc::new(CreateUserCommandHandler {
repo: user_repository_arc.clone(),
Expand All @@ -28,12 +40,17 @@ pub async fn create_server(port: i32) -> Result<ServerInfo, std::io::Error> {
repo: user_repository_arc.clone(),
});

let openapi = ApiDoc::openapi();

let http_server = HttpServer::new(move || {
App::new()
.service(
SwaggerUi::new("/swagger-ui/{_:.*}").url("/api-docs/openapi.json", openapi.clone()),
)
.service(create_user)
.service(get_user)
.app_data(Data::from(command_handler.clone()))
.app_data(Data::from(query_handler.clone()))
.route("/user/{user_id}", get().to(get_user))
.route("/user", post().to(create_user))
})
.bind(format!("127.0.0.1:{}", port))
.expect("Failed to bind to the server.");
Expand Down
1 change: 1 addition & 0 deletions host/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use host::factory::create_server;
#[actix_web::main]
async fn main() -> std::io::Result<()> {
std::env::set_var("RUST_LOG", "debug");

env_logger::init();
create_server(8080).await.unwrap().server.await
}
2 changes: 1 addition & 1 deletion integrtion-tests/tests/sut.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ impl Sut {
.await
.unwrap();

if response.status() == StatusCode::OK {
if response.status() == StatusCode::CREATED {
let user: CreatedUserIdResponse = response.json().await.unwrap();

Ok(user)
Expand Down

0 comments on commit 3986ab8

Please sign in to comment.