Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#100] Request Body 스웨거 생성 구현 #114

Merged
merged 6 commits into from
Aug 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,5 @@ Cargo.lock
# Added by cargo

/target

test.json
1 change: 1 addition & 0 deletions rupring/src/example/domains/users/controller.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ pub fn get_user(
#[rupring::Post(path = /users)]
#[tags = [user]]
#[summary = "user 생성"]
#[RequestBody = crate::domains::users::dto::CreateUserRequest]
pub fn create_user(request: rupring::Request, _: rupring::Response) -> rupring::Response {
let user_service = request.get_provider::<Arc<dyn IUserService>>().unwrap();

Expand Down
14 changes: 13 additions & 1 deletion rupring/src/example/domains/users/dto.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,22 @@
use rupring_macro::RupringDoc;
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
pub mod foo {

use rupring_macro::RupringDoc;
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize, RupringDoc)]
pub struct Bar {}
}

#[derive(Debug, Serialize, Deserialize, RupringDoc)]
pub struct CreateUserRequest {
#[desc = "유저명"]
#[example = "foobar"]
pub username: String,
pub email: String,
pub password: String,
pub bar: foo::Bar,
}

#[derive(Debug, Serialize, Deserialize)]
Expand Down
5 changes: 5 additions & 0 deletions rupring/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,7 @@ pub use request::Request;
/// HTTP Response
pub use response::Response;
use swagger::json::SwaggerOperation;
use swagger::macros::SwaggerRequestBody;

/// Module interface
pub trait IModule {
Expand Down Expand Up @@ -566,6 +567,10 @@ pub trait IRoute {
fn swagger(&self) -> SwaggerOperation {
Default::default()
}

fn swagger_request_body(&self) -> Option<SwaggerRequestBody> {
None
}
}

/// Handler interface
Expand Down
36 changes: 34 additions & 2 deletions rupring/src/swagger/context.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
use std::sync::{Arc, RwLock};

use crate as rupring;
use crate::IModule;
use crate::{self as rupring};

use super::{
json::{SwaggerPath, SwaggerSchema},
SwaggerTags,
};
use super::{SwaggerParameter, SwaggerParameterCategory, SwaggerReference, SwaggerTypeOrReference};

#[derive(Debug, Clone, Default)]
pub struct SwaggerContext {
Expand Down Expand Up @@ -54,7 +55,38 @@ fn generate_swagger(swagger: &mut SwaggerSchema, root_module: Box<dyn crate::IMo
for route in controller.routes() {
let normalized_path = crate::boot::route::normalize_path(prefix.clone(), route.path());
let normalized_path = swaggerize_url(normalized_path.as_str());
let operation = route.swagger();
let mut operation = route.swagger();

if let Some(swagger_request_body) = route.swagger_request_body() {
operation.parameters.push(SwaggerParameter {
name: swagger_request_body
.definition_name
.split("::")
.last()
.unwrap_or("Request Body")
.to_string(),
in_: SwaggerParameterCategory::Body,
description: "Request Body".to_string(),
required: true,
schema: Some(SwaggerTypeOrReference::Reference(SwaggerReference {
reference: "#/definitions/".to_string()
+ swagger_request_body.definition_name.as_str(),
})),
type_: None,
});

swagger.definitions.insert(
swagger_request_body.definition_name.clone(),
swagger_request_body.definition_value,
);

for dependency in swagger_request_body.dependencies {
swagger.definitions.insert(
dependency.definition_name.clone(),
dependency.definition_value,
);
}
}

// TODO: 추후에는 swagger ignore 속성을 추가해서 그걸로 처리
match normalized_path.as_str() {
Expand Down
34 changes: 30 additions & 4 deletions rupring/src/swagger/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,7 @@ pub type SwaggerSecurity = HashMap<String, Vec<String>>;
pub type SwaggerSecurityDefinitions = HashMap<String, SwaggerSecurityDefinition>;

#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(untagged)]
pub enum SwaggerSecurityDefinition {
APIKey(SwaggerAPIKey),
Oauth2(SwaggerOauth2),
Expand Down Expand Up @@ -324,24 +325,31 @@ pub type SwaggerOauth2Scopes = HashMap<String, String>;

pub type SwaggerDefinitions = HashMap<String, SwaggerDefinition>;

pub type SwaggerDefinition = SwaggerDefinitionObject;

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct SwaggerDefinition {
pub struct SwaggerDefinitionObject {
#[serde(rename = "type")]
pub type_: String,

#[serde(rename = "properties")]
pub properties: SwaggerProperties,

#[serde(rename = "required")]
pub required: Vec<String>,
}

pub type SwaggerProperties = HashMap<String, SwaggerProperty>;

#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(untagged)]
pub enum SwaggerProperty {
Array(SwaggerArrayProperty),
Single(SwaggerSingleProperty),
Reference(SwaggerReferenceProperty),
}

#[derive(Serialize, Deserialize, Debug, Clone)]
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct SwaggerArrayProperty {
#[serde(rename = "type")]
pub type_: String,
Expand All @@ -353,7 +361,7 @@ pub struct SwaggerArrayProperty {
pub description: String,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct SwaggerSingleProperty {
#[serde(rename = "type")]
pub type_: String,
Expand All @@ -362,7 +370,16 @@ pub struct SwaggerSingleProperty {
pub description: String,

#[serde(rename = "example")]
pub example: Option<String>,
pub example: Option<String>, // TODO: Union으로 치환
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct SwaggerReferenceProperty {
#[serde(rename = "$ref")]
pub reference: String,

#[serde(rename = "description")]
pub description: String,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
Expand All @@ -372,7 +389,16 @@ pub struct SwaggerType {
}

#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(untagged)]
pub enum SwaggerTypeOrReference {
Type(SwaggerType),
Reference(SwaggerReference),
}

impl Default for SwaggerTypeOrReference {
fn default() -> Self {
SwaggerTypeOrReference::Type(SwaggerType {
type_: "".to_string(),
})
}
}
Loading
Loading