diff --git a/user-service/build.gradle b/user-service/build.gradle index b71a6b07..76cda7f2 100644 --- a/user-service/build.gradle +++ b/user-service/build.gradle @@ -2,6 +2,7 @@ plugins { id 'java' id 'org.springframework.boot' version '3.2.3' id 'io.spring.dependency-management' version '1.1.4' + id "org.springdoc.openapi-gradle-plugin" version '1.8.0' } group = 'com.waither' @@ -76,8 +77,8 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' // Swagger - implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.0.4' - implementation 'org.springdoc:springdoc-openapi-starter-webmvc-api:2.0.4' + implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.1.0' + implementation 'org.springdoc:springdoc-openapi-starter-webmvc-api:2.1.0' } @@ -88,6 +89,17 @@ dependencyManagement { } } +openApi { + apiDocsUrl.set("http://localhost:3000") // Document URL + outputDir.set(file("$rootDir/docs")) // Build Result Path + outputFileName.set("user.json") // Build Result File Name + groupedApiMappings.set(Map.of("http://localhost:8080/user/api-docs", "user.json")) + waitTimeInSeconds.set(60) // Timeout + customBootRun { + args.add("--spring.profiles.active=dev") + } +} + tasks.named('test') { useJUnitPlatform() } diff --git a/user-service/docs/user.json b/user-service/docs/user.json new file mode 100644 index 00000000..d34cbbf2 --- /dev/null +++ b/user-service/docs/user.json @@ -0,0 +1,1160 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "OpenAPI definition", + "version": "v0" + }, + "servers": [ + { + "url": "http://localhost:8080", + "description": "Generated server url" + } + ], + "paths": { + "/survey/submit": { + "post": { + "tags": [ + "survey-controller" + ], + "operationId": "createSurvey", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SurveyRequestDto" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/ApiResponseString" + } + } + } + } + } + } + }, + "/signup": { + "post": { + "tags": [ + "user-controller" + ], + "summary": "Sign Up", + "description": "회원가입", + "operationId": "register", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SignUpRequestDto" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/ApiResponseString" + } + } + } + } + } + } + }, + "/password-check": { + "post": { + "tags": [ + "user-controller" + ], + "operationId": "passwordCheckEmail", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PasswordCheckDto" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/ApiResponseString" + } + } + } + } + } + } + }, + "/emails/verifications": { + "post": { + "tags": [ + "user-controller" + ], + "operationId": "verificationEmail", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmailVerificationDto" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/ApiResponseString" + } + } + } + } + } + } + }, + "/update-password": { + "patch": { + "tags": [ + "user-controller" + ], + "operationId": "updatePassword", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdatePasswordDto" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/ApiResponseString" + } + } + } + } + } + } + }, + "/update-nickname": { + "patch": { + "tags": [ + "user-controller" + ], + "operationId": "updateNickname", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NicknameDto" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/ApiResponseString" + } + } + } + } + } + } + }, + "/setting/user-weight": { + "get": { + "tags": [ + "setting-controller" + ], + "operationId": "getWeight", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/ApiResponseWeightDto" + } + } + } + } + } + }, + "patch": { + "tags": [ + "setting-controller" + ], + "operationId": "updateWeight", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WeightDto" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/ApiResponseString" + } + } + } + } + } + } + }, + "/setting/region": { + "get": { + "tags": [ + "setting-controller" + ], + "operationId": "getRegion", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/ApiResponseRegionNameDto" + } + } + } + } + } + }, + "patch": { + "tags": [ + "setting-controller" + ], + "operationId": "updateRegion", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RegionDto" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/ApiResponseString" + } + } + } + } + } + } + }, + "/setting/region-report": { + "patch": { + "tags": [ + "setting-controller" + ], + "operationId": "updateRegionReport", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RegionReportDto" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/ApiResponseString" + } + } + } + } + } + } + }, + "/setting/noti/wind": { + "get": { + "tags": [ + "setting-controller" + ], + "operationId": "getWind", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/ApiResponseWindDto" + } + } + } + } + } + }, + "patch": { + "tags": [ + "setting-controller" + ], + "operationId": "updateWind", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WindDto" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/ApiResponseString" + } + } + } + } + } + } + }, + "/setting/noti/user-alert": { + "patch": { + "tags": [ + "setting-controller" + ], + "operationId": "updateUserAlert", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserAlertDto" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/ApiResponseString" + } + } + } + } + } + } + }, + "/setting/noti/snow-alert": { + "patch": { + "tags": [ + "setting-controller" + ], + "operationId": "updateSnowAlert", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SnowAlertDto" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/ApiResponseString" + } + } + } + } + } + } + }, + "/setting/noti/out-alert": { + "patch": { + "tags": [ + "setting-controller" + ], + "operationId": "updateOutAlert", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OutAlertDto" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/ApiResponseString" + } + } + } + } + } + } + }, + "/setting/noti/out-alert-set": { + "patch": { + "tags": [ + "setting-controller" + ], + "operationId": "updateOutAlertSet", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OutAlertSetDto" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/ApiResponseString" + } + } + } + } + } + } + }, + "/setting/noti/climate-alert": { + "patch": { + "tags": [ + "setting-controller" + ], + "operationId": "updateClimateAlert", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ClimateAlertDto" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/ApiResponseString" + } + } + } + } + } + } + }, + "/setting/display": { + "get": { + "tags": [ + "setting-controller" + ], + "operationId": "getDisplay", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/ApiResponseDisplayDto" + } + } + } + } + } + }, + "patch": { + "tags": [ + "setting-controller" + ], + "operationId": "updateDisplay", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DisplayDto" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/ApiResponseString" + } + } + } + } + } + } + }, + "/setting/custom": { + "get": { + "tags": [ + "setting-controller" + ], + "operationId": "getUserCustom", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/ApiResponseCustomDto" + } + } + } + } + } + }, + "patch": { + "tags": [ + "setting-controller" + ], + "operationId": "updateCustom", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomDto" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/ApiResponseString" + } + } + } + } + } + } + }, + "/setting/noti": { + "get": { + "tags": [ + "setting-controller" + ], + "operationId": "getNotification", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/ApiResponseNotificationDto" + } + } + } + } + } + } + }, + "/setting/mypage": { + "get": { + "tags": [ + "setting-controller" + ], + "operationId": "getUserInfo", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/ApiResponseUserInfoDto" + } + } + } + } + } + } + }, + "/reissue": { + "get": { + "tags": [ + "user-controller" + ], + "operationId": "reissueToken", + "parameters": [ + { + "name": "RefreshToken", + "in": "header", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/ApiResponseJwtDto" + } + } + } + } + } + } + }, + "/emails/temporary-password": { + "get": { + "tags": [ + "user-controller" + ], + "operationId": "submitTemporaryPassword", + "parameters": [ + { + "name": "email", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/ApiResponseString" + } + } + } + } + } + } + }, + "/emails/submit-authcode": { + "get": { + "tags": [ + "user-controller" + ], + "operationId": "submitAuthCode", + "parameters": [ + { + "name": "email", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/ApiResponseString" + } + } + } + } + } + } + }, + "/delete": { + "delete": { + "tags": [ + "user-controller" + ], + "operationId": "deleteUser", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/ApiResponseString" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "SurveyRequestDto": { + "type": "object", + "properties": { + "ans": { + "type": "integer", + "format": "int32" + }, + "time": { + "type": "string", + "format": "date-time" + } + } + }, + "ApiResponseString": { + "type": "object", + "properties": { + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "type": "string" + } + } + }, + "SignUpRequestDto": { + "required": [ + "email", + "password" + ], + "type": "object", + "properties": { + "email": { + "pattern": "^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+.[A-Za-z]{2,6}$", + "type": "string" + }, + "password": { + "maxLength": 2147483647, + "minLength": 8, + "pattern": "^(?\u003d.*[a-z])(?\u003d.*\\d)(?\u003d.*[!@#$%^\u0026*]).{8,64}$", + "type": "string" + } + } + }, + "PasswordCheckDto": { + "type": "object", + "properties": { + "password": { + "type": "string" + } + } + }, + "EmailVerificationDto": { + "type": "object", + "properties": { + "email": { + "type": "string" + }, + "authCode": { + "type": "string" + } + } + }, + "UpdatePasswordDto": { + "required": [ + "password" + ], + "type": "object", + "properties": { + "password": { + "maxLength": 2147483647, + "minLength": 8, + "pattern": "^(?\u003d.*[a-z])(?\u003d.*\\d)(?\u003d.*[!@#$%^\u0026*]).{8,64}$", + "type": "string" + } + } + }, + "NicknameDto": { + "type": "object", + "properties": { + "nickname": { + "type": "string" + } + } + }, + "WeightDto": { + "type": "object", + "properties": { + "weight": { + "type": "number", + "format": "double" + } + } + }, + "RegionDto": { + "type": "object", + "properties": { + "regionName": { + "type": "string" + }, + "longitude": { + "type": "number", + "format": "double" + }, + "latitude": { + "type": "number", + "format": "double" + } + } + }, + "RegionReportDto": { + "type": "object", + "properties": { + "regionReport": { + "type": "boolean" + } + } + }, + "WindDto": { + "type": "object", + "properties": { + "windAlert": { + "type": "boolean" + }, + "windDegree": { + "type": "integer", + "format": "int32" + } + } + }, + "UserAlertDto": { + "type": "object", + "properties": { + "userAlert": { + "type": "boolean" + } + } + }, + "SnowAlertDto": { + "type": "object", + "properties": { + "snowAlert": { + "type": "boolean" + } + } + }, + "OutAlertDto": { + "type": "object", + "properties": { + "outAlert": { + "type": "boolean" + } + } + }, + "LocalTime": { + "type": "object", + "properties": { + "hour": { + "type": "integer", + "format": "int32" + }, + "minute": { + "type": "integer", + "format": "int32" + }, + "second": { + "type": "integer", + "format": "int32" + }, + "nano": { + "type": "integer", + "format": "int32" + } + } + }, + "OutAlertSetDto": { + "type": "object", + "properties": { + "days": { + "type": "array", + "items": { + "type": "string" + } + }, + "outTime": { + "$ref": "#/components/schemas/LocalTime" + } + } + }, + "ClimateAlertDto": { + "type": "object", + "properties": { + "climateAlert": { + "type": "boolean" + } + } + }, + "DisplayDto": { + "type": "object", + "properties": { + "precipitation": { + "type": "boolean" + }, + "wind": { + "type": "boolean" + }, + "dust": { + "type": "boolean" + } + } + }, + "CustomDto": { + "type": "object", + "properties": { + "custom": { + "type": "boolean" + } + } + }, + "ApiResponseWeightDto": { + "type": "object", + "properties": { + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/WeightDto" + } + } + }, + "ApiResponseRegionNameDto": { + "type": "object", + "properties": { + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/RegionNameDto" + } + } + }, + "RegionNameDto": { + "type": "object", + "properties": { + "regionName": { + "type": "string" + } + } + }, + "ApiResponseNotificationDto": { + "type": "object", + "properties": { + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/NotificationDto" + } + } + }, + "NotificationDto": { + "type": "object", + "properties": { + "outAlert": { + "type": "boolean" + }, + "days": { + "type": "array", + "items": { + "type": "string" + } + }, + "outTime": { + "$ref": "#/components/schemas/LocalTime" + }, + "climateAlert": { + "type": "boolean" + }, + "userAlert": { + "type": "boolean" + }, + "snowAlert": { + "type": "boolean" + } + } + }, + "ApiResponseWindDto": { + "type": "object", + "properties": { + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/WindDto" + } + } + }, + "ApiResponseUserInfoDto": { + "type": "object", + "properties": { + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/UserInfoDto" + } + } + }, + "UserInfoDto": { + "type": "object", + "properties": { + "email": { + "type": "string" + }, + "nickname": { + "type": "string" + } + } + }, + "ApiResponseDisplayDto": { + "type": "object", + "properties": { + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/DisplayDto" + } + } + }, + "ApiResponseCustomDto": { + "type": "object", + "properties": { + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/CustomDto" + } + } + }, + "ApiResponseJwtDto": { + "type": "object", + "properties": { + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/JwtDto" + } + } + }, + "JwtDto": { + "type": "object", + "properties": { + "accessToken": { + "type": "string" + }, + "refreshToken": { + "type": "string" + } + } + } + } + } +} \ No newline at end of file diff --git a/user-service/src/main/java/com/waither/userservice/controller/UserController.java b/user-service/src/main/java/com/waither/userservice/controller/UserController.java index f1cde08f..cca7fa1b 100644 --- a/user-service/src/main/java/com/waither/userservice/controller/UserController.java +++ b/user-service/src/main/java/com/waither/userservice/controller/UserController.java @@ -6,6 +6,7 @@ import com.waither.userservice.jwt.dto.JwtDto; import com.waither.userservice.service.UserService; import com.waither.userservice.global.response.ApiResponse; +import io.swagger.v3.oas.annotations.Operation; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -22,6 +23,7 @@ public class UserController { private final UserService userService; // 회원가입 + @Operation(summary = "Sign Up", description = "회원가입") @PostMapping("/signup") public ResponseEntity> register(@Valid @RequestBody UserReqDto.SignUpRequestDto requestDto) { userService.signup(requestDto); @@ -38,7 +40,6 @@ public ResponseEntity> register(@Valid @RequestBody UserReqD public ApiResponse reissueToken(@RequestHeader("RefreshToken") String refreshToken) { JwtDto jwtDto = userService.reissueToken(refreshToken); return ApiResponse.onSuccess(jwtDto); - } // 이메일에 인증번호 보내기 diff --git a/user-service/src/main/resources/bootstrap.yml b/user-service/src/main/resources/bootstrap.yml index 2a00e97f..5a46d2f0 100644 --- a/user-service/src/main/resources/bootstrap.yml +++ b/user-service/src/main/resources/bootstrap.yml @@ -9,7 +9,7 @@ spring: cloud: config: uri: http://localhost:8888 - name: database-user,redis, jwt, smtp + name: database-user,redis, jwt, smtp, apiDocs-user kafka: bootstrap-servers: "localhost:9092" consumer: