diff --git a/.github/workflows/deploy-to-mavencentral.yaml b/.github/workflows/deploy-to-mavencentral.yaml index dec258f..2ff4139 100644 --- a/.github/workflows/deploy-to-mavencentral.yaml +++ b/.github/workflows/deploy-to-mavencentral.yaml @@ -16,11 +16,11 @@ jobs: steps: - name: GitHub 리포지토리 체크아웃 uses: actions/checkout@v6 - - name: JDK 17 설치 + - name: JDK 21 설치 uses: actions/setup-java@v5 with: distribution: 'adopt' - java-version: '17' + java-version: '21' - name: Gradle 애드온 준비하기 uses: gradle/gradle-build-action@v3 - name: 프로젝트 빌드 diff --git a/.github/workflows/pull-request-coverage-report.yaml b/.github/workflows/pull-request-coverage-report.yaml index ad1e405..1bf070d 100644 --- a/.github/workflows/pull-request-coverage-report.yaml +++ b/.github/workflows/pull-request-coverage-report.yaml @@ -16,11 +16,11 @@ jobs: steps: - name: GitHub 리포지토리 체크아웃 uses: actions/checkout@v6 - - name: JDK 17 설치 + - name: JDK 21 설치 uses: actions/setup-java@v5 with: distribution: 'adopt' - java-version: '17' + java-version: '21' - name: Gradle 애드온 준비하기 uses: gradle/gradle-build-action@v3 - name: 커버리지 측정 및 리포트 생성 diff --git a/README.md b/README.md index 8161b23..b8448c8 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,16 @@ It combines the advantages of both Swagger and RestDocs for efficient and intuit ## Installation and Getting Started ### Installation + +This library requires `spring-restdocs-webtestclient` to be declared explicitly +in your project, as it is no longer transitively provided. + +```kotlin +dependencies { + testImplementation("org.springframework.restdocs:spring-restdocs-webtestclient") +} +``` + Add the following dependency to your `build.gradle.kts` file:

`MVC` @@ -92,7 +102,7 @@ fun documentationGetApi() { responseBody { field("testField", "test", "test") } - }.expect(jsonPath("$testField").value("test")) + }.jsonPath("$testField").value("test") } ``` diff --git a/build.gradle.kts b/build.gradle.kts index b06db1d..e3166bf 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -42,13 +42,13 @@ subprojects { } tasks { java { - sourceCompatibility = JavaVersion.VERSION_17 - targetCompatibility = JavaVersion.VERSION_17 + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 } withType { compilerOptions { freeCompilerArgs.add("-Xjsr305=strict") - jvmTarget.set(JvmTarget.JVM_17) + jvmTarget.set(JvmTarget.JVM_21) } } test { diff --git a/documentify-project/documentify-core/build.gradle.kts b/documentify-project/documentify-core/build.gradle.kts index c3dc488..3b28282 100644 --- a/documentify-project/documentify-core/build.gradle.kts +++ b/documentify-project/documentify-core/build.gradle.kts @@ -1,9 +1,8 @@ dependencies { - implementation(libs.spring.boot.starter.test) implementation(libs.restdocs.api.spec) implementation(libs.jackson.databind) implementation(libs.jackson.datatype.jsr310) - compileOnly(libs.spring.restdocs.mockmvc) + compileOnly(libs.spring.boot.starter.test) + compileOnly(libs.spring.restdocs.webtestclient) compileOnly(libs.spring.boot.starter.web) - compileOnly(libs.spring.boot.starter.webflux) } \ No newline at end of file diff --git a/documentify-project/documentify-core/src/main/kotlin/io/github/bgmsound/documentify/core/AbstractDocumentify.kt b/documentify-project/documentify-core/src/main/kotlin/io/github/bgmsound/documentify/core/AbstractDocumentify.kt new file mode 100644 index 0000000..6d792cc --- /dev/null +++ b/documentify-project/documentify-core/src/main/kotlin/io/github/bgmsound/documentify/core/AbstractDocumentify.kt @@ -0,0 +1,58 @@ +package io.github.bgmsound.documentify.core + +import io.github.bgmsound.documentify.core.emitter.DocumentEmitter +import io.github.bgmsound.documentify.core.emitter.EmitterFactory +import io.github.bgmsound.documentify.core.environment.ApplicationContextEnvironment.Companion.applicationContextEnvironment +import io.github.bgmsound.documentify.core.environment.DocumentContextEnvironment +import io.github.bgmsound.documentify.core.environment.WebTestClientContextEnvironment.Companion.webTestClientEnvironment +import io.github.bgmsound.documentify.core.specification.schema.document.DocumentSpec +import org.springframework.context.ApplicationContext +import org.springframework.restdocs.RestDocumentationContextProvider +import org.springframework.test.web.reactive.server.WebTestClient +import org.springframework.web.context.WebApplicationContext + +abstract class AbstractDocumentify { + protected lateinit var provider: RestDocumentationContextProvider + protected lateinit var environment: DocumentContextEnvironment + protected var customEmitter: DocumentEmitter? = null + + fun documentation( + name: String, + specCustomizer: DocumentSpec.() -> Unit + ): WebTestClient.BodyContentSpec { + val documentSpec = DocumentSpec(name).also { specCustomizer(it) } + val emitter = customEmitter ?: EmitterFactory.of(provider, documentSpec, environment) + + return emitter.emit() + } + + fun emitter( + customEmitter: DocumentEmitter + ) { + this.customEmitter = customEmitter + } + + fun webTestClient( + provider: RestDocumentationContextProvider, + webTestClient: WebTestClient + ) { + this.provider = provider + environment = webTestClientEnvironment(provider, webTestClient) + } + + fun applicationContext( + provider: RestDocumentationContextProvider, + applicationContext: ApplicationContext + ) { + this.provider = provider + environment = applicationContextEnvironment(provider, applicationContext) + } + + fun webApplicationContext( + provider: RestDocumentationContextProvider, + context: WebApplicationContext + ) { + environment = applicationContextEnvironment(provider, context) + this.provider = provider + } +} \ No newline at end of file diff --git a/documentify-project/documentify-core/src/main/kotlin/io/github/bgmsound/documentify/core/emitter/AbstractDocumentEmitter.kt b/documentify-project/documentify-core/src/main/kotlin/io/github/bgmsound/documentify/core/emitter/AbstractDocumentEmitter.kt index b394cfd..0bcba95 100644 --- a/documentify-project/documentify-core/src/main/kotlin/io/github/bgmsound/documentify/core/emitter/AbstractDocumentEmitter.kt +++ b/documentify-project/documentify-core/src/main/kotlin/io/github/bgmsound/documentify/core/emitter/AbstractDocumentEmitter.kt @@ -3,10 +3,12 @@ package io.github.bgmsound.documentify.core.emitter import com.epages.restdocs.apispec.ResourceDocumentation import com.epages.restdocs.apispec.ResourceSnippetParameters import com.epages.restdocs.apispec.Schema +import io.github.bgmsound.documentify.core.emitter.WebTestClientDocumentResult.Companion.validateWith import io.github.bgmsound.documentify.core.specification.schema.document.DocumentSpec import io.github.bgmsound.documentify.core.specification.schema.response.ResponseSpec import org.springframework.restdocs.RestDocumentationContextProvider import org.springframework.restdocs.snippet.Snippet +import org.springframework.test.web.reactive.server.WebTestClient.BodyContentSpec abstract class AbstractDocumentEmitter( protected val provider: RestDocumentationContextProvider, @@ -27,4 +29,16 @@ abstract class AbstractDocumentEmitter( } return ResourceDocumentation.resource(resourceBuilder.build()) } + + override fun emit(): BodyContentSpec { + val validatableDocumentResponse = emitDocument() + emitAlternativeResponseDocument() + validatableDocumentResponse.validateWith(documentSpec.response) + + return validatableDocumentResponse + } + + abstract fun emitDocument(): BodyContentSpec + + abstract fun emitAlternativeResponseDocument() } diff --git a/documentify-project/documentify-mvc/src/main/kotlin/io/github/bgmsound/documentify/mvc/emitter/AlternativeMvcResponseDocumentController.kt b/documentify-project/documentify-core/src/main/kotlin/io/github/bgmsound/documentify/core/emitter/AlternativeResponseDocumentController.kt similarity index 51% rename from documentify-project/documentify-mvc/src/main/kotlin/io/github/bgmsound/documentify/mvc/emitter/AlternativeMvcResponseDocumentController.kt rename to documentify-project/documentify-core/src/main/kotlin/io/github/bgmsound/documentify/core/emitter/AlternativeResponseDocumentController.kt index 75d3476..e7e2917 100644 --- a/documentify-project/documentify-mvc/src/main/kotlin/io/github/bgmsound/documentify/mvc/emitter/AlternativeMvcResponseDocumentController.kt +++ b/documentify-project/documentify-core/src/main/kotlin/io/github/bgmsound/documentify/core/emitter/AlternativeResponseDocumentController.kt @@ -1,11 +1,17 @@ -package io.github.bgmsound.documentify.mvc.emitter +package io.github.bgmsound.documentify.core.emitter import org.springframework.http.ResponseEntity -import org.springframework.web.bind.annotation.* +import org.springframework.web.bind.annotation.DeleteMapping +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PatchMapping +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.PutMapping +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController @RestController @RequestMapping("/**") -class AlternativeMvcResponseDocumentController private constructor( +class AlternativeResponseDocumentController private constructor( status: Int, response: Any ) { @@ -40,8 +46,8 @@ class AlternativeMvcResponseDocumentController private constructor( fun new( status: Int, response: Any - ): AlternativeMvcResponseDocumentController { - return AlternativeMvcResponseDocumentController(status, response) + ): AlternativeResponseDocumentController { + return AlternativeResponseDocumentController(status, response) } } } \ No newline at end of file diff --git a/documentify-project/documentify-core/src/main/kotlin/io/github/bgmsound/documentify/core/emitter/DocumentEmitter.kt b/documentify-project/documentify-core/src/main/kotlin/io/github/bgmsound/documentify/core/emitter/DocumentEmitter.kt index a1d909e..99a0562 100644 --- a/documentify-project/documentify-core/src/main/kotlin/io/github/bgmsound/documentify/core/emitter/DocumentEmitter.kt +++ b/documentify-project/documentify-core/src/main/kotlin/io/github/bgmsound/documentify/core/emitter/DocumentEmitter.kt @@ -1,3 +1,9 @@ package io.github.bgmsound.documentify.core.emitter -interface DocumentEmitter \ No newline at end of file +import org.springframework.test.web.reactive.server.WebTestClient.BodyContentSpec + +interface DocumentEmitter { + + fun emit(): BodyContentSpec + +} \ No newline at end of file diff --git a/documentify-project/documentify-reactive/src/main/kotlin/io/github/bgmsound/documentify/reactive/emitter/EmitterFactory.kt b/documentify-project/documentify-core/src/main/kotlin/io/github/bgmsound/documentify/core/emitter/EmitterFactory.kt similarity index 50% rename from documentify-project/documentify-reactive/src/main/kotlin/io/github/bgmsound/documentify/reactive/emitter/EmitterFactory.kt rename to documentify-project/documentify-core/src/main/kotlin/io/github/bgmsound/documentify/core/emitter/EmitterFactory.kt index 4587a82..179268a 100644 --- a/documentify-project/documentify-reactive/src/main/kotlin/io/github/bgmsound/documentify/reactive/emitter/EmitterFactory.kt +++ b/documentify-project/documentify-core/src/main/kotlin/io/github/bgmsound/documentify/core/emitter/EmitterFactory.kt @@ -1,15 +1,15 @@ -package io.github.bgmsound.documentify.reactive.emitter +package io.github.bgmsound.documentify.core.emitter +import io.github.bgmsound.documentify.core.environment.DocumentContextEnvironment import io.github.bgmsound.documentify.core.specification.schema.document.DocumentSpec -import io.github.bgmsound.documentify.reactive.ReactiveDocumentContextEnvironment import org.springframework.restdocs.RestDocumentationContextProvider object EmitterFactory { fun of( provider: RestDocumentationContextProvider, documentSpec: DocumentSpec, - environment: ReactiveDocumentContextEnvironment - ): ReactiveDocumentEmitter { - return WebTestClientReactiveDocumentEmitter(provider, documentSpec, environment) + environment: DocumentContextEnvironment + ): DocumentEmitter { + return WebTestClientDocumentEmitter(provider, documentSpec, environment) } } \ No newline at end of file diff --git a/documentify-project/documentify-reactive/src/main/kotlin/io/github/bgmsound/documentify/reactive/emitter/WebTestClientReactiveDocumentEmitter.kt b/documentify-project/documentify-core/src/main/kotlin/io/github/bgmsound/documentify/core/emitter/WebTestClientDocumentEmitter.kt similarity index 90% rename from documentify-project/documentify-reactive/src/main/kotlin/io/github/bgmsound/documentify/reactive/emitter/WebTestClientReactiveDocumentEmitter.kt rename to documentify-project/documentify-core/src/main/kotlin/io/github/bgmsound/documentify/core/emitter/WebTestClientDocumentEmitter.kt index e0171fa..3c99e7f 100644 --- a/documentify-project/documentify-reactive/src/main/kotlin/io/github/bgmsound/documentify/reactive/emitter/WebTestClientReactiveDocumentEmitter.kt +++ b/documentify-project/documentify-core/src/main/kotlin/io/github/bgmsound/documentify/core/emitter/WebTestClientDocumentEmitter.kt @@ -1,9 +1,9 @@ -package io.github.bgmsound.documentify.reactive.emitter +package io.github.bgmsound.documentify.core.emitter +import io.github.bgmsound.documentify.core.environment.DocumentContextEnvironment import io.github.bgmsound.documentify.core.specification.schema.Method import io.github.bgmsound.documentify.core.specification.schema.document.DocumentSpec -import io.github.bgmsound.documentify.reactive.ReactiveDocumentContextEnvironment import org.springframework.http.HttpMethod import org.springframework.restdocs.RestDocumentationContextProvider import org.springframework.restdocs.operation.preprocess.Preprocessors.* @@ -15,16 +15,16 @@ import org.springframework.test.web.reactive.server.WebTestClient.RequestBodySpe import org.springframework.util.LinkedMultiValueMap import org.springframework.util.MultiValueMap -class WebTestClientReactiveDocumentEmitter( +class WebTestClientDocumentEmitter( provider: RestDocumentationContextProvider, documentSpec: DocumentSpec, - environment: ReactiveDocumentContextEnvironment -) : AbstractReactiveDocumentEmitter(provider, documentSpec) { - private val webTestClient: WebTestClient = environment.buildWebTestClient() + environment: DocumentContextEnvironment +) : AbstractDocumentEmitter(provider, documentSpec) { + private val webTestClient: WebTestClient = environment.buildTestClient() private val requestPreprocessors = environment.requestPreprocessors().toTypedArray() private val responsePreprocessors = environment.responsePreprocessors().toTypedArray() - override suspend fun emitDocument(): BodyContentSpec { + override fun emitDocument(): BodyContentSpec { val snippets = documentSpec.build() val samplePathVariables = sampleAggregator.aggregate(documentSpec.request.pathVariables) val sampleHeaders = sampleAggregator.aggregate(documentSpec.request.headers) @@ -54,10 +54,10 @@ class WebTestClientReactiveDocumentEmitter( ) } - override suspend fun emitAlternativeResponseDocument() { + override fun emitAlternativeResponseDocument() { documentSpec.otherResponses.forEachIndexed { index, response -> val sampleResponseFields = sampleAggregator.aggregate(response.fields) - val api = AlternativeReactiveResponseDocumentController.new( + val api = AlternativeResponseDocumentController.new( response.statusCode, sampleResponseFields ) diff --git a/documentify-project/documentify-reactive/src/main/kotlin/io/github/bgmsound/documentify/reactive/emitter/ReactiveDocumentResult.kt b/documentify-project/documentify-core/src/main/kotlin/io/github/bgmsound/documentify/core/emitter/WebTestClientDocumentResult.kt similarity index 75% rename from documentify-project/documentify-reactive/src/main/kotlin/io/github/bgmsound/documentify/reactive/emitter/ReactiveDocumentResult.kt rename to documentify-project/documentify-core/src/main/kotlin/io/github/bgmsound/documentify/core/emitter/WebTestClientDocumentResult.kt index 390ac3a..436ddf4 100644 --- a/documentify-project/documentify-reactive/src/main/kotlin/io/github/bgmsound/documentify/reactive/emitter/ReactiveDocumentResult.kt +++ b/documentify-project/documentify-core/src/main/kotlin/io/github/bgmsound/documentify/core/emitter/WebTestClientDocumentResult.kt @@ -1,12 +1,11 @@ -package io.github.bgmsound.documentify.reactive.emitter +package io.github.bgmsound.documentify.core.emitter -import io.github.bgmsound.documentify.core.emitter.AbstractDocumentResult import io.github.bgmsound.documentify.core.specification.schema.response.ResponseSpec import org.hamcrest.Matcher import org.hamcrest.Matchers import org.springframework.test.web.reactive.server.WebTestClient -class ReactiveDocumentResult( +class WebTestClientDocumentResult( private val actualResponse: WebTestClient.BodyContentSpec ) : AbstractDocumentResult() { override fun expect(jsonPath: String, matcher: Matcher<*>) { @@ -19,7 +18,7 @@ class ReactiveDocumentResult( companion object { fun WebTestClient.BodyContentSpec.validateWith(responseSpec: ResponseSpec) { - ReactiveDocumentResult(this).validateWith(responseSpec) + WebTestClientDocumentResult(this).validateWith(responseSpec) } } } \ No newline at end of file diff --git a/documentify-project/documentify-reactive/src/main/kotlin/io/github/bgmsound/documentify/reactive/environment/ApplicationContextEnvironment.kt b/documentify-project/documentify-core/src/main/kotlin/io/github/bgmsound/documentify/core/environment/ApplicationContextEnvironment.kt similarity index 79% rename from documentify-project/documentify-reactive/src/main/kotlin/io/github/bgmsound/documentify/reactive/environment/ApplicationContextEnvironment.kt rename to documentify-project/documentify-core/src/main/kotlin/io/github/bgmsound/documentify/core/environment/ApplicationContextEnvironment.kt index 0a6fdae..592cb44 100644 --- a/documentify-project/documentify-reactive/src/main/kotlin/io/github/bgmsound/documentify/reactive/environment/ApplicationContextEnvironment.kt +++ b/documentify-project/documentify-core/src/main/kotlin/io/github/bgmsound/documentify/core/environment/ApplicationContextEnvironment.kt @@ -1,6 +1,5 @@ -package io.github.bgmsound.documentify.reactive.environment +package io.github.bgmsound.documentify.core.environment -import io.github.bgmsound.documentify.reactive.AbstractReactiveDocumentContextEnvironment import org.springframework.context.ApplicationContext import org.springframework.restdocs.RestDocumentationContextProvider import org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation @@ -9,8 +8,8 @@ import org.springframework.test.web.reactive.server.WebTestClient class ApplicationContextEnvironment private constructor( private val provider: RestDocumentationContextProvider, private val applicationContext: ApplicationContext -) : AbstractReactiveDocumentContextEnvironment() { - override fun buildWebTestClient(): WebTestClient { +) : AbstractDocumentContextEnvironment() { + override fun buildTestClient(): WebTestClient { return WebTestClient .bindToApplicationContext(applicationContext) .configureClient() diff --git a/documentify-project/documentify-core/src/main/kotlin/io/github/bgmsound/documentify/core/environment/DocumentContextEnvironment.kt b/documentify-project/documentify-core/src/main/kotlin/io/github/bgmsound/documentify/core/environment/DocumentContextEnvironment.kt index 78e5228..e02137e 100644 --- a/documentify-project/documentify-core/src/main/kotlin/io/github/bgmsound/documentify/core/environment/DocumentContextEnvironment.kt +++ b/documentify-project/documentify-core/src/main/kotlin/io/github/bgmsound/documentify/core/environment/DocumentContextEnvironment.kt @@ -1,6 +1,7 @@ package io.github.bgmsound.documentify.core.environment import org.springframework.restdocs.operation.preprocess.OperationPreprocessor +import org.springframework.test.web.reactive.server.WebTestClient interface DocumentContextEnvironment { @@ -13,11 +14,13 @@ interface DocumentContextEnvironment { } fun responsePreprocessors(preprocessors: List) { - requestPreprocessors(*preprocessors.toTypedArray()) + responsePreprocessors(*preprocessors.toTypedArray()) } fun requestPreprocessors(): List fun responsePreprocessors(): List + fun buildTestClient(): WebTestClient + } \ No newline at end of file diff --git a/documentify-project/documentify-reactive/src/main/kotlin/io/github/bgmsound/documentify/reactive/environment/WebTestClientContextEnvironment.kt b/documentify-project/documentify-core/src/main/kotlin/io/github/bgmsound/documentify/core/environment/WebTestClientContextEnvironment.kt similarity index 77% rename from documentify-project/documentify-reactive/src/main/kotlin/io/github/bgmsound/documentify/reactive/environment/WebTestClientContextEnvironment.kt rename to documentify-project/documentify-core/src/main/kotlin/io/github/bgmsound/documentify/core/environment/WebTestClientContextEnvironment.kt index 3278aa7..afeb1e1 100644 --- a/documentify-project/documentify-reactive/src/main/kotlin/io/github/bgmsound/documentify/reactive/environment/WebTestClientContextEnvironment.kt +++ b/documentify-project/documentify-core/src/main/kotlin/io/github/bgmsound/documentify/core/environment/WebTestClientContextEnvironment.kt @@ -1,6 +1,5 @@ -package io.github.bgmsound.documentify.reactive.environment +package io.github.bgmsound.documentify.core.environment -import io.github.bgmsound.documentify.reactive.AbstractReactiveDocumentContextEnvironment import org.springframework.restdocs.RestDocumentationContextProvider import org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation import org.springframework.test.web.reactive.server.WebTestClient @@ -8,8 +7,8 @@ import org.springframework.test.web.reactive.server.WebTestClient class WebTestClientContextEnvironment private constructor( private val provider: RestDocumentationContextProvider, private val webTestClient: WebTestClient -) : AbstractReactiveDocumentContextEnvironment() { - override fun buildWebTestClient(): WebTestClient { +) : AbstractDocumentContextEnvironment() { + override fun buildTestClient(): WebTestClient { return webTestClient .mutate() .filter(WebTestClientRestDocumentation.documentationConfiguration(provider)) diff --git a/documentify-project/documentify-core/src/main/kotlin/io/github/bgmsound/documentify/core/specification/schema/ResourceSpec.kt b/documentify-project/documentify-core/src/main/kotlin/io/github/bgmsound/documentify/core/specification/schema/ResourceSpec.kt index 7107e34..f4e98c2 100644 --- a/documentify-project/documentify-core/src/main/kotlin/io/github/bgmsound/documentify/core/specification/schema/ResourceSpec.kt +++ b/documentify-project/documentify-core/src/main/kotlin/io/github/bgmsound/documentify/core/specification/schema/ResourceSpec.kt @@ -114,7 +114,7 @@ class ResourceSpec( } private fun randomSuffix(): String { - return (1..7).map { + return (1..5).map { val char = ('0'..'9').random() val number = ('a'..'z').random() (0..1).random().let { if (it == 0) char else number } diff --git a/documentify-project/documentify-mvc/build.gradle.kts b/documentify-project/documentify-mvc/build.gradle.kts index 1705f11..59c11fb 100644 --- a/documentify-project/documentify-mvc/build.gradle.kts +++ b/documentify-project/documentify-mvc/build.gradle.kts @@ -1,9 +1,5 @@ dependencies { compileOnly(libs.spring.boot.starter.web) - implementation(libs.spring.restdocs.mockmvc) - implementation(libs.spring.restdocs.restassured) - implementation(libs.restassured.mockmvc) + compileOnly(libs.spring.restdocs.webtestclient) implementation(libs.restdocs.api.spec) - implementation(libs.restdocs.api.spec.mockmvc) - implementation(libs.restdocs.api.spec.restassured) } \ No newline at end of file diff --git a/documentify-project/documentify-mvc/src/main/kotlin/io/github/bgmsound/documentify/mvc/AbstractMvcDocumentContextEnvironment.kt b/documentify-project/documentify-mvc/src/main/kotlin/io/github/bgmsound/documentify/mvc/AbstractMvcDocumentContextEnvironment.kt deleted file mode 100644 index d184e53..0000000 --- a/documentify-project/documentify-mvc/src/main/kotlin/io/github/bgmsound/documentify/mvc/AbstractMvcDocumentContextEnvironment.kt +++ /dev/null @@ -1,5 +0,0 @@ -package io.github.bgmsound.documentify.mvc - -import io.github.bgmsound.documentify.core.environment.AbstractDocumentContextEnvironment - -abstract class AbstractMvcDocumentContextEnvironment : AbstractDocumentContextEnvironment(), MvcDocumentContextEnvironment \ No newline at end of file diff --git a/documentify-project/documentify-mvc/src/main/kotlin/io/github/bgmsound/documentify/mvc/Documentify.kt b/documentify-project/documentify-mvc/src/main/kotlin/io/github/bgmsound/documentify/mvc/Documentify.kt index 4573c95..b11b315 100644 --- a/documentify-project/documentify-mvc/src/main/kotlin/io/github/bgmsound/documentify/mvc/Documentify.kt +++ b/documentify-project/documentify-mvc/src/main/kotlin/io/github/bgmsound/documentify/mvc/Documentify.kt @@ -1,45 +1,21 @@ package io.github.bgmsound.documentify.mvc -import io.github.bgmsound.documentify.core.specification.schema.document.DocumentSpec -import io.github.bgmsound.documentify.mvc.emitter.EmitterFactory -import io.github.bgmsound.documentify.mvc.emitter.MvcDocumentEmitter +import io.github.bgmsound.documentify.core.AbstractDocumentify import io.github.bgmsound.documentify.mvc.environment.MockMvcContextEnvironment.Companion.mockMvcEnvironment import io.github.bgmsound.documentify.mvc.environment.StandaloneMvcContextEnvironment -import io.github.bgmsound.documentify.mvc.environment.WebApplicationContextEnvironment.Companion.webApplicationContextEnvironment import org.junit.jupiter.api.extension.ExtendWith import org.springframework.restdocs.RestDocumentationContextProvider import org.springframework.restdocs.RestDocumentationExtension import org.springframework.test.web.servlet.MockMvc -import org.springframework.web.context.WebApplicationContext @ExtendWith(RestDocumentationExtension::class) -abstract class Documentify { - private lateinit var provider: RestDocumentationContextProvider - private lateinit var environment: MvcDocumentContextEnvironment - private var customEmitter: MvcDocumentEmitter? = null - - fun documentation( - name: String, - specCustomizer: DocumentSpec.() -> Unit - ): ValidatableMockResponse { - val documentSpec = DocumentSpec(name).also { specCustomizer(it) } - val emitter = customEmitter ?: EmitterFactory.of(provider, documentSpec, environment) - - return emitter.emit() - } - - fun emitter( - customEmitter: MvcDocumentEmitter - ) { - this.customEmitter = customEmitter - } - +abstract class Documentify : AbstractDocumentify() { fun mockMvc( provider: RestDocumentationContextProvider, mockMvc: MockMvc ) { this.provider = provider - environment = mockMvcEnvironment(mockMvc) + environment = mockMvcEnvironment(provider, mockMvc) } fun standalone( @@ -59,12 +35,4 @@ abstract class Documentify { .also(contextCustomizer) standalone(provider, standaloneContext) } - - fun webApplicationContext( - provider: RestDocumentationContextProvider, - context: WebApplicationContext - ) { - environment = webApplicationContextEnvironment(provider, context) - this.provider = provider - } } \ No newline at end of file diff --git a/documentify-project/documentify-mvc/src/main/kotlin/io/github/bgmsound/documentify/mvc/MvcDocumentContextEnvironment.kt b/documentify-project/documentify-mvc/src/main/kotlin/io/github/bgmsound/documentify/mvc/MvcDocumentContextEnvironment.kt deleted file mode 100644 index cf21fbb..0000000 --- a/documentify-project/documentify-mvc/src/main/kotlin/io/github/bgmsound/documentify/mvc/MvcDocumentContextEnvironment.kt +++ /dev/null @@ -1,10 +0,0 @@ -package io.github.bgmsound.documentify.mvc - -import io.github.bgmsound.documentify.core.environment.DocumentContextEnvironment -import org.springframework.test.web.servlet.MockMvc - -interface MvcDocumentContextEnvironment : DocumentContextEnvironment { - - fun buildMockMvc(): MockMvc - -} \ No newline at end of file diff --git a/documentify-project/documentify-mvc/src/main/kotlin/io/github/bgmsound/documentify/mvc/ValidatableMockMvcResponseAdapter.kt b/documentify-project/documentify-mvc/src/main/kotlin/io/github/bgmsound/documentify/mvc/ValidatableMockMvcResponseAdapter.kt deleted file mode 100644 index e996ec1..0000000 --- a/documentify-project/documentify-mvc/src/main/kotlin/io/github/bgmsound/documentify/mvc/ValidatableMockMvcResponseAdapter.kt +++ /dev/null @@ -1,37 +0,0 @@ -package io.github.bgmsound.documentify.mvc - -import io.restassured.module.mockmvc.response.ValidatableMockMvcResponse -import org.springframework.http.HttpStatus -import org.springframework.test.web.servlet.ResultHandler -import org.springframework.test.web.servlet.ResultMatcher - -class ValidatableMockMvcResponseAdapter private constructor( - private val restAssuredMockResponse: ValidatableMockMvcResponse -) : ValidatableMockResponse { - - override fun expect(matcher: ResultMatcher): ValidatableMockResponse { - restAssuredMockResponse.expect(matcher) - return this - } - - override fun status(status: HttpStatus): ValidatableMockResponse { - restAssuredMockResponse.statusCode(status.value()) - return this - } - - override fun apply(handler: ResultHandler, vararg additionalHandlers: ResultHandler): ValidatableMockResponse { - restAssuredMockResponse.apply(handler, *additionalHandlers) - return this - } - - override fun assertThat(matcher: ResultMatcher): ValidatableMockResponse { - restAssuredMockResponse.assertThat(matcher) - return this - } - - companion object { - fun of(restAssuredMockResponse: ValidatableMockMvcResponse): ValidatableMockResponse { - return ValidatableMockMvcResponseAdapter(restAssuredMockResponse) - } - } -} \ No newline at end of file diff --git a/documentify-project/documentify-mvc/src/main/kotlin/io/github/bgmsound/documentify/mvc/ValidatableMockResponse.kt b/documentify-project/documentify-mvc/src/main/kotlin/io/github/bgmsound/documentify/mvc/ValidatableMockResponse.kt deleted file mode 100644 index 5e436a5..0000000 --- a/documentify-project/documentify-mvc/src/main/kotlin/io/github/bgmsound/documentify/mvc/ValidatableMockResponse.kt +++ /dev/null @@ -1,17 +0,0 @@ -package io.github.bgmsound.documentify.mvc - -import org.springframework.http.HttpStatus -import org.springframework.test.web.servlet.ResultHandler -import org.springframework.test.web.servlet.ResultMatcher - -interface ValidatableMockResponse { - - fun expect(matcher: ResultMatcher): ValidatableMockResponse - - fun status(status: HttpStatus): ValidatableMockResponse - - fun apply(handler: ResultHandler, vararg additionalHandlers: ResultHandler): ValidatableMockResponse - - fun assertThat(matcher: ResultMatcher): ValidatableMockResponse - -} \ No newline at end of file diff --git a/documentify-project/documentify-mvc/src/main/kotlin/io/github/bgmsound/documentify/mvc/emitter/AbstractMvcDocumentEmitter.kt b/documentify-project/documentify-mvc/src/main/kotlin/io/github/bgmsound/documentify/mvc/emitter/AbstractMvcDocumentEmitter.kt deleted file mode 100644 index 903ebce..0000000 --- a/documentify-project/documentify-mvc/src/main/kotlin/io/github/bgmsound/documentify/mvc/emitter/AbstractMvcDocumentEmitter.kt +++ /dev/null @@ -1,26 +0,0 @@ -package io.github.bgmsound.documentify.mvc.emitter - -import io.github.bgmsound.documentify.core.emitter.AbstractDocumentEmitter -import io.github.bgmsound.documentify.core.specification.schema.document.DocumentSpec -import io.github.bgmsound.documentify.mvc.ValidatableMockMvcResponseAdapter -import io.github.bgmsound.documentify.mvc.ValidatableMockResponse -import io.github.bgmsound.documentify.mvc.emitter.MvcDocumentResult.Companion.validateWith -import io.restassured.module.mockmvc.response.ValidatableMockMvcResponse -import org.springframework.restdocs.RestDocumentationContextProvider - -abstract class AbstractMvcDocumentEmitter( - provider: RestDocumentationContextProvider, - documentSpec: DocumentSpec -) : AbstractDocumentEmitter(provider, documentSpec), MvcDocumentEmitter { - override fun emit(): ValidatableMockResponse { - val documentResult = ValidatableMockMvcResponseAdapter.of(emitDocument()) - documentResult.validateWith(documentSpec.response) - emitAlternativeResponseDocument() - - return documentResult - } - - abstract fun emitDocument(): ValidatableMockMvcResponse - - abstract fun emitAlternativeResponseDocument() -} \ No newline at end of file diff --git a/documentify-project/documentify-mvc/src/main/kotlin/io/github/bgmsound/documentify/mvc/emitter/EmitterFactory.kt b/documentify-project/documentify-mvc/src/main/kotlin/io/github/bgmsound/documentify/mvc/emitter/EmitterFactory.kt deleted file mode 100644 index c1d0241..0000000 --- a/documentify-project/documentify-mvc/src/main/kotlin/io/github/bgmsound/documentify/mvc/emitter/EmitterFactory.kt +++ /dev/null @@ -1,15 +0,0 @@ -package io.github.bgmsound.documentify.mvc.emitter - -import io.github.bgmsound.documentify.core.specification.schema.document.DocumentSpec -import io.github.bgmsound.documentify.mvc.MvcDocumentContextEnvironment -import org.springframework.restdocs.RestDocumentationContextProvider - -object EmitterFactory { - fun of( - provider: RestDocumentationContextProvider, - documentSpec: DocumentSpec, - environment: MvcDocumentContextEnvironment - ): MvcDocumentEmitter { - return RestAssuredMvcDocumentEmitter(provider, documentSpec, environment) - } -} \ No newline at end of file diff --git a/documentify-project/documentify-mvc/src/main/kotlin/io/github/bgmsound/documentify/mvc/emitter/MvcDocumentEmitter.kt b/documentify-project/documentify-mvc/src/main/kotlin/io/github/bgmsound/documentify/mvc/emitter/MvcDocumentEmitter.kt deleted file mode 100644 index f7aa124..0000000 --- a/documentify-project/documentify-mvc/src/main/kotlin/io/github/bgmsound/documentify/mvc/emitter/MvcDocumentEmitter.kt +++ /dev/null @@ -1,9 +0,0 @@ -package io.github.bgmsound.documentify.mvc.emitter - -import io.github.bgmsound.documentify.mvc.ValidatableMockResponse - -interface MvcDocumentEmitter { - - fun emit(): ValidatableMockResponse - -} \ No newline at end of file diff --git a/documentify-project/documentify-mvc/src/main/kotlin/io/github/bgmsound/documentify/mvc/emitter/MvcDocumentResult.kt b/documentify-project/documentify-mvc/src/main/kotlin/io/github/bgmsound/documentify/mvc/emitter/MvcDocumentResult.kt deleted file mode 100644 index da97305..0000000 --- a/documentify-project/documentify-mvc/src/main/kotlin/io/github/bgmsound/documentify/mvc/emitter/MvcDocumentResult.kt +++ /dev/null @@ -1,25 +0,0 @@ -package io.github.bgmsound.documentify.mvc.emitter - -import io.github.bgmsound.documentify.core.emitter.AbstractDocumentResult -import io.github.bgmsound.documentify.core.specification.schema.response.ResponseSpec -import io.github.bgmsound.documentify.mvc.ValidatableMockResponse -import org.hamcrest.Matcher -import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath - -class MvcDocumentResult( - private val actualResponse: ValidatableMockResponse -) : AbstractDocumentResult() { - override fun expect(jsonPath: String, matcher: Matcher<*>) { - actualResponse.expect(jsonPath(jsonPath).value(matcher)) - } - - override fun expectValue(jsonPath: String, value: Any) { - actualResponse.expect(jsonPath(jsonPath).value(value)) - } - - companion object { - fun ValidatableMockResponse.validateWith(responseSpec: ResponseSpec) { - MvcDocumentResult(this).validateWith(responseSpec) - } - } -} \ No newline at end of file diff --git a/documentify-project/documentify-mvc/src/main/kotlin/io/github/bgmsound/documentify/mvc/emitter/RestAssuredMvcDocumentEmitter.kt b/documentify-project/documentify-mvc/src/main/kotlin/io/github/bgmsound/documentify/mvc/emitter/RestAssuredMvcDocumentEmitter.kt deleted file mode 100644 index 9a86e33..0000000 --- a/documentify-project/documentify-mvc/src/main/kotlin/io/github/bgmsound/documentify/mvc/emitter/RestAssuredMvcDocumentEmitter.kt +++ /dev/null @@ -1,106 +0,0 @@ -package io.github.bgmsound.documentify.mvc.emitter - -import com.epages.restdocs.apispec.MockMvcRestDocumentationWrapper.document -import io.github.bgmsound.documentify.core.specification.schema.Method -import io.github.bgmsound.documentify.core.specification.schema.document.DocumentSpec -import io.github.bgmsound.documentify.mvc.MvcDocumentContextEnvironment -import io.restassured.http.ContentType -import io.restassured.module.mockmvc.RestAssuredMockMvc.given -import io.restassured.module.mockmvc.response.MockMvcResponse -import io.restassured.module.mockmvc.response.ValidatableMockMvcResponse -import io.restassured.module.mockmvc.specification.MockMvcRequestSpecification -import org.springframework.restdocs.RestDocumentationContextProvider -import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration -import org.springframework.restdocs.operation.preprocess.Preprocessors.* -import org.springframework.test.web.servlet.setup.MockMvcBuilders -import org.springframework.test.web.servlet.setup.StandaloneMockMvcBuilder - -class RestAssuredMvcDocumentEmitter( - provider: RestDocumentationContextProvider, - documentSpec: DocumentSpec, - environment: MvcDocumentContextEnvironment -) : AbstractMvcDocumentEmitter(provider, documentSpec) { - private val mockMvc = environment.buildMockMvc() - private val requestPreprocessors = environment.requestPreprocessors().toTypedArray() - private val responsePreprocessors = environment.responsePreprocessors().toTypedArray() - - override fun emitDocument(): ValidatableMockMvcResponse { - val snippets = documentSpec.build() - val samplePathVariables = sampleAggregator.aggregate(documentSpec.request.pathVariables) - val sampleQueryParameters = sampleAggregator.aggregate(documentSpec.request.queryParameters) - val sampleHeaders = sampleAggregator.aggregate(documentSpec.request.headers) - val sampleFields = sampleAggregator.aggregate(documentSpec.request.fields) - - val documentResultHandler = document( - documentSpec.name, - preprocessRequest(prettyPrint(), *requestPreprocessors), - preprocessResponse(prettyPrint(), *responsePreprocessors), - *snippets.toTypedArray() - ) - val requestSpecification: MockMvcRequestSpecification = given().mockMvc(mockMvc) - val response = requestSpecification - .log().all() - .pathParams(samplePathVariables) - .queryParams(sampleQueryParameters) - .headers(sampleHeaders) - .bodyIfExists(sampleFields) - .contentType(ContentType.JSON) - .accept(ContentType.JSON) - .request() - return response - .then() - .log().all() - .assertThat() - .apply(documentResultHandler) - .statusCode(documentSpec.response.statusCode) - } - - override fun emitAlternativeResponseDocument() { - documentSpec.otherResponses.forEachIndexed { index, response -> - val sampleResponseFields = sampleAggregator.aggregate(response.fields) - val api = AlternativeMvcResponseDocumentController.new( - response.statusCode, - sampleResponseFields - ) - val mockMvc = MockMvcBuilders - .standaloneSetup(api) - .apply(documentationConfiguration(provider)) - .build() - val requestSpecification: MockMvcRequestSpecification = given().mockMvc(mockMvc) - val samplePathVariables = sampleAggregator.aggregate(documentSpec.request.pathVariables) - requestSpecification - .pathParams(samplePathVariables) - .contentType(ContentType.JSON) - .accept(ContentType.JSON) - .request() - .then() - .apply( - document( - "${documentSpec.name}-case-${index + 1}", - preprocessRequest(prettyPrint(), *requestPreprocessors), - preprocessResponse(prettyPrint(), *responsePreprocessors), - response.buildResource(index) - ) - ) - .statusCode(response.statusCode) - } - } - - private fun MockMvcRequestSpecification.bodyIfExists( - fields: Map - ): MockMvcRequestSpecification = if (fields.isEmpty()) { - this - } else { - body(fields) - } - - private fun MockMvcRequestSpecification.request(): MockMvcResponse { - return when (documentSpec.request.method) { - Method.GET -> get(documentSpec.request.url) - Method.POST -> post(documentSpec.request.url) - Method.PUT -> put(documentSpec.request.url) - Method.PATCH -> patch(documentSpec.request.url) - Method.DELETE -> delete(documentSpec.request.url) - } - } -} \ No newline at end of file diff --git a/documentify-project/documentify-mvc/src/main/kotlin/io/github/bgmsound/documentify/mvc/environment/MockMvcContextEnvironment.kt b/documentify-project/documentify-mvc/src/main/kotlin/io/github/bgmsound/documentify/mvc/environment/MockMvcContextEnvironment.kt index ecf35ea..8c92375 100644 --- a/documentify-project/documentify-mvc/src/main/kotlin/io/github/bgmsound/documentify/mvc/environment/MockMvcContextEnvironment.kt +++ b/documentify-project/documentify-mvc/src/main/kotlin/io/github/bgmsound/documentify/mvc/environment/MockMvcContextEnvironment.kt @@ -1,18 +1,29 @@ package io.github.bgmsound.documentify.mvc.environment -import io.github.bgmsound.documentify.mvc.AbstractMvcDocumentContextEnvironment +import io.github.bgmsound.documentify.core.environment.AbstractDocumentContextEnvironment +import org.springframework.restdocs.RestDocumentationContextProvider +import org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation +import org.springframework.test.web.reactive.server.WebTestClient import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.client.MockMvcWebTestClient class MockMvcContextEnvironment private constructor( + private val provider: RestDocumentationContextProvider, private val mockMvc: MockMvc -): AbstractMvcDocumentContextEnvironment() { - override fun buildMockMvc(): MockMvc { - return mockMvc +): AbstractDocumentContextEnvironment() { + override fun buildTestClient(): WebTestClient { + return MockMvcWebTestClient + .bindTo(mockMvc) + .filter(WebTestClientRestDocumentation.documentationConfiguration(provider)) + .build() } companion object { - fun mockMvcEnvironment(mockMvc: MockMvc): MockMvcContextEnvironment { - return MockMvcContextEnvironment(mockMvc) + fun mockMvcEnvironment( + provider: RestDocumentationContextProvider, + mockMvc: MockMvc + ): MockMvcContextEnvironment { + return MockMvcContextEnvironment(provider, mockMvc) } } } \ No newline at end of file diff --git a/documentify-project/documentify-mvc/src/main/kotlin/io/github/bgmsound/documentify/mvc/environment/StandaloneMvcContextEnvironment.kt b/documentify-project/documentify-mvc/src/main/kotlin/io/github/bgmsound/documentify/mvc/environment/StandaloneMvcContextEnvironment.kt index 6e66808..d72f3a9 100644 --- a/documentify-project/documentify-mvc/src/main/kotlin/io/github/bgmsound/documentify/mvc/environment/StandaloneMvcContextEnvironment.kt +++ b/documentify-project/documentify-mvc/src/main/kotlin/io/github/bgmsound/documentify/mvc/environment/StandaloneMvcContextEnvironment.kt @@ -1,19 +1,18 @@ package io.github.bgmsound.documentify.mvc.environment import io.github.bgmsound.documentify.core.environment.AbstractStandaloneContextEnvironment -import io.github.bgmsound.documentify.mvc.MvcDocumentContextEnvironment import org.springframework.boot.convert.ApplicationConversionService import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter import org.springframework.restdocs.RestDocumentationContextProvider -import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration -import org.springframework.test.web.servlet.MockMvc +import org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation.documentationConfiguration +import org.springframework.test.web.reactive.server.WebTestClient +import org.springframework.test.web.servlet.client.MockMvcWebTestClient import org.springframework.test.web.servlet.setup.MockMvcBuilders -import org.springframework.test.web.servlet.setup.StandaloneMockMvcBuilder import org.springframework.web.method.support.HandlerMethodArgumentResolver class StandaloneMvcContextEnvironment private constructor( private val provider: RestDocumentationContextProvider -) : AbstractStandaloneContextEnvironment(), MvcDocumentContextEnvironment { +) : AbstractStandaloneContextEnvironment() { private val argumentResolvers: MutableList = mutableListOf() fun argumentResolver(argumentResolver: HandlerMethodArgumentResolver): StandaloneMvcContextEnvironment { @@ -31,8 +30,8 @@ class StandaloneMvcContextEnvironment private constructor( return this } - override fun buildMockMvc(): MockMvc { - return MockMvcBuilders + override fun buildTestClient(): WebTestClient { + val mockMvc = MockMvcBuilders .standaloneSetup(*controllers.toTypedArray()) .setControllerAdvice(*controllerAdvices.toTypedArray()) .setCustomArgumentResolvers(*argumentResolvers.toTypedArray()) @@ -41,12 +40,15 @@ class StandaloneMvcContextEnvironment private constructor( addConverter(converter) } }) - .apply(documentationConfiguration(provider)) .apply { if (codec != null) { val objectMapper = codec!! setMessageConverters(MappingJackson2HttpMessageConverter(objectMapper)) }} .build() + return MockMvcWebTestClient + .bindTo(mockMvc) + .filter(documentationConfiguration(provider)) + .build() } companion object { diff --git a/documentify-project/documentify-mvc/src/main/kotlin/io/github/bgmsound/documentify/mvc/environment/WebApplicationContextEnvironment.kt b/documentify-project/documentify-mvc/src/main/kotlin/io/github/bgmsound/documentify/mvc/environment/WebApplicationContextEnvironment.kt deleted file mode 100644 index a3c497b..0000000 --- a/documentify-project/documentify-mvc/src/main/kotlin/io/github/bgmsound/documentify/mvc/environment/WebApplicationContextEnvironment.kt +++ /dev/null @@ -1,31 +0,0 @@ -package io.github.bgmsound.documentify.mvc.environment - -import io.github.bgmsound.documentify.mvc.AbstractMvcDocumentContextEnvironment -import org.springframework.restdocs.RestDocumentationContextProvider -import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration -import org.springframework.test.web.servlet.MockMvc -import org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder -import org.springframework.test.web.servlet.setup.MockMvcBuilders -import org.springframework.web.context.WebApplicationContext - -class WebApplicationContextEnvironment private constructor( - private val provider: RestDocumentationContextProvider, - private val applicationContext: WebApplicationContext -) : AbstractMvcDocumentContextEnvironment() { - - companion object { - fun webApplicationContextEnvironment( - provider: RestDocumentationContextProvider, - context: WebApplicationContext - ): WebApplicationContextEnvironment { - return WebApplicationContextEnvironment(provider, context) - } - } - - override fun buildMockMvc(): MockMvc { - return MockMvcBuilders - .webAppContextSetup(applicationContext) - .apply(documentationConfiguration(provider)) - .build() - } -} \ No newline at end of file diff --git a/documentify-project/documentify-reactive/build.gradle.kts b/documentify-project/documentify-reactive/build.gradle.kts index 4b32801..c359c46 100644 --- a/documentify-project/documentify-reactive/build.gradle.kts +++ b/documentify-project/documentify-reactive/build.gradle.kts @@ -1,6 +1,5 @@ dependencies { compileOnly(libs.spring.boot.starter.webflux) - implementation(libs.spring.restdocs.webtestclient) + compileOnly(libs.spring.restdocs.webtestclient) implementation(libs.restdocs.api.spec) - implementation(libs.restdocs.api.spec.webtestclient) } \ No newline at end of file diff --git a/documentify-project/documentify-reactive/src/main/kotlin/io/github/bgmsound/documentify/reactive/AbstractReactiveDocumentContextEnvironment.kt b/documentify-project/documentify-reactive/src/main/kotlin/io/github/bgmsound/documentify/reactive/AbstractReactiveDocumentContextEnvironment.kt deleted file mode 100644 index 7f49960..0000000 --- a/documentify-project/documentify-reactive/src/main/kotlin/io/github/bgmsound/documentify/reactive/AbstractReactiveDocumentContextEnvironment.kt +++ /dev/null @@ -1,5 +0,0 @@ -package io.github.bgmsound.documentify.reactive - -import io.github.bgmsound.documentify.core.environment.AbstractDocumentContextEnvironment - -abstract class AbstractReactiveDocumentContextEnvironment : AbstractDocumentContextEnvironment(), ReactiveDocumentContextEnvironment \ No newline at end of file diff --git a/documentify-project/documentify-reactive/src/main/kotlin/io/github/bgmsound/documentify/reactive/Documentify.kt b/documentify-project/documentify-reactive/src/main/kotlin/io/github/bgmsound/documentify/reactive/Documentify.kt index 5776834..78d2c74 100644 --- a/documentify-project/documentify-reactive/src/main/kotlin/io/github/bgmsound/documentify/reactive/Documentify.kt +++ b/documentify-project/documentify-reactive/src/main/kotlin/io/github/bgmsound/documentify/reactive/Documentify.kt @@ -1,49 +1,14 @@ package io.github.bgmsound.documentify.reactive -import io.github.bgmsound.documentify.core.specification.schema.document.DocumentSpec -import io.github.bgmsound.documentify.reactive.emitter.EmitterFactory -import io.github.bgmsound.documentify.reactive.emitter.ReactiveDocumentEmitter -import io.github.bgmsound.documentify.reactive.environment.ApplicationContextEnvironment.Companion.applicationContextEnvironment +import io.github.bgmsound.documentify.core.AbstractDocumentify import io.github.bgmsound.documentify.reactive.environment.StandaloneReactiveContextEnvironment import io.github.bgmsound.documentify.reactive.environment.StandaloneReactiveContextEnvironment.Companion.standaloneEnvironment -import io.github.bgmsound.documentify.reactive.environment.WebTestClientContextEnvironment.Companion.webTestClientEnvironment import org.junit.jupiter.api.extension.ExtendWith -import org.springframework.context.ApplicationContext import org.springframework.restdocs.RestDocumentationContextProvider import org.springframework.restdocs.RestDocumentationExtension -import org.springframework.test.web.reactive.server.WebTestClient -import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolver @ExtendWith(RestDocumentationExtension::class) -abstract class Documentify { - private lateinit var provider: RestDocumentationContextProvider - private lateinit var environment: ReactiveDocumentContextEnvironment - private var customEmitter: ReactiveDocumentEmitter? = null - - suspend fun documentation( - name: String, - specCustomizer: DocumentSpec.() -> Unit - ): WebTestClient.BodyContentSpec { - val documentSpec = DocumentSpec(name).also { specCustomizer(it) } - val emitter = customEmitter ?: EmitterFactory.of(provider, documentSpec, environment) - - return emitter.emit() - } - - fun emitter( - customEmitter: ReactiveDocumentEmitter - ) { - this.customEmitter = customEmitter - } - - fun webTestClient( - provider: RestDocumentationContextProvider, - webTestClient: WebTestClient - ) { - this.provider = provider - environment = webTestClientEnvironment(provider, webTestClient) - } - +abstract class Documentify : AbstractDocumentify() { fun standalone( provider: RestDocumentationContextProvider, standaloneContext: StandaloneReactiveContextEnvironment @@ -59,12 +24,4 @@ abstract class Documentify { val standaloneContext = standaloneEnvironment(provider).also(contextCustomizer) standalone(provider, standaloneContext) } - - fun applicationContext( - provider: RestDocumentationContextProvider, - applicationContext: ApplicationContext - ) { - this.provider = provider - environment = applicationContextEnvironment(provider, applicationContext) - } } \ No newline at end of file diff --git a/documentify-project/documentify-reactive/src/main/kotlin/io/github/bgmsound/documentify/reactive/ReactiveDocumentContextEnvironment.kt b/documentify-project/documentify-reactive/src/main/kotlin/io/github/bgmsound/documentify/reactive/ReactiveDocumentContextEnvironment.kt deleted file mode 100644 index b35926f..0000000 --- a/documentify-project/documentify-reactive/src/main/kotlin/io/github/bgmsound/documentify/reactive/ReactiveDocumentContextEnvironment.kt +++ /dev/null @@ -1,10 +0,0 @@ -package io.github.bgmsound.documentify.reactive - -import io.github.bgmsound.documentify.core.environment.DocumentContextEnvironment -import org.springframework.test.web.reactive.server.WebTestClient - -interface ReactiveDocumentContextEnvironment : DocumentContextEnvironment { - - fun buildWebTestClient(): WebTestClient - -} \ No newline at end of file diff --git a/documentify-project/documentify-reactive/src/main/kotlin/io/github/bgmsound/documentify/reactive/emitter/AbstractReactiveDocumentEmitter.kt b/documentify-project/documentify-reactive/src/main/kotlin/io/github/bgmsound/documentify/reactive/emitter/AbstractReactiveDocumentEmitter.kt deleted file mode 100644 index 6bd7e72..0000000 --- a/documentify-project/documentify-reactive/src/main/kotlin/io/github/bgmsound/documentify/reactive/emitter/AbstractReactiveDocumentEmitter.kt +++ /dev/null @@ -1,26 +0,0 @@ -package io.github.bgmsound.documentify.reactive.emitter - -import io.github.bgmsound.documentify.core.emitter.AbstractDocumentEmitter -import io.github.bgmsound.documentify.core.specification.schema.document.DocumentSpec -import io.github.bgmsound.documentify.reactive.emitter.ReactiveDocumentResult.Companion.validateWith -import org.springframework.restdocs.RestDocumentationContextProvider -import org.springframework.test.web.reactive.server.WebTestClient.BodyContentSpec - -abstract class AbstractReactiveDocumentEmitter( - provider: RestDocumentationContextProvider, - documentSpec: DocumentSpec, -) : AbstractDocumentEmitter(provider, documentSpec), ReactiveDocumentEmitter { - - override suspend fun emit(): BodyContentSpec { - val validatableDocumentResponse = emitDocument() - emitAlternativeResponseDocument() - validatableDocumentResponse.validateWith(documentSpec.response) - - return validatableDocumentResponse - } - - abstract suspend fun emitDocument(): BodyContentSpec - - abstract suspend fun emitAlternativeResponseDocument() - -} \ No newline at end of file diff --git a/documentify-project/documentify-reactive/src/main/kotlin/io/github/bgmsound/documentify/reactive/emitter/AlternativeReactiveResponseDocumentController.kt b/documentify-project/documentify-reactive/src/main/kotlin/io/github/bgmsound/documentify/reactive/emitter/AlternativeReactiveResponseDocumentController.kt deleted file mode 100644 index d23981f..0000000 --- a/documentify-project/documentify-reactive/src/main/kotlin/io/github/bgmsound/documentify/reactive/emitter/AlternativeReactiveResponseDocumentController.kt +++ /dev/null @@ -1,53 +0,0 @@ -package io.github.bgmsound.documentify.reactive.emitter - -import org.springframework.http.ResponseEntity -import org.springframework.web.bind.annotation.* -import reactor.core.publisher.Mono - -@RestController -@RequestMapping("/**") -class AlternativeReactiveResponseDocumentController private constructor( - private val status: Int, - private val response: Any -) { - @GetMapping - fun get(): Mono> { - return response() - } - - @PostMapping - fun post(): Mono> { - return response() - } - - @PutMapping - fun put(): Mono> { - return response() - } - - @DeleteMapping - fun delete(): Mono> { - return response() - } - - @PatchMapping - fun patch(): Mono> { - return response() - } - - private fun response(): Mono> { - if (response is ResponseEntity<*>) { - return Mono.just(response) - } - return Mono.just(ResponseEntity.status(status).body(response)) - } - - companion object { - fun new( - status: Int, - response: Any - ): AlternativeReactiveResponseDocumentController { - return AlternativeReactiveResponseDocumentController(status, response) - } - } -} \ No newline at end of file diff --git a/documentify-project/documentify-reactive/src/main/kotlin/io/github/bgmsound/documentify/reactive/emitter/ReactiveDocumentEmitter.kt b/documentify-project/documentify-reactive/src/main/kotlin/io/github/bgmsound/documentify/reactive/emitter/ReactiveDocumentEmitter.kt deleted file mode 100644 index cd9ca1e..0000000 --- a/documentify-project/documentify-reactive/src/main/kotlin/io/github/bgmsound/documentify/reactive/emitter/ReactiveDocumentEmitter.kt +++ /dev/null @@ -1,9 +0,0 @@ -package io.github.bgmsound.documentify.reactive.emitter - -import org.springframework.test.web.reactive.server.WebTestClient.BodyContentSpec - -interface ReactiveDocumentEmitter { - - suspend fun emit(): BodyContentSpec - -} \ No newline at end of file diff --git a/documentify-project/documentify-reactive/src/main/kotlin/io/github/bgmsound/documentify/reactive/environment/StandaloneReactiveContextEnvironment.kt b/documentify-project/documentify-reactive/src/main/kotlin/io/github/bgmsound/documentify/reactive/environment/StandaloneReactiveContextEnvironment.kt index b57bd4e..93fbebe 100644 --- a/documentify-project/documentify-reactive/src/main/kotlin/io/github/bgmsound/documentify/reactive/environment/StandaloneReactiveContextEnvironment.kt +++ b/documentify-project/documentify-reactive/src/main/kotlin/io/github/bgmsound/documentify/reactive/environment/StandaloneReactiveContextEnvironment.kt @@ -2,7 +2,6 @@ package io.github.bgmsound.documentify.reactive.environment import com.fasterxml.jackson.databind.ObjectMapper import io.github.bgmsound.documentify.core.environment.AbstractStandaloneContextEnvironment -import io.github.bgmsound.documentify.reactive.ReactiveDocumentContextEnvironment import org.springframework.http.MediaType import org.springframework.http.codec.json.Jackson2JsonDecoder import org.springframework.http.codec.json.Jackson2JsonEncoder @@ -15,7 +14,7 @@ import org.springframework.web.reactive.result.method.HandlerMethodArgumentResol class StandaloneReactiveContextEnvironment private constructor( private val provider: RestDocumentationContextProvider -) : AbstractStandaloneContextEnvironment(), ReactiveDocumentContextEnvironment { +) : AbstractStandaloneContextEnvironment() { private val argumentResolvers = mutableListOf() fun argumentResolver(argumentResolver: HandlerMethodArgumentResolver): StandaloneReactiveContextEnvironment { @@ -33,7 +32,7 @@ class StandaloneReactiveContextEnvironment private constructor( return this } - override fun buildWebTestClient(): WebTestClient { + override fun buildTestClient(): WebTestClient { return WebTestClient .bindToController(*controllers.toTypedArray()) .controllerAdvice(*controllerAdvices.toTypedArray()) @@ -56,12 +55,6 @@ class StandaloneReactiveContextEnvironment private constructor( .build() } - companion object { - fun standaloneEnvironment(provider: RestDocumentationContextProvider): StandaloneReactiveContextEnvironment { - return StandaloneReactiveContextEnvironment(provider) - } - } - private fun WebTestClient.Builder.include(objectMapper: ObjectMapper?): WebTestClient.Builder { if (objectMapper == null) return this return exchangeStrategies(ExchangeStrategies.builder().codecs { configurer -> @@ -69,4 +62,10 @@ class StandaloneReactiveContextEnvironment private constructor( configurer.defaultCodecs().jackson2JsonEncoder(Jackson2JsonEncoder(objectMapper, MediaType.APPLICATION_JSON)) }.build()) } + + companion object { + fun standaloneEnvironment(provider: RestDocumentationContextProvider): StandaloneReactiveContextEnvironment { + return StandaloneReactiveContextEnvironment(provider) + } + } } \ No newline at end of file diff --git a/documentify-sample/build.gradle.kts b/documentify-sample/build.gradle.kts index 6356593..29645d8 100644 --- a/documentify-sample/build.gradle.kts +++ b/documentify-sample/build.gradle.kts @@ -9,6 +9,7 @@ subprojects { dependencies { implementation(rootProject.libs.jackson.kotlin) testImplementation(rootProject.libs.spring.boot.starter.test) + testImplementation(rootProject.libs.spring.restdocs.webtestclient) testImplementation(rootProject.libs.mockk) } } \ No newline at end of file diff --git a/documentify-sample/reactive-sample/src/test/kotlin/io/github/bgmsound/documentify/sample/reactive/documentation/DateParseSampleDocs.kt b/documentify-sample/reactive-sample/src/test/kotlin/io/github/bgmsound/documentify/sample/reactive/documentation/DateParseSampleDocs.kt deleted file mode 100644 index b63a339..0000000 --- a/documentify-sample/reactive-sample/src/test/kotlin/io/github/bgmsound/documentify/sample/reactive/documentation/DateParseSampleDocs.kt +++ /dev/null @@ -1,32 +0,0 @@ -package io.github.bgmsound.documentify.sample.reactive.documentation - -import io.github.bgmsound.documentify.reactive.Documentify -import io.github.bgmsound.documentify.sample.reactive.controller.DateParseSampleController -import kotlinx.coroutines.test.runTest -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Test -import org.springframework.restdocs.RestDocumentationContextProvider - -class DateParseSampleDocs : Documentify() { - private val api = DateParseSampleController() - - @BeforeEach - fun setUp(provider: RestDocumentationContextProvider) { - standalone(provider) { - controller(api) - } - } - - @Test - fun dateParseSampleApi() = runTest { - documentation("Date Parse Sample API") { - information { - description("this is Date Parse Sample API description") - tag("date-parse") - } - requestLine(io.github.bgmsound.documentify.core.specification.schema.Method.GET, "/date-parse-sample") { - queryParameter("time", "time", "2024-01-01 12:00:00") - } - } - } -} \ No newline at end of file diff --git a/documentify-sample/reactive-sample/src/test/kotlin/io/github/bgmsound/documentify/sample/reactive/documentation/SnakeSampleDocs.kt b/documentify-sample/reactive-sample/src/test/kotlin/io/github/bgmsound/documentify/sample/reactive/documentation/SnakeSampleDocs.kt deleted file mode 100644 index ea34d20..0000000 --- a/documentify-sample/reactive-sample/src/test/kotlin/io/github/bgmsound/documentify/sample/reactive/documentation/SnakeSampleDocs.kt +++ /dev/null @@ -1,51 +0,0 @@ -package io.github.bgmsound.documentify.sample.reactive.documentation - -import com.fasterxml.jackson.databind.ObjectMapper -import com.fasterxml.jackson.databind.PropertyNamingStrategies -import com.fasterxml.jackson.module.kotlin.KotlinModule -import io.github.bgmsound.documentify.core.specification.schema.Method -import io.github.bgmsound.documentify.reactive.Documentify -import io.github.bgmsound.documentify.sample.reactive.controller.SampleController -import kotlinx.coroutines.test.runTest - -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Test -import org.springframework.http.HttpStatus -import org.springframework.restdocs.RestDocumentationContextProvider - -class SnakeSampleDocs : Documentify() { - private val api = SampleController() - private val objectMapper = ObjectMapper().apply { - propertyNamingStrategy = PropertyNamingStrategies.SNAKE_CASE - registerModules(KotlinModule.Builder().build()) - } - - @BeforeEach - fun setUp(provider: RestDocumentationContextProvider) { - standalone(provider) { - controller(api) - codec(objectMapper) - } - } - - @Test - fun samplePostApi() = runTest { - documentation("Snake Sample Post API") { - information { - summary("Snake Sample Post API") - description("this is Sample API description") - tag("flat") - } - requestLine(Method.POST, "/sample") - requestBody { - field("integer_field", "integerField", 1) - field("string_field", "stringField", "string") - } - responseStatus(HttpStatus.OK) - responseBody { - field("integer_field", "integerField", 1) - field("string_field", "stringField", "string") - } - } - } -} \ No newline at end of file diff --git a/documentify-starters/documentify-starter-mvc/build.gradle.kts b/documentify-starters/documentify-starter-mvc/build.gradle.kts index 6dfce7b..902c5e5 100644 --- a/documentify-starters/documentify-starter-mvc/build.gradle.kts +++ b/documentify-starters/documentify-starter-mvc/build.gradle.kts @@ -1,10 +1,5 @@ dependencies { api(projects.documentifyProject.documentifyCore) api(projects.documentifyProject.documentifyMvc) - api(libs.spring.restdocs.mockmvc) - api(libs.spring.restdocs.restassured) - api(libs.restassured.mockmvc) - api(libs.restdocs.api.spec) - api(libs.restdocs.api.spec.mockmvc) - api(libs.restdocs.api.spec.restassured) + api(libs.spring.restdocs.webtestclient) } \ No newline at end of file diff --git a/documentify-starters/documentify-starter-reactive/build.gradle.kts b/documentify-starters/documentify-starter-reactive/build.gradle.kts index c86d46c..4a84d36 100644 --- a/documentify-starters/documentify-starter-reactive/build.gradle.kts +++ b/documentify-starters/documentify-starter-reactive/build.gradle.kts @@ -2,6 +2,4 @@ dependencies { api(projects.documentifyProject.documentifyCore) api(projects.documentifyProject.documentifyReactive) api(libs.spring.restdocs.webtestclient) - api(libs.restdocs.api.spec) - api(libs.restdocs.api.spec.webtestclient) } \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index d70ccca..50eb399 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,7 +1,7 @@ project.name=documentify project.group=io.github.bgmsound -project.version.id=1.3.9 +project.version.id=1.3.10 project.artifact=documentify project.description=Documentify is a tool to generate API documentation from source code. diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a38cd7c..ebd2888 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -6,12 +6,11 @@ kotlinx-coroutines = "1.8.1" kotlinx-kover = "0.9.1" spring-boot = "3.4.1" -spring-restdocs = "3.0.3" +spring-restdocs = "3.0.5" spring-dependency-management = "1.1.5" jackson = "2.17.2" restdocs-api-spec = "0.19.4" -restassured = "5.5.0" mockk = "1.13.13" [libraries] @@ -28,8 +27,6 @@ spring-boot-starter-web = { group = "org.springframework.boot", name = "spring-b spring-boot-starter-webflux = { group = "org.springframework.boot", name = "spring-boot-starter-webflux", version.ref = "spring-boot" } spring-boot-starter-test = { group = "org.springframework.boot", name = "spring-boot-starter-test", version.ref = "spring-boot" } spring-boot-dependencies = { group = "org.springframework.boot", name = "spring-boot-dependencies", version.ref = "spring-boot" } -spring-restdocs-restassured = { group = "org.springframework.restdocs", name = "spring-restdocs-restassured", version.ref = "spring-restdocs" } -spring-restdocs-mockmvc = { group = "org.springframework.restdocs", name = "spring-restdocs-mockmvc", version.ref = "spring-restdocs" } spring-restdocs-webtestclient = { group = "org.springframework.restdocs", name = "spring-restdocs-webtestclient", version.ref = "spring-restdocs" } jackson-databind = { group = "com.fasterxml.jackson.core", name = "jackson-databind", version.ref = "jackson" } @@ -37,12 +34,9 @@ jackson-datatype-jsr310 = { group = "com.fasterxml.jackson.datatype", name = "ja jackson-dataformat-yaml = { group = "com.fasterxml.jackson.dataformat", name = "jackson-dataformat-yaml", version.ref = "jackson" } jackson-kotlin = { group = "com.fasterxml.jackson.module", name = "jackson-module-kotlin", version.ref = "jackson" } restdocs-api-spec = { group = "com.epages", name = "restdocs-api-spec", version.ref = "restdocs-api-spec" } -restdocs-api-spec-mockmvc = { group = "com.epages", name = "restdocs-api-spec-mockmvc", version.ref = "restdocs-api-spec" } -restdocs-api-spec-restassured = { group = "com.epages", name = "restdocs-api-spec-restassured", version.ref = "restdocs-api-spec" } restdocs-api-spec-webtestclient = { group = "com.epages", name = "restdocs-api-spec-webtestclient", version.ref = "restdocs-api-spec" } restdocs-api-spec-gradlePlugin = { group = "com.epages.restdocs-api-spec", name = "com.epages.restdocs-api-spec.gradle.plugin", version.ref = "restdocs-api-spec" } mockk = { group = "io.mockk", name = "mockk", version.ref = "mockk" } -restassured-mockmvc = { group = "io.rest-assured", name = "spring-mock-mvc", version.ref = "restassured" } [bundles] kotlinx-ecosystem = ["kotlinx-datetime", "kotlinx-serialization", "kotlinx-coroutines"]