Вступление

Если есть сервер, то у него есть api и нужно писать клиент к нему.

Конечно, лучше если клиент пишется автоматически: тогда он актуален и содержит меньше ошибок.

Клиенты для HTTP-протокола сейчас принято писать из OpenAPI-спецификаций. Благо они так же в большинстве случаев генерируются сервером автоматически. А когда почему-то генератор не используют, то содержат ошибки и устарели: не надо так.

Swagger-codegen vs openapi-generator

Есть 2 основных генератора swagger-codegen (изначальный) и openapi-generator (его форк).

Если посравнивать:

И посмотреть сколько скачали:

то однозначно видно, что openapi-generator более популярен и более активно разрабатывается.

Как же сгенерировать клиентскую библиотеку?

docker run --rm -v ${PWD}:/local openapitools/openapi-generator-cli generate \
    -i /local/specs/simple.json \
    -g kotlin \
    --additional-properties enumPropertyNaming=UPPERCASE \
    --additional-properties library=jvm-spring-webclient \
    --additional-properties useSpringBoot3=true \
    --additional-properties serializationLibrary=jackson \
    -o /local/clients/simple

Мы хотим клиент для spring 3 на Котлине.

Чем не устраивает клиент на Java?

  • теряем информацию о null
  • на нужны корутины

Устраивает ли то, что нагенерировано?

Нет:

  • не используются корутины, а значит код перехода на корутины будет в основном приложении – самый большой минус
  • не используются интерфейсы клиентов из Spring 3: хуже читабельность
  • куча какого-то левого кода в infrastructure пакете – лучше использовать внешнюю зависимость (при желании ее легко можно заменить на свою в файлах сборки основного приложения)
  • почему-то ktlint не положили в докер образ и выдают warning об этом (из-за этого неформатированный код)
  • странный подход к типам: почему для котлина пишут kotlin.String, а для java не пишут java.lang.String?

А может в другом проекте лучше?

Нет, там примерно то же самое.

Что же делать?

Дописываем.

Новые параметры:

  • --library=jvm-spring-http-interface --additional-properties useCoroutines=true – включает генерацию интерфейсов с корутинами
  • --global-property apiTests=false,modelTests=false – не генерируем тесты (мусор, т.к. мы не собираемся их запускать)
  • --additional-properties omitInfrastructureClasses=true – не генерируем инфраструктурный код (подключим зависимость к основному проекту)
  • подумал, что не имеет особого смысла подключать зависимость к клиенту, лучше к основному проекту, чтобы потом не заниматься ее исключением
  • добавил ktlint в docker-образ
  • удалил генерацию стандартных имен классов с префиксом kotlin.*

Сборка образа:

cd openapi-generator
docker build . -f .hub.cli.dockerfile -t stepin/openapi-generator-cli

#or
./run-in-docker.sh mvn package
cp docker-entrypoint.sh modules/openapi-generator-cli
cd modules/openapi-generator-cli
docker build . -t stepin/openapi-generator-cli

Запуск образа:

docker run --rm -v ${PWD}:/local stepin/openapi-generator-cli generate \
    -i /local/specs/simple.json \
    -g kotlin \
    --library=jvm-spring-http-interface \
    --additional-properties groupId=name.stepin \
    --additional-properties artifactId=simple-client \
    --additional-properties artifactVersion=0.2.0 \
    --additional-properties packageName=name.stepin.client.simple \
    --additional-properties useSpringBoot3=true \
    --additional-properties useCoroutines=true \
    --additional-properties serializationLibrary=jackson \
    --additional-properties omitInfrastructureClasses=true \
    --additional-properties enumPropertyNaming=UPPERCASE \
    --global-property apiTests=false,modelTests=false \
    -o /local/clients/simple

Пока что это имеет бета-статус: вроде как для меня все работает, но наверняка найдутся какие-то краевые случаи. Плюс, библиотека подключения http interface клиентов в проект понятна и в черновике написана, но еще не опубликована.