OpenAPI кодогенерация
Модуль для создания декларативных HTTP-обработчиков HTTP сервера либо создания декларативных HTTP клиентов из OpenAPI контрактов с использованием OpenAPI Generator плагином.
Подключение¶
Зависимость генератора build.gradle:
Зависимость плагина build.gradle:
Зависимость build.gradle.kts:
Зависимость плагина build.gradle.kts:
Требует подключения HTTP сервера либо HTTP клиента.
Конфигурация¶
Конфигурировать требуется параметры плагина OpenAPI Generator:
- Настройка параметров Gradle плагина в документации.
- Настройка
configOptionsпараметра плагина в документации. - Настройка
openapiNormalizerпараметра плагина в документации.
Клиент¶
Минимальный пример настройки плагина для создания декларативного HTTP клиента:
Доступные Kora параметры плагина (configOptions):
clientConfigPrefix- префикс конфигурации созданных HTTP-клиентов. Значениестрока.tags- возможность проставлять дополнительные теги на созданные HTTP-клиентыinterceptors- возможность указывать перехватчики для HTTP-клиентовadditionalContractAnnotations- возможность указывать дополнительные аннотации над методами HTTP-клиентаprimaryAuth- указать какой механизм авторизации использовать как основной если указано несколько securitySchemes в OpenAPI. Значениестрока.securityConfigPrefix- префикс конфигурации механизм авторизации Basic/ApiKey (путь конфигурации будет заданный префикс + имя securitySchemes в OpenAPI, либо просто имя в OpenAPI если префикс не задан). Значениестрока.authAsMethodArgument- возможность указывать авторизацию как аргумент метода HTTP клиента, а не через перехватчик. Значения:true,falseenableJsonNullable- обрабатыватьnullable=trueиrequired=falseполя схем как JsonNullable обертку. Значения:true,falseforceIncludeOptional- проставлять принудительно@JsonInclude(Always)дляnullable=trueиrequired=falseполей вместоenableJsonNullable. Значения:true,false.forceIncludeNonRequired- проставлять принудительно @JsonInclude(Always) для толькоrequired=falseполей. Значения:true,false.filterWithModels- фильтровать и исключать из генерации также ненужные модели когда указана опция FILTER вopenapiNormalizer. Значения:true,falsemodeв каком режиме работать генератору, доступные значения:java-client- создание синхронного клиентаjava-async-client- создание CompletionStage клиентаjava-reactive-client- создание реактивного клиента, требуется подключить Project Reactor самостоятельно.
def openApiGenerateHttpClient = tasks.register("openApiGenerateHttpClient", GenerateTask) {
generatorName = "kora"
group = "openapi tools"
inputSpec = "$projectDir/src/main/resources/openapi/openapi.yaml" //(1)!
outputDir = "$buildDir/generated/openapi" //(2)!
def corePackage = "ru.tinkoff.kora.example.openapi"
apiPackage = "${corePackage}.api" //(3)!
modelPackage = "${corePackage}.model" //(4)!
invokerPackage = "${corePackage}.invoker" //(5)!
openapiNormalizer = [
DISABLE_ALL: "true"
]
configOptions = [
mode: "java-client", //(6)!
clientConfigPrefix: "httpClient.myclient" //(7)!
]
}
sourceSets.main { java.srcDirs += openApiGenerateHttpClient.get().outputDir } //(8)!
compileJava.dependsOn openApiGenerateHttpClient //(9)!
- Путь до OpenAPI файла из которого будут созданы классы
- Директория куда буду создаваться файлы
- Пакет от классов делегатов, контроллеров, преобразователей и тп.
- Пакет от классов моделей, DTO и тп.
- Пакет от классов вызова
- Режим работы плагина (создание Java клиента / Kotlin / Java сервера и тп)
- Префикс путь к файлу конфигурации клиента
- Регистрируем созданные классы как исходный код проекта
- Делаем компиляцию кода, зависимой от генерации классов HTTP-клиента (сначала генерируем, потом компилируем)
Доступные Kora параметры плагина (configOptions):
clientConfigPrefix- префикс конфигурации созданных HTTP-клиентов. Значениестрока.tags- возможность проставлять дополнительные теги на созданные HTTP-клиентыinterceptors- возможность указывать перехватчики для HTTP-клиентовadditionalContractAnnotations- возможность указывать дополнительные аннотации над методами HTTP-клиентаprimaryAuth- указать какой механизм авторизации использовать как основной если указано несколько securitySchemes в OpenAPI. Значениестрока.securityConfigPrefix- префикс конфигурации механизм авторизации Basic/ApiKey (путь конфигурации будет заданный префикс + имя securitySchemes в OpenAPI, либо просто имя в OpenAPI если префикс не задан). Значениестрока.authAsMethodArgument- возможность указывать авторизацию как аргумент метода HTTP клиента, а не через перехватчик. Значения:true,falseenableJsonNullable- обрабатыватьnullable=trueиrequired=falseполя схем как JsonNullable обертку. Значения:true,falseforceIncludeOptional- проставлять принудительно@JsonInclude(Always)дляnullable=trueиrequired=falseполей вместоenableJsonNullable. Значения:true,false.forceIncludeNonRequired- проставлять принудительно @JsonInclude(Always) для толькоrequired=falseполей. Значения:true,false.filterWithModels- фильтровать и исключать из генерации также ненужные модели когда указана опция FILTER вopenapiNormalizer. Значения:true,falsemodeв каком режиме работать генератору, доступные значения:kotlin-client- создание синхронного клиентаkotlin-suspend-client- создание suspend клиента
val openApiGenerateHttpClient = tasks.register<GenerateTask>("openApiGenerateHttpClient") {
generatorName = "kora"
group = "openapi tools"
inputSpec = "$projectDir/src/main/resources/openapi/openapi.yaml" //(1)!
outputDir = "$buildDir/generated/openapi" //(2)!
val corePackage = "ru.tinkoff.kora.example.openapi"
apiPackage = "${corePackage}.api" //(3)!
modelPackage = "${corePackage}.model" //(4)!
invokerPackage = "${corePackage}.invoker" //(5)!
openapiNormalizer = mapOf(
"DISABLE_ALL" to "true"
)
configOptions = mapOf(
"mode" to "kotlin-client", //(6)!
"clientConfigPrefix" to "httpClient.myclient" //(7)!
)
}
kotlin.sourceSets.main { kotlin.srcDir(openApiGenerateHttpClient.get().outputDir) } //(8)!
tasks.withType<KspTask> { dependsOn(openApiGenerateHttpClient) } //(9)!
- Путь до OpenAPI файла из которого будут созданы классы
- Директория куда буду создаваться файлы
- Пакет от классов делегатов, контроллеров, преобразователей и тп.
- Пакет от классов моделей, DTO и тп.
- Пакет от классов вызова
- Режим работы плагина (создание Java клиента / Kotlin / Java сервера и тп)
- Префикс путь к файлу конфигурации клиента
- Регистрируем созданные классы как исходный код проекта
- Делаем компиляцию кода, зависимой от генерации классов HTTP-клиента (сначала генерируем, потом компилируем)
После создания HTTP-клиент будет доступен для внедрения как зависимость по созданному интерфейсу.
Перехватчики¶
Есть возможность на созданные клиенты с @HttpClient аннотацией поставить перехватчики.
Значение - Json объект, ключом которого выступает тег апи из контракта, а значением объект с полями type и tag,
можно указывать как оба поля одновременно, так и опционально одно из них на выбор где:
type- класс реализации конкретного перехватчикаtag- теги перехватчика (можно указать как массив строк)
Для этого необходимо установить параметр configOptions.interceptors:
Теги¶
Есть возможность на созданные клиенты с @HttpClient аннотацией поставить параметры httpClientTag и telemetryTag.
Значение - Json объект, ключом которого выступает тег апи из контракта, а значением объект с полями httpClientTag и telemetryTag.
Для этого необходимо установить параметр configOptions.tags:
configOptions = [
mode: "java-client",
tags: """
{
"*": { // применится для всех тегов, кроме явно указанных (в данном случае instrument)
"httpClientTag": "some.tag.Common",
"telemetryTag": "some.tag.Common"
},
"instrument": { // применится для instrument
"httpClientTag": "some.tag.Instrument",
"telemetryTag": "some.tag.Instrument"
}
}
"""
]
configOptions = mapOf(
"mode" to "kotlin-client",
"tags" to """{
"*": { // применится для всех тегов, кроме явно указанных (в данном случае instrument)
"httpClientTag": "some.tag.Common",
"telemetryTag": "some.tag.Common"
},
"instrument": { // применится для instrument
"httpClientTag": "some.tag.Instrument",
"telemetryTag": "some.tag.Instrument"
}
}
"""
)
Сервер¶
Минимальный пример настройки плагина для создания обработчиков HTTP-сервера:
Доступные Kora параметры плагина (configOptions):
enableServerValidation- создавать ли валидаторы по описанию OpenAPI сецификации для сервера и включать ли валидацию на HTTP-обработчиках. Значения:true,falserequestInDelegateParams- прокидывать лиHttpServerRequestпринудительно как аргумент метода. Значения:true,falseinterceptors- возможность указывать перехватчики для HTTP-контроллеровadditionalContractAnnotations- возможность указывать дополнительные аннотации над методами контроллераenableJsonNullable- обрабатыватьnullable=trueиrequired=falseполя схем как JsonNullable обертку. Значения:true,falseforceIncludeOptional- проставлять принудительно @JsonInclude(Always) дляnullable=trueиrequired=falseполей вместоenableJsonNullable. Значения:true,false.forceIncludeNonRequired- проставлять принудительно @JsonInclude(Always) для толькоrequired=falseполей. Значения:true,false.filterWithModels- фильтровать и исключать из генерации также ненужные модели когда указана опция FILTER вopenapiNormalizer. Значения:true,falseprefixPath- префикс пути обработчиков HTTP-сервера. Значение:строкаdelegateMethodBodyMode- способ генерации тела метода в delegate классе.none- не генерировать тело метода,throw-exception- бросать исключение в теле метода. Дляthrow-exceptionдополнительно будет сгенерирован модуль со стандартной реализацией Delegate класса, если в графе приложения нет другой реализацииmodeв каком режиме работать генератору, доступные значения:java-server- создание синхронного сервераjava-async-server- создание CompletionStage сервераjava-reactive-server- создание реактивного сервера, требуется подключить Project Reactor самостоятельно.
def openApiGenerateHttpServer = tasks.register("openApiGenerateHttpServer", GenerateTask) {
generatorName = "kora"
group = "openapi tools"
inputSpec = "$projectDir/src/main/resources/openapi/openapi.yaml" //(1)!
outputDir = "$buildDir/generated/openapi" //(2)!
def corePackage = "ru.tinkoff.kora.example.openapi"
apiPackage = "${corePackage}.api" //(3)!
modelPackage = "${corePackage}.model" //(4)!
invokerPackage = "${corePackage}.invoker" //(5)!
openapiNormalizer = [
DISABLE_ALL: "true"
]
configOptions = [
mode: "java-server", //(6)!
]
}
sourceSets.main { java.srcDirs += openApiGenerateHttpServer.get().outputDir } //(7)!
compileJava.dependsOn openApiGenerateHttpServer //(8)!
- Путь до OpenAPI файла из которого будут созданы классы
- Директория куда буду создаваться файлы
- Пакет от классов делегатов, контроллеров, преобразователей и тп.
- Пакет от классов моделей, DTO и тп.
- Пакет от классов вызова
- Режим работы плагина (создание Java клиента / Kotlin / Java сервера и тп)
- Регистрируем созданные классы как исходный код проекта
- Делаем компиляцию кода, зависимой от генерации классов HTTP-сервера (сначала генерируем, потом компилируем)
Доступные Kora параметры плагина (configOptions):
enableServerValidation- создавать ли валидаторы по описанию OpenAPI сецификации для сервера и включать ли валидацию на HTTP-обработчиках. Значения:true,falserequestInDelegateParams- прокидывать лиHttpServerRequestпринудительно как аргумент метода. Значения:true,falseinterceptors- возможность указывать перехватчики для HTTP-контроллеровadditionalContractAnnotations- возможность указывать дополнительные аннотации над методами контроллераenableJsonNullable- обрабатыватьnullable=trueиrequired=falseполя схем как JsonNullable обертку. Значения:true,falseforceIncludeOptional- проставлять принудительно @JsonInclude(Always) дляnullable=trueиrequired=falseполей вместоenableJsonNullable. Значения:true,false.forceIncludeNonRequired- проставлять принудительно @JsonInclude(Always) для толькоrequired=falseполей. Значения:true,false.filterWithModels- фильтровать и исключать из генерации также ненужные модели когда указана опция FILTER вopenapiNormalizer. Значения:true,falseprefixPath- префикс пути обработчиков HTTP-сервера. Значение:строкаdelegateMethodBodyMode- способ генерации тела метода в delegate классе.none- не генерировать тело метода,throw-exception- бросать исключение в теле метода. Дляthrow-exceptionдополнительно будет сгенерирован модуль со стандартной реализацией Delegate класса, если в графе приложения нет другой реализацииmodeв каком режиме работать генератору, доступные значения:kotlin-server- создание синхронного сервераkotlin-suspend-server- создание suspend сервера
val openApiGenerateHttpServer = tasks.register<GenerateTask>("openApiGenerateHttpServer") {
generatorName = "kora"
group = "openapi tools"
inputSpec = "$projectDir/src/main/resources/openapi/openapi.yaml" //(1)!
outputDir = "$buildDir/generated/openapi" //(2)!
val corePackage = "ru.tinkoff.kora.example.openapi"
apiPackage = "${corePackage}.api" //(3)!
modelPackage = "${corePackage}.model" //(4)!
invokerPackage = "${corePackage}.invoker" //(5)!
openapiNormalizer = mapOf(
"DISABLE_ALL" to "true"
)
configOptions = mapOf(
"mode" to "kotlin-server" //(6)!
)
}
kotlin.sourceSets.main { kotlin.srcDir(openApiGenerateHttpServer.get().outputDir) } //(7)!
tasks.withType<KspTask> { dependsOn(openApiGenerateHttpServer) } //(8)!
- Путь до OpenAPI файла из которого будут созданы классы
- Директория куда буду создаваться файлы
- Пакет от классов делегатов, контроллеров, преобразователей и тп.
- Пакет от классов моделей, DTO и тп.
- Пакет от классов вызова
- Режим работы плагина (создание Java клиента / Kotlin / Java сервера и тп)
- Регистрируем созданные классы как исходный код проекта
- Делаем компиляцию кода, зависимой от генерации классов HTTP-сервера (сначала генерируем, потом компилируем)
После создания обработчики будут автоматически зарегистрированы.
Валидация¶
Для генерации моделей и контроллеров с аннотациями из модуля валидации необходимо установить опцию enableServerValidation:
Перехватчики¶
Есть возможность на созданные контроллеры с @HttpController аннотацией поставить перехватчики.
Значение - Json объект, ключом которого выступает тег апи из контракта, а значением объект с полями type и tag,
можно указывать как оба поля одновременно, так и опционально одно из них на выбор где:
type- класс реализации конкретного перехватчикаtag- теги перехватчика (можно указать как массив строк)
Для этого необходимо установить параметр configOptions.interceptors:
Авторизация¶
Kora предоставляет интерфейс для извлечения авторизационной информации в рамках перехватчика, созданного для сервера из OpenAPI, можно вытаскивать любые типы авторизации Basic/ApiKey/Bearer/OAuth
@Module
interface AuthModule {
@Tag(ApiSecurity.BearerAuth::class)
fun bearerHttpServerPrincipalExtractor(): HttpServerPrincipalExtractor<Principal> {
return HttpServerPrincipalExtractor<Principal> { request, value ->
CompletableFuture.completedFuture<Principal>(
MyPrincipal(request.headers().getFirst("Authorization"))
)
}
}
}
Совет¶
Совет
В случае если у вас что-то не создается посредствам плагина, либо поведение отличается от желаемого или других версий, требуется тщательно проверить настройки конфигурации плагина и изучить их, так как они могут влиять на результаты того как создаются классы.
Начиная с 7.0.0 версии плагина, включенное по умолчанию SIMPLIFY_ONEOF_ANYOF правило у параметра openapiNormalizer
может вести к некоторым не очевидным результатам генератора.