From c9de7c8074ec15a3a69db808c31bd3415c17ba15 Mon Sep 17 00:00:00 2001 From: Gauthier Roebroeck Date: Mon, 13 Apr 2020 20:08:12 +0800 Subject: [PATCH] feat(swagger): update to OpenAPI 3 migrate from Springfox to Springdoc --- komga/build.gradle.kts | 8 ++-- .../swagger/SwaggerConfiguration.kt | 48 +++++++++---------- .../komga/interfaces/rest/BookController.kt | 11 ++++- .../komga/interfaces/rest/SeriesController.kt | 23 +++++---- komga/src/main/resources/application-dev.yml | 4 ++ komga/src/main/resources/application.yml | 9 ++++ 6 files changed, 65 insertions(+), 38 deletions(-) diff --git a/komga/build.gradle.kts b/komga/build.gradle.kts index a8dbd40c6..5b58c77ef 100644 --- a/komga/build.gradle.kts +++ b/komga/build.gradle.kts @@ -51,9 +51,11 @@ dependencies { implementation("io.micrometer:micrometer-registry-influx") run { - val springfoxVersion = "2.9.2" - implementation("io.springfox:springfox-swagger2:$springfoxVersion") - implementation("io.springfox:springfox-swagger-ui:$springfoxVersion") + val springdocVersion = "1.3.1" + implementation("org.springdoc:springdoc-openapi-ui:$springdocVersion") + implementation("org.springdoc:springdoc-openapi-data-rest:$springdocVersion") + implementation("org.springdoc:springdoc-openapi-security:$springdocVersion") + implementation("org.springdoc:springdoc-openapi-kotlin:$springdocVersion") } implementation("com.fasterxml.jackson.module:jackson-module-kotlin") diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/swagger/SwaggerConfiguration.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/swagger/SwaggerConfiguration.kt index d1046d334..92013272f 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/swagger/SwaggerConfiguration.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/swagger/SwaggerConfiguration.kt @@ -1,36 +1,34 @@ package org.gotson.komga.infrastructure.swagger +import io.swagger.v3.oas.models.Components +import io.swagger.v3.oas.models.ExternalDocumentation +import io.swagger.v3.oas.models.OpenAPI +import io.swagger.v3.oas.models.info.Info +import io.swagger.v3.oas.models.info.License +import io.swagger.v3.oas.models.security.SecurityScheme import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration -import org.springframework.core.Ordered -import org.springframework.data.domain.Pageable -import org.springframework.security.core.annotation.AuthenticationPrincipal -import org.springframework.web.context.request.WebRequest -import springfox.documentation.schema.AlternateTypeRules -import springfox.documentation.spi.DocumentationType -import springfox.documentation.spring.web.plugins.Docket -import springfox.documentation.swagger2.annotations.EnableSwagger2 @Configuration -@EnableSwagger2 class SwaggerConfiguration { @Bean - fun getDocket(): Docket = - Docket(DocumentationType.SWAGGER_2) - .ignoredParameterTypes( - AuthenticationPrincipal::class.java, - WebRequest::class.java - ) - .alternateTypeRules(AlternateTypeRules.newRule( - Pageable::class.java, - PageableMixin::class.java, - Ordered.HIGHEST_PRECEDENCE - )) + fun openApi(): OpenAPI = + OpenAPI() + .info(Info() + .title("Komga API") + .version("v1.0") + .description(""" + Komga offers 2 APIs: REST and OPDS. - private class PageableMixin { - val page = 0 - val size = 20 - val sort = "" - } + Both APIs are secured using HTTP Basic Authentication. + """.trimIndent()) + .license(License().name("MIT").url("https://github.com/gotson/komga/blob/master/LICENSE"))) + .externalDocs(ExternalDocumentation() + .description("Komga documentation") + .url("https://komga.org")) + .components(Components() + .addSecuritySchemes( + "basicAuth", + SecurityScheme().type(SecurityScheme.Type.HTTP).scheme("basic"))) } diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/rest/BookController.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/rest/BookController.kt index dd1062385..1571ca573 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/rest/BookController.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/rest/BookController.kt @@ -3,6 +3,8 @@ package org.gotson.komga.interfaces.rest import com.github.klinq.jpaspec.`in` import com.github.klinq.jpaspec.likeLower import com.github.klinq.jpaspec.toJoin +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter import mu.KotlinLogging import org.gotson.komga.application.service.AsyncOrchestrator import org.gotson.komga.application.service.BookLifecycle @@ -21,6 +23,7 @@ import org.gotson.komga.interfaces.rest.dto.BookDto import org.gotson.komga.interfaces.rest.dto.BookMetadataUpdateDto import org.gotson.komga.interfaces.rest.dto.PageDto import org.gotson.komga.interfaces.rest.dto.toDto +import org.springdoc.api.annotations.ParameterObject import org.springframework.core.io.FileSystemResource import org.springframework.data.domain.Page import org.springframework.data.domain.PageRequest @@ -71,7 +74,7 @@ class BookController( @RequestParam(name = "search", required = false) searchTerm: String?, @RequestParam(name = "library_id", required = false) libraryIds: List?, @RequestParam(name = "media_status", required = false) mediaStatus: List?, - page: Pageable + @ParameterObject page: Pageable ): Page { val pageRequest = PageRequest.of( page.pageNumber, @@ -115,10 +118,12 @@ class BookController( } + @Operation(description = "Return newly added or updated books.") @GetMapping("api/v1/books/latest") + @Parameter(name = "sort", hidden = true) fun getLatestSeries( @AuthenticationPrincipal principal: KomgaPrincipal, - page: Pageable + @ParameterObject page: Pageable ): Page { val pageRequest = PageRequest.of( page.pageNumber, @@ -193,6 +198,7 @@ class BookController( } else throw ResponseStatusException(HttpStatus.NOT_FOUND) } ?: throw ResponseStatusException(HttpStatus.NOT_FOUND) + @Operation(description = "Download the book file.") @GetMapping(value = [ "api/v1/books/{bookId}/file", "api/v1/books/{bookId}/file/*", @@ -348,6 +354,7 @@ class BookController( @PreAuthorize("hasRole('ADMIN')") fun updateMetadata( @PathVariable bookId: Long, + @Parameter(description = "Metadata fields to update. Set a field to null to unset the metadata. You can omit fields you don't want to update.") @Valid @RequestBody newMetadata: BookMetadataUpdateDto ): BookDto = bookRepository.findByIdOrNull(bookId)?.let { book -> diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/rest/SeriesController.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/rest/SeriesController.kt index 1f6e4a32a..aac37d2a3 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/rest/SeriesController.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/rest/SeriesController.kt @@ -3,6 +3,8 @@ package org.gotson.komga.interfaces.rest import com.github.klinq.jpaspec.`in` import com.github.klinq.jpaspec.likeLower import com.github.klinq.jpaspec.toJoin +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter import mu.KotlinLogging import org.gotson.komga.application.service.AsyncOrchestrator import org.gotson.komga.domain.model.Library @@ -16,6 +18,7 @@ import org.gotson.komga.interfaces.rest.dto.BookDto import org.gotson.komga.interfaces.rest.dto.SeriesDto import org.gotson.komga.interfaces.rest.dto.SeriesMetadataUpdateDto import org.gotson.komga.interfaces.rest.dto.toDto +import org.springdoc.api.annotations.ParameterObject import org.springframework.data.domain.Page import org.springframework.data.domain.PageRequest import org.springframework.data.domain.Pageable @@ -57,7 +60,7 @@ class SeriesController( @RequestParam(name = "search", required = false) searchTerm: String?, @RequestParam(name = "library_id", required = false) libraryIds: List?, @RequestParam(name = "status", required = false) metadataStatus: List?, - page: Pageable + @ParameterObject page: Pageable ): Page { val pageRequest = PageRequest.of( page.pageNumber, @@ -100,11 +103,12 @@ class SeriesController( }.map { it.toDto(includeUrl = principal.user.isAdmin()) } } - // all updated series, whether newly added or updated + @Operation(description = "Return recently added or updated series.") @GetMapping("/latest") + @Parameter(name = "sort", hidden = true) fun getLatestSeries( @AuthenticationPrincipal principal: KomgaPrincipal, - page: Pageable + @ParameterObject page: Pageable ): Page { val pageRequest = PageRequest.of( page.pageNumber, @@ -119,11 +123,12 @@ class SeriesController( }.map { it.toDto(includeUrl = principal.user.isAdmin()) } } - // new series only, doesn't contain existing updated series + @Operation(description = "Return newly added series.") @GetMapping("/new") + @Parameter(name = "sort", hidden = true) fun getNewSeries( @AuthenticationPrincipal principal: KomgaPrincipal, - page: Pageable + @ParameterObject page: Pageable ): Page { val pageRequest = PageRequest.of( page.pageNumber, @@ -138,11 +143,12 @@ class SeriesController( }.map { it.toDto(includeUrl = principal.user.isAdmin()) } } - // updated series only, doesn't contain new series + @Operation(description = "Return recently updated series, but not newly added ones.") @GetMapping("/updated") + @Parameter(name = "sort", hidden = true) fun getUpdatedSeries( @AuthenticationPrincipal principal: KomgaPrincipal, - page: Pageable + @ParameterObject page: Pageable ): Page { val pageRequest = PageRequest.of( page.pageNumber, @@ -185,7 +191,7 @@ class SeriesController( @AuthenticationPrincipal principal: KomgaPrincipal, @PathVariable(name = "seriesId") id: Long, @RequestParam(name = "media_status", required = false) mediaStatus: List?, - page: Pageable + @ParameterObject page: Pageable ): Page { seriesRepository.findByIdOrNull(id)?.let { if (!principal.user.canAccessSeries(it)) throw ResponseStatusException(HttpStatus.UNAUTHORIZED) @@ -234,6 +240,7 @@ class SeriesController( @PreAuthorize("hasRole('ADMIN')") fun updateMetadata( @PathVariable seriesId: Long, + @Parameter(description = "Metadata fields to update. Set a field to null to unset the metadata. You can omit fields you don't want to update.") @Valid @RequestBody newMetadata: SeriesMetadataUpdateDto ): SeriesDto = seriesRepository.findByIdOrNull(seriesId)?.let { series -> diff --git a/komga/src/main/resources/application-dev.yml b/komga/src/main/resources/application-dev.yml index 6be4438c6..11abc3adb 100644 --- a/komga/src/main/resources/application-dev.yml +++ b/komga/src/main/resources/application-dev.yml @@ -34,6 +34,10 @@ management.metrics.export.influx: # enabled: true uri: http://localhost:8086 +springdoc: + cache: + disabled: true + #server: # servlet: # context-path: /komga diff --git a/komga/src/main/resources/application.yml b/komga/src/main/resources/application.yml index 877c5d2e9..87c2e275e 100644 --- a/komga/src/main/resources/application.yml +++ b/komga/src/main/resources/application.yml @@ -53,3 +53,12 @@ management: export: influx: enabled: false +springdoc: + group-configs: + - group: REST API + paths-to-match: /api/** + - group: OPDS + paths-to-match: /opds/** + swagger-ui: + groups-order: desc + operations-sorter: alpha