Spring Fox＋SwaggerでAPI仕様書作成

# 環境

Spring Boot 2.2.3.RELEASE - 2.2.4.RELEASE
Spring Fox 2.9.2
Kotlin 1.3.61
Gradle

環境は以下の記事のまんま

https://qiita.com/ShassBeleth/items/3f3afca83b8ef0b98ede

# 導入

リファレンスにそって`build.gradle.kts`に追加

```リファレンス.gradle
repositories {
  jcenter()
}

dependencies {
    compile "io.springfox:springfox-swagger2:2.9.2"
}
```

追加してみると

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/195499/b7be59a8-cf01-d829-e178-4615f26be93c.png)

おや？

どうやらdependenciesにcompile書くのは非推奨になったらしい

compileは依存するライブラリがさらに依存してるライブラリも参照できるようになるらしい

これの代わりが`api`。`implementation`はライブラリが依存してるライブラリは参照できない制限付き

gradleのドキュメントにも`implementation`でいいならそっち使えって書いてあるんで

ってことで推奨してる通りに変更

```build.gradle.kts
repositories {
	jcenter()
}

dependencies {
	implementation( "io.springfox:springfox-swagger2:2.9.2")
}
```

おっけーおっけー

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/195499/cdd274dd-75ab-bcd9-5c6e-731b070e0e74.png)

ライブラリもちゃんと入ってるー

---

```build.gradle.kts
repositories {
	mavenCentral()
	jcenter()
}
```

`repositories`は`mavenCentral`より`jcenter`を下に書いたほうがいいのかな？
こいつらからライブラリをとってくるわけだけど、
`repositories`は上から順に優先順位が決まって
`mavenCentral`からとってこれなければ`jcenter`からとってくる
といった具合になるのかなぁ

## クイックスタートにそって書いてみる

```SpringBootExampleApplication.kt
package com.example.spring.boot.web

import com.example.spring.boot.web.sample.HogeController
import com.example.spring.boot.web.sample.SampleController
import com.fasterxml.classmate.TypeResolver
import com.google.common.collect.Lists.newArrayList
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.ComponentScan
import springfox.documentation.swagger2.annotations.EnableSwagger2
import springfox.documentation.service.SecurityReference
import springfox.documentation.builders.PathSelectors
import springfox.documentation.spi.service.contexts.SecurityContext
import springfox.documentation.service.ApiKey
import springfox.documentation.schema.ModelRef
import springfox.documentation.builders.ParameterBuilder
import springfox.documentation.builders.ResponseMessageBuilder
import org.springframework.web.bind.annotation.RequestMethod
import org.springframework.http.ResponseEntity
import org.springframework.web.context.request.async.DeferredResult
import java.time.LocalDate
import springfox.documentation.builders.RequestHandlerSelectors
import springfox.documentation.schema.AlternateTypeRules.newRule
import springfox.documentation.schema.WildcardType
import springfox.documentation.service.AuthorizationScope
import springfox.documentation.service.Tag
import springfox.documentation.spi.DocumentationType
import springfox.documentation.spring.web.plugins.Docket
import springfox.documentation.swagger.web.*

/**
 * エントリポイント
 */
@SpringBootApplication
@EnableSwagger2
@ComponentScan( basePackageClasses = [ SampleController::class , HogeController::class ] )
class SpringBootExampleApplication

/**
 * エントリポイント
 */
fun main(args: Array<String>) {
    SpringApplication(SpringBootExampleApplication::class.java).run(*args)
}

@Autowired
private val typeResolver: TypeResolver? = null

@Bean
fun petApi(): Docket = Docket(DocumentationType.SWAGGER_2)
    .select()
    .apis(RequestHandlerSelectors.any())
    .paths(PathSelectors.any())
    .build()
    .pathMapping("/")
    .directModelSubstitute(LocalDate::class.java, String::class.java)
    .genericModelSubstitutes(ResponseEntity::class.java)
    .alternateTypeRules(
            newRule(
                    typeResolver!!.resolve(
                            DeferredResult::class.java,
                            typeResolver!!.resolve(ResponseEntity::class.java, WildcardType::class.java)
                    ),
                    typeResolver!!.resolve(WildcardType::class.java)
            )
    )
    .useDefaultResponseMessages(false)
    .globalResponseMessage(
            RequestMethod.GET,
            newArrayList(
                    ResponseMessageBuilder()
                            .code(500)
                            .message("500 message")
                            .responseModel(ModelRef("Error"))
                            .build()
            )
    )
    .securitySchemes(newArrayList(ApiKey("mykey", "api_key", "header")))
    .securityContexts(newArrayList(SecurityContext.builder()
            .securityReferences(defaultAuth())
            .forPaths(PathSelectors.regex("/anyPath.*"))
            .build())
    )
    .enableUrlTemplating(true)
    .globalOperationParameters(
            newArrayList(ParameterBuilder()
                    .name("someGlobalParameter")
                    .description("Description of someGlobalParameter")
                    .modelRef(ModelRef("string"))
                    .parameterType("query")
                    .required(true)
                    .build()
            )
    )
    .tags(Tag("Pet Service", "All apis relating to pets"))
//    .additionalModels(typeResolver!!.resolve(AdditionalModel::class.java))

fun defaultAuth(): List<SecurityReference> {
    val authorizationScopes = arrayOfNulls<AuthorizationScope>(1)
    authorizationScopes[0] = AuthorizationScope("global", "accessEverything")
    return newArrayList(SecurityReference("mykey", authorizationScopes))
}

@Bean
fun security(): SecurityConfiguration = SecurityConfigurationBuilder
        .builder()
        .clientId("test-app-client-id")
        .clientSecret("test-app-client-secret")
        .realm("test-app-realm")
        .appName("test-app")
        .scopeSeparator(",")
        .additionalQueryStringParams(null)
        .useBasicAuthenticationWithAccessCodeGrant(false)
        .build()

@Bean
fun uiConfig(): UiConfiguration = UiConfigurationBuilder
        .builder()
        .deepLinking(true)
        .displayOperationId(false)
        .defaultModelsExpandDepth(1)
        .defaultModelExpandDepth(1)
        .defaultModelRendering(ModelRendering.EXAMPLE)
        .displayRequestDuration(false)
        .docExpansion(DocExpansion.NONE)
        .filter(false)
        .maxDisplayedTags(null)
        .operationsSorter(OperationsSorter.ALPHA)
        .showExtensions(false)
        .tagsSorter(TagsSorter.ALPHA)
        .supportedSubmitMethods(UiConfiguration.Constants.DEFAULT_SUBMIT_METHODS)
        .validatorUrl(null)
        .build()
```

一通りKotlinに変換
動かしてみても何も出ない・・・

## springfox-swagger-uiで表示してみる

```build.gradle.kt
dependencies {
    implementation( "io.springfox:springfox-swagger-ui:2.9.2" )
}
```
追加ー

これまたリファレンスは`compile`だったのを`implementation`に置き換えとく

## Webを立ち上げてみる

これで`http://localhost:8080/swagger-ui.html`でAPIリファレンスが見れるようになった

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/195499/ae228415-2294-2825-195e-1b3c977a592a.png)


いえーい