diff --git a/build.gradle.kts b/build.gradle.kts index 9de0cea..0f9d0d8 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -25,6 +25,9 @@ dependencies { implementation("org.jetbrains.kotlin:kotlin-reflect") implementation("com.fasterxml.jackson.module:jackson-module-kotlin") implementation("org.springframework.boot:spring-boot-starter-data-jpa") + implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0") + runtimeOnly("com.mysql:mysql-connector-j") + testImplementation("org.mockito:mockito-core:4.11.0") testImplementation("org.springframework.boot:spring-boot-starter-test") { exclude(module = "mockito-core") @@ -33,7 +36,6 @@ dependencies { testImplementation("com.ninja-squad:springmockk:4.0.2") testImplementation("org.jetbrains.kotlin:kotlin-test-junit5") testRuntimeOnly("org.junit.platform:junit-platform-launcher") - runtimeOnly("com.mysql:mysql-connector-j") } kotlin { diff --git a/src/main/kotlin/nexters/weski/common/config/SwaggerConfig.kt b/src/main/kotlin/nexters/weski/common/config/SwaggerConfig.kt new file mode 100644 index 0000000..bc865b4 --- /dev/null +++ b/src/main/kotlin/nexters/weski/common/config/SwaggerConfig.kt @@ -0,0 +1,32 @@ +package nexters.weski.common.config + +import io.swagger.v3.oas.models.OpenAPI +import io.swagger.v3.oas.models.info.Info +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.web.filter.ForwardedHeaderFilter + +@Configuration +class SwaggerConfig { + @Bean + fun openAPI(): OpenAPI { + return OpenAPI() + .info( + Info() + .title("We-ski API") + .description("we-ski server API") + .version("1.0.0") + ) + .servers( + listOf( + io.swagger.v3.oas.models.servers.Server().url("http://localhost:8080"), + io.swagger.v3.oas.models.servers.Server().url("http://223.130.154.51:8080") + ) + ) + } + + @Bean + fun forwardedHeaderFilter(): ForwardedHeaderFilter { + return ForwardedHeaderFilter() + } +} diff --git a/src/main/kotlin/nexters/weski/common/config/WebConfig.kt b/src/main/kotlin/nexters/weski/common/config/WebConfig.kt new file mode 100644 index 0000000..2bb36d0 --- /dev/null +++ b/src/main/kotlin/nexters/weski/common/config/WebConfig.kt @@ -0,0 +1,16 @@ +package nexters.weski.common.config + +import org.springframework.context.annotation.Configuration +import org.springframework.web.servlet.config.annotation.CorsRegistry +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer + +@Configuration +class WebConfig : WebMvcConfigurer { + + override fun addCorsMappings(registry: CorsRegistry) { + registry.addMapping("/**") + .allowedOrigins("*") + .allowedMethods("GET", "POST", "PUT", "DELETE") + .allowedHeaders("*") + } +} diff --git a/src/main/kotlin/nexters/weski/ski_resort/SkiResortController.kt b/src/main/kotlin/nexters/weski/ski_resort/SkiResortController.kt index 3b46e45..e20a432 100644 --- a/src/main/kotlin/nexters/weski/ski_resort/SkiResortController.kt +++ b/src/main/kotlin/nexters/weski/ski_resort/SkiResortController.kt @@ -1,15 +1,17 @@ package nexters.weski.ski_resort +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.tags.Tag import org.springframework.web.bind.annotation.GetMapping -import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RestController +@Tag(name = "전체 스키장 정보 API", description = "전체 스키장 날씨 및 슬로프 정보 관련") @RestController -@RequestMapping("/api/ski-resorts") class SkiResortController( private val skiResortService: SkiResortService ) { - @GetMapping + @Operation(summary = "날씨와 슬로프 정보를 포함한 전체 스키장 데이터를 조회하는 API") + @GetMapping("/api/ski-resorts") fun getAllSkiResorts(): List { return skiResortService.getAllSkiResortsAndWeather() } diff --git a/src/main/kotlin/nexters/weski/ski_resort/SkiResortResponseDto.kt b/src/main/kotlin/nexters/weski/ski_resort/SkiResortResponseDto.kt index 36682c2..addb6e9 100644 --- a/src/main/kotlin/nexters/weski/ski_resort/SkiResortResponseDto.kt +++ b/src/main/kotlin/nexters/weski/ski_resort/SkiResortResponseDto.kt @@ -1,10 +1,12 @@ package nexters.weski.ski_resort +import io.swagger.v3.oas.annotations.media.Schema import nexters.weski.weather.CurrentWeather import nexters.weski.weather.DailyWeather import nexters.weski.weather.SimpleCurrentWeatherDto import nexters.weski.weather.WeeklyWeatherDto +@Schema(description = "스키장 정보 응답 DTO") data class SkiResortResponseDto( val resortId: Long, val name: String, diff --git a/src/main/kotlin/nexters/weski/slope/SlopeController.kt b/src/main/kotlin/nexters/weski/slope/SlopeController.kt index 0bd5ded..2f1055c 100644 --- a/src/main/kotlin/nexters/weski/slope/SlopeController.kt +++ b/src/main/kotlin/nexters/weski/slope/SlopeController.kt @@ -1,17 +1,23 @@ package nexters.weski.slope +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.tags.Tag import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PathVariable -import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RestController +@Tag(name = "스키장 별 슬로프&웹캠 정보 API", description = "슬로프&웹캠 관련") @RestController -@RequestMapping("/api/slopes") class SlopeController( private val slopeService: SlopeService ) { - @GetMapping("/{resortId}") - fun getSlopesAndWebcams(@PathVariable resortId: Long): SlopeResponseDto { + @Operation(summary = "특정 스키장의 슬로프와 웹캠 정보를 조회하는 API") + @GetMapping("/api/slopes/{resortId}") + fun getSlopesAndWebcams( + @Parameter(description = "스키장 ID", example = "1") + @PathVariable resortId: Long + ): SlopeResponseDto { return slopeService.getSlopesAndWebcams(resortId) } } diff --git a/src/main/kotlin/nexters/weski/snow_maker/SnowMakerController.kt b/src/main/kotlin/nexters/weski/snow_maker/SnowMakerController.kt index d9b62ea..d22e491 100644 --- a/src/main/kotlin/nexters/weski/snow_maker/SnowMakerController.kt +++ b/src/main/kotlin/nexters/weski/snow_maker/SnowMakerController.kt @@ -1,20 +1,32 @@ package nexters.weski.snow_maker +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.tags.Tag import org.springframework.web.bind.annotation.* +@Tag(name = "스키장 설질 관련 API", description = "설질 투표와 현황 조회 API") @RestController -@RequestMapping("/api/snow-maker") - class SnowMakerController( private val snowMakerService: SnowMakerService ) { - @GetMapping("/{resortId}") - fun getSnowMaker(@PathVariable resortId: Long): SnowMakerDto { + @Operation(summary = "스키장 설질 정보 조회 API") + @GetMapping("/api/snow-maker/{resortId}") + fun getSnowMaker( + @Parameter(description = "스키장 ID", example = "1") + @PathVariable resortId: Long + ): SnowMakerDto { return snowMakerService.getSnowMaker(resortId) } - @PostMapping("/{resortId}/vote") - fun voteSnowMaker(@PathVariable resortId: Long, @RequestParam isPositive: Boolean) { + @Operation(summary = "스키장 설질 투표 API") + @PostMapping("/api/snow-maker/{resortId}/vote") + fun voteSnowMaker( + @Parameter(description = "스키장 ID", example = "1") + @PathVariable resortId: Long, + @Parameter(description = "설질의 긍정/부정 boolean value", example = "true") + @RequestParam isPositive: Boolean + ) { snowMakerService.voteSnowMaker(resortId, isPositive) } } diff --git a/src/main/kotlin/nexters/weski/weather/WeatherController.kt b/src/main/kotlin/nexters/weski/weather/WeatherController.kt index ebcba5f..e24473d 100644 --- a/src/main/kotlin/nexters/weski/weather/WeatherController.kt +++ b/src/main/kotlin/nexters/weski/weather/WeatherController.kt @@ -1,17 +1,23 @@ package nexters.weski.weather +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.tags.Tag import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PathVariable -import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RestController +@Tag(name = "스키장 별 날씨 API", description = "스키장 별 날씨 상세 정보 API") @RestController -@RequestMapping("/api/weather") class WeatherController( private val weatherService: WeatherService ) { - @GetMapping("/{resortId}") - fun getWeatherByResortId(@PathVariable resortId: Long): WeatherDto? { + @Operation(summary = "특정 스키장의 날씨 정보를 조회하는 API") + @GetMapping("/api/weather/{resortId}") + fun getWeatherByResortId( + @Parameter(description = "스키장 ID", example = "1") + @PathVariable resortId: Long + ): WeatherDto? { return weatherService.getWeatherByResortId(resortId) } } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index a444aef..aa99a67 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -15,4 +15,9 @@ spring: properties: hibernate: format_sql: true - dialect: org.hibernate.dialect.MySQL8Dialect \ No newline at end of file + dialect: org.hibernate.dialect.MySQL8Dialect +springdoc: + api-docs: + path: /v3/api-docs + swagger-ui: + path: /swagger-ui.html