Swaggerλ REST APIμ λ¬Έμνλ₯Ό μλννμ¬ νλ‘ νΈμλμ λ°±μλ κ°λ° κ°μ νμ μ ν¨μ¨μ μΌλ‘ μ§μνλ λꡬμ λλ€. Swaggerμ μ¬μ©κ³Ό κ·Έ μ΄μ μ λ¨κ³λ³λ‘ μ€λͺ νκ² μ΅λλ€.
π― μ΄μ²λΌ μν μ΄ λΆλ¦¬λλ©΄ λ°±μλ κ°λ°μκ° μ 곡νλ APIλ₯Ό νλ‘ νΈμλ κ°λ°μκ° μ°Έκ³ νμ¬ νλ©΄μ νμν λ°μ΄ν°λ₯Ό κ°μ ΈμμΌ ν©λλ€.
νλ‘ νΈμλ κ°λ°μλ λ°±μλμμ μ 곡νλ APIμ μμ‘΄ν΄ λ°μ΄ν°λ₯Ό μ²λ¦¬ν©λλ€. API λ¬Έμκ° μλ€λ©΄ μμ²ν΄μΌ ν URL, νλΌλ―Έν°, μλ΅ νμ λ±μ μκΈ° μ΄λ ΅κΈ° λλ¬Έμ API λ¬Έμκ° νμμ μ λλ€.
μμ: μ¬μ©μ μ 보λ₯Ό 보μ¬μ£Όλ νλ©΄μ ꡬνν λ, νλ‘ νΈμλ κ°λ°μλ μ¬μ©μ λ°μ΄ν°λ₯Ό μ»κΈ° μν APIμ μλν¬μΈνΈ URL, μμ² λ°©μ, μλ΅ νμ λ±μ μκ³ μμ΄μΌ ν©λλ€.
κ°λ° μ€μλ APIκ° μμ£Ό λ³κ²½λ©λλ€. μλ‘μ΄ κΈ°λ₯ μΆκ°, κΈ°μ‘΄ κΈ°λ₯ μμ , μμΈ μ²λ¦¬ μΆκ° λ±μ μ΄μ λ‘ APIκ° μ λ°μ΄νΈλ λλ§λ€ λ¬Έμ λν μ΅μ μΌλ‘ μ μ§ν΄μΌ ν©λλ€.
Swaggerλ APIλ₯Ό μλμΌλ‘ λ¬Έμνν΄μ£Όλ λꡬλ‘, API λ³κ²½ μ¬νμ μλ λ°μνμ¬ νλ‘ νΈμλμ λ°±μλ κ° νμ μ ν¬κ² ν₯μμν΅λλ€.
π ν¨μ¨μ± μ¦κ°: Swaggerλ API λ³κ²½ μ¬νμ 체κ³μ μΌλ‘ κ΄λ¦¬ν μ μμ΄, μλ λ¬Έμνλ‘ μΈν μ€λ₯λ₯Ό μ€μ΄κ³ , μ μ§λ³΄μλ₯Ό κ°νΈνκ² ν©λλ€.
Swaggerλ API λ¬Έμνλ₯Ό μλννκ³ , κ°λ°μλ€μ΄ APIμ λ μ½κ² μνΈμμ©ν μ μλλ‘ λλ κ°λ ₯ν λꡬμ λλ€. κ° κΈ°λ₯κ³Ό μ₯μ μ μλμ κ°μ΄ μ€λͺ νκ² μ΅λλ€.
π― ν¨κ³Ό: Swaggerλ₯Ό ν΅ν΄ APIμ λν μ λ³΄κ° μ½κ² μ 곡λμ΄, λͺ¨λ κ°λ°μλ€μ΄ κ°νΈνκ² API λͺ©λ‘μ νμΈνκ³ κ° APIμ μΈλΆ μ¬νμ λͺ νν μ μ μμ΅λλ€.
π ν¨κ³Ό: νλ‘μ νΈ λ΄μμ μ΄λ€ APIκ° μ΄λ€ κ²½λ‘μμ νΈμΆλλμ§ μ§κ΄μ μΌλ‘ μ΄ν΄ν μ μμ΄, κ°λ°μ κ°μ νμ μ΄ μμν΄μ§λλ€.
π ν¨κ³Ό: κ°λ°μλ€μ΄ κ° APIμ λμκ³Ό νλΌλ―Έν°λ₯Ό μ½κ² μ΄ν΄ν μ μμΌλ©°, API μ¬μ© μ€ λ°μν μ μλ νΌλκ³Ό μ€μλ₯Ό λ°©μ§ν μ μμ΅λλ€.
π ν¨κ³Ό: κ°λ° μ΄κΈ° λ¨κ³μ μ μ§λ³΄μ λ¨κ³μμ APIμ μ μ μλ μ¬λΆλ₯Ό μ¦μ νμΈν μ μμ΄, λλ²κΉ κ³Ό μ€λ₯ μμ μ΄ μ©μ΄ν΄μ§λλ€.
springdoc-openapi
λ Spring Boot νκ²½μμ Swagger μ€μ μ κ°λ¨ν μΆκ°ν μ μμ΄, Spring κΈ°λ°μ νλ‘μ νΈμ Swagger UI κΈ°λ₯μ μ½κ² λμ
ν μ μμ΅λλ€.SwaggerConfiguration.java
νμΌ μ€μ @Configuration
μ΄λ
Έν
μ΄μ
μ΄ λΆμ΄ μμ΅λλ€. μ΄ ν΄λμ€λ Springμμ μ€μ ν΄λμ€λ‘ μΈμλλ©°, Swagger κ΄λ ¨ μ€μ μ΄ μ μ©λ©λλ€.@Bean
μ΄λ
Έν
μ΄μ
μ ν΅ν΄ openAPI()
λ©μλκ° μ μλμ΄ μμ΅λλ€. μ΄ λ©μλλ OpenAPIμ κΈ°λ³Έ μ 보λ₯Ό μ€μ ν©λλ€.Info info
κ°μ²΄λ₯Ό μμ±νμ¬ APIμ νμ΄ν, μ€λͺ
, λ²μ , μ°λ½μ² μ 보 λ±μ μ€μ ν©λλ€.title("Project API λͺ
μΈμ")
: APIμ μ΄λ¦μ λνλ΄λ©°, νλ‘μ νΈ λͺ
μΈμλΌλ μλ―Έμ
λλ€.description
: Swagger UIμ νμλ μΆκ° μ 보λ‘, HTML νκ·Έλ₯Ό ν¬ν¨ν΄ λ‘κ³ μ μλ΄ ν
μ€νΈλ₯Ό μΆκ°ν©λλ€.contact
: API λ΄λΉμ μ΄λ¦, μ΄λ©μΌ, URLμ μ€μ νμ¬ μ°κ΄λ μ 보λ νμν©λλ€.return
: μ€μ λ info
κ°μ²΄κ° ν¬ν¨λ OpenAPI μΈμ€ν΄μ€λ₯Ό λ°ννμ¬ Swagger UIμ νμλ©λλ€.@Configuration
public class SwaggerConfiguration {
@Bean
public OpenAPI openAPI() {
Info info = new Info()
.title("Project API λͺ
μΈμ")
.description("<img src='https://example.com/logo.png' style='width: 50px;'/> API λͺ
μΈμμ
λλ€. ")
.version("v1.0.0")
.contact(new Contact().name("κ°λ°ν").email("devteam@example.com").url("https://example.com"));
return new OpenAPI().info(info);
}
}
publicApi()
λ©μλλ GroupedOpenApi
λ₯Ό ν΅ν΄ κ΄λ¦¬μμ© API κ·Έλ£Ήμ λ§λλλ€.group("admin-api")
: μ΄ API κ·Έλ£Ήμ μ΄λ¦μ "admin-api"
λ‘ μ€μ νμ¬, Swagger UIμμ κ΄λ¦¬μμ© APIλ₯Ό μ½κ² ꡬλΆν μ μλλ‘ ν©λλ€.pathsToMatch("/admin/**")
: /admin/
λ‘ μμνλ κ²½λ‘λ§ μ΄ κ·Έλ£Ήμ ν¬ν¨μμΌ κ΄λ¦¬μκ° μ¬μ©νλ μλν¬μΈνΈλ€λ§ νμλ©λλ€.@Bean
public GroupedOpenApi publicApi() {
return GroupedOpenApi.builder()
.group("admin-api")
.pathsToMatch("/admin/**")
.build();
}
userApi()
λ©μλλ μ¬μ©μμ© GroupedOpenApi
λ₯Ό μμ±ν©λλ€.group("user-api")
: μ΄ API κ·Έλ£Ήμ μ΄λ¦μ "user-api"
λ‘ μ€μ νμ¬ μΌλ° μ¬μ©μκ° λ³Ό μ μλ API κ·Έλ£Ήμ νμν©λλ€.pathsToMatch("/user/**")
: /user/
λ‘ μμνλ κ²½λ‘λ§ μ΄ κ·Έλ£Ήμ ν¬ν¨λμ΄ μ¬μ©μμ© μλν¬μΈνΈλ€λ§ νμλ©λλ€.@Bean
public GroupedOpenApi userApi() {
return GroupedOpenApi.builder()
.group("user-api")
.pathsToMatch("/user/**")
.build();
}
AdminUserController
ν΄λμ€@RestController
@RequestMapping("/admin")
@CrossOrigin("*")
@Tag(name = "μ΄λλ―Ό 컨νΈλ‘€λ¬", description = "νμ λͺ©λ‘κ³Ό μμΈλ³΄κΈ°, λ±λ‘, μμ , μμ λ± μ λ°μ μΈ νμ κ΄λ¦¬λ₯Ό μ²λ¦¬νλ ν΄λμ€")
public class AdminUserController {
private static final Logger logger = LoggerFactory.getLogger(AdminUserController.class);
private MemberService memberService;
public AdminUserController(MemberService memberService) {
this.memberService = memberService;
}
@RestController
@RequestMapping("/admin")
/admin
μΌλ‘ μ€μ ν©λλ€. μ΄ ν΄λμ€μ μ μλ λͺ¨λ λ©μλλ /admin
μ ν¬ν¨ν URLμμ νΈμΆλ©λλ€.@CrossOrigin("*")
@Tag
μ΄λ
Έν
μ΄μ
@Tag(name = "μ΄λλ―Ό 컨νΈλ‘€λ¬", description = "νμ λͺ©λ‘κ³Ό μμΈλ³΄κΈ°, λ±λ‘, μμ , μμ λ± μ λ°μ μΈ νμ κ΄λ¦¬λ₯Ό μ²λ¦¬νλ ν΄λμ€")
name
: Swagger UIμμ 컨νΈλ‘€λ¬μ μ΄λ¦μ νμν©λλ€.description
: νμ κ΄λ¦¬ κΈ°λ₯μ λν μ€λͺ
μ μΆκ°νμ¬, ν΄λΉ 컨νΈλ‘€λ¬κ° μ΄λ€ μν μ μννλμ§ μ€λͺ
ν©λλ€. @Operation(summary = "νμλͺ©λ‘", description = "νμμ <big>μ 체 λͺ©λ‘</big>μ λ°νν΄ μ€λλ€.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "νμλͺ©λ‘ OK!!"),
@ApiResponse(responseCode = "404", description = "νμ΄μ§μμ΄!!"),
@ApiResponse(responseCode = "500", description = "μλ²μλ¬!!")
})
@GetMapping(value = "/user")
public ResponseEntity<?> userList() {
return ResponseEntity.ok("νμλͺ©λ‘ λ¦¬ν΄ call");
}
}
@Operation
μ΄λ
Έν
μ΄μ
summary
: API μλν¬μΈνΈμ κ°λ¨ν μμ½μ μ 곡ν©λλ€. μ¬κΈ°μλ "νμλͺ©λ‘"
μΌλ‘ μ€μ λμ΄ μμ΄, μ΄ APIκ° νμ λͺ©λ‘μ μ 곡νλ κΈ°λ₯μμ λνλ
λλ€.description
: APIμ μμΈ μ€λͺ
μ μ 곡ν©λλ€. μ΄ μ€λͺ
μ Swagger UIμμ λ μμΈν μ 보λ₯Ό μ 곡νλ©°, HTML νκ·Έλ₯Ό μ¬μ©νμ¬ ν
μ€νΈλ₯Ό κ°μ‘°ν μλ μμ΅λλ€.@ApiResponses
μ΄λ
Έν
μ΄μ
@ApiResponse
λ₯Ό ν¬ν¨νμ¬ APIμ λ€μν μλ΅ μ½λμ κ·Έ μ€λͺ
μ μ μν©λλ€.@ApiResponse
μ΄λ
Έν
μ΄μ
responseCode
: HTTP μλ΅ μ½λλ₯Ό μ§μ ν©λλ€.description
: μλ΅ μ½λμ λν μ€λͺ
μ μ 곡ν©λλ€.200
: μμ²μ΄ μ±κ³΅νμ λμ λ©μμ§ "νμλͺ©λ‘ OK!!"
.404
: 리μμ€λ₯Ό μ°Ύμ§ λͺ»νμ λμ λ©μμ§ "νμ΄μ§μμ΄!!"
.500
: μλ² λ΄λΆ μ€λ₯κ° λ°μνμ λμ λ©μμ§ "μλ²μλ¬!!"
.@GetMapping(value = "/user")
/admin/user
κ²½λ‘λ‘ νΈμΆλ©λλ€. μ΄ λ©μλλ νμ λͺ©λ‘μ λ°ννλ κΈ°λ₯μ λ΄λΉν©λλ€.userList
λ©μλResponseEntity.ok("νμλͺ©λ‘ λ¦¬ν΄ call")
μ λ°ννμ¬, νμ λͺ©λ‘μ λ°ννλ APIμ μμ μλ΅μ λνλ
λλ€. μ€μ κ°λ° νκ²½μμλ λ°μ΄ν°λ² μ΄μ€μμ νμ λͺ©λ‘μ κ°μ Έμ λ°νν κ²μ
λλ€.@Schema
μ΄λ
Έν
μ΄μ
μ μ© (MemberDto
ν΄λμ€)@Schema(title = "MemberDto (νμμ 보)", description = "νμμ μμ΄λ, λΉλ², μ΄λ¦μ κ°μ§ Domain Class")
public class MemberDto {
@Schema
μ΄λ
Έν
μ΄μ
(ν΄λμ€ μμ€)"MemberDto (νμμ 보)"
λ‘ μ€μ νμ¬ μ΄ ν΄λμ€κ° νμ μ 보λ₯Ό λ€λ£¨λ DTOμμ λͺ
νν ν©λλ€."νμμ μμ΄λ, λΉλ², μ΄λ¦μ κ°μ§ Domain Class"
λΌλ μ€λͺ
μ΄ λνλ©λλ€. μ΄λ₯Ό ν΅ν΄ μ΄ DTOκ° νμ κ΄λ ¨ λ°μ΄ν°λ₯Ό λ΄κ³ μμμ μ§κ΄μ μΌλ‘ μ μ μμ΅λλ€.@Schema
μ΄λ
Έν
μ΄μ
(νλ μμ€) κ° νλλ³ μ€λͺ
@Schema(description = "νμμμ΄λ", requiredMode = Schema.RequiredMode.REQUIRED, example = "hissam")
private String userId;
"νμμμ΄λ"
λ₯Ό λͺ
μνμ¬, Swagger UIμμ μ΄ νλκ° νμμ μμ΄λμμ λνλ
λλ€.Schema.RequiredMode.REQUIRED
λ₯Ό μ¬μ©νμ¬, API μμ² μ λ°λμ ν¬ν¨λμ΄μΌ νλ κ°μμ λνλ
λλ€."hissam"
μ μΆκ°νμ¬, Swagger UIμμ API ν
μ€νΈ μ μ°Έμ‘°ν μ μλ μν κ°μ μ 곡ν©λλ€. @Schema(description = "νμμ΄λ¦", example = "νκΈΈλ")
private String userName;
"νμμ΄λ¦"
μΌλ‘ νλμ λν μ€λͺ
μ μΆκ°νμ¬ μ΄ νλκ° μ¬μ©μμ μ΄λ¦μ λ΄κ³ μμμ λͺ
μν©λλ€."νκΈΈλ"
μ΄λΌλ μμ κ°μ μ 곡νμ¬ Swagger UIμμ API ν
μ€νΈ μ μ°Έκ³ ν μ μμ΅λλ€. @Schema(description = "νμλΉλ°λ²νΈ")
private String userPwd;
"νμλΉλ°λ²νΈ"
λΌλ μ€λͺ
μ μΆκ°νμ¬, μ΄ νλκ° μ¬μ©μμ λΉλ°λ²νΈλ₯Ό λ΄λ νλμμ λͺ
νν ν©λλ€. @Schema(description = "μ΄λ©μΌμμ΄λ")
private String emailId;
@Schema(description = "μ΄λ©μΌλλ©μΈ", defaultValue = "ssafy.com", example = "google.com")
private String emailDomain;
emailId
νλλ "μ΄λ©μΌμμ΄λ"λ‘ μ€λͺ
λ©λλ€.emailDomain
νλλ "μ΄λ©μΌλλ©μΈ"μΌλ‘ μ€λͺ
λλ©°, μΆκ°μ μΌλ‘ κΈ°λ³Έ κ°κ³Ό μμ κ°μ μ 곡ν©λλ€."ssafy.com"
μΌλ‘ μ€μ νμ¬, κ°μ΄ μ§μ λμ§ μμμ λ κΈ°λ³Έμ μΌλ‘ μ΄ κ°μ μ¬μ©νκ² λ©λλ€."google.com"
μ΄λΌλ μμ κ°μ μ€μ νμ¬ Swagger λ¬Έμμμ μ΄ νλλ₯Ό ν
μ€νΈν λ μ°Έκ³ ν μ μμ΅λλ€. @Schema(description = "κ°μ
μΌ", defaultValue = "νμ¬μκ°")
private String joinDate;
}