Проект демонстрирует подход API-First для разработки микросервисов с использованием Spring Boot и Kotlin.
Для просмотра архитектуры запустите structurizr:
./run-c4.sh- Admin Service (
admin-service-app) - REST API для управления отчетами - Report Generator Service - Модульная архитектура для генерации отчетов:
report-generator-service-api- API интерфейсы и моделиreport-generator-service-app- REST API приложениеreport-generator-service-sdk- SDK для клиентовreport-generator-service-starter- Spring Boot Starter
- Backend: Spring Boot 3.5.3, Kotlin 2.0.0
- API: REST API (JSON), gRPC
- Documentation: OpenAPI 3.0.3, Swagger UI (springdoc-openapi 2.7.0)
- Code Generation: OpenAPI Generator 7.14.0
- HTTP Clients: Spring HTTP Exchange, OpenFeign
- Testing: JUnit 5, Pact (Consumer-Driven Contract Testing)
- Infrastructure: Docker, Docker Compose, PostgreSQL 17.5
- Java 21+
- Docker & Docker Compose
Все сервисы через Docker Compose:
docker compose up -dОтдельные сервисы через Gradle:
./gradlew admin-service:admin-service-app:bootRun
./gradlew report-generator-service:report-generator-service-app:bootRun- Admin Service: http://localhost:8080
- Report Generator Service: http://localhost:8081
- Pact Broker: http://localhost:9292
Интерактивная документация API:
- Admin Service: http://localhost:8080/swagger-ui.html
- Report Generator Service: http://localhost:8081/swagger-ui.html
- Admin Service: http://localhost:8080/v3/api-docs
- Report Generator Service: http://localhost:8081/v3/api-docs
Admin Service:
./gradlew admin-service:admin-service-app:generateOpenApiReport Generator Service:
./gradlew report-generator-service:report-generator-service-api:generateOpenApiAdmin Service:
- API Interfaces:
build/generated/src/main/kotlin/home/kali/admin/generated/api/ - Models:
build/generated/src/main/kotlin/home/kali/admin/generated/model/ - OpenAPI Contract:
docs/contracts/openapi-admin-service.yaml
Report Generator Service:
- API Interfaces:
build/generated/src/main/kotlin/home/kali/report/generated/api/ - Models:
build/generated/src/main/kotlin/home/kali/report/generated/model/ - OpenAPI Contract:
docs/contracts/openapi-report-generator.yaml
tasks.register<GenerateTask>("generateOpenApi") {
generatorName.set("kotlin-spring")
inputSpec.set("$rootDir/docs/contracts/openapi-admin-service.yaml")
outputDir.set("${layout.buildDirectory.get()}/generated")
apiPackage.set("home.kali.admin.generated.api")
modelPackage.set("home.kali.admin.generated.model")
invokerPackage.set("home.kali.admin.generated.invoker")
}- Создание контракта: Определение API в OpenAPI YAML файле
- Генерация кода: Автоматическая генерация Kotlin интерфейсов и моделей
- Реализация: Реализация сгенерированных интерфейсов в контроллерах
- Документация: Автоматическая генерация Swagger UI из контрактов
1. report-generator-service-api - API контракты
- Генерирует Kotlin интерфейсы и модели из OpenAPI контракта
- Определяет API endpoints и модели данных
- Содержит HttpExchange интерфейсы
- Используется как зависимость другими модулями
2. report-generator-service-app - REST API приложение
- Реализует API интерфейсы из
report-generator-service-api - Содержит контроллеры и бизнес-логику
- Запускаемое Spring Boot приложение
3. report-generator-service-sdk - SDK для клиентов
- Предоставляет готовые HTTP клиенты для взаимодействия с API
- Поддерживает два типа клиентов: OpenFeign и HTTP Exchange
- Автоматическая конфигурация через Spring Boot
4. report-generator-service-starter - Spring Boot Starter
- Автоматическая конфигурация SDK при добавлении зависимости
- Упрощает интеграцию для клиентских приложений
- Следует паттерну Spring Boot Starters
// Конфигурация HTTP Exchange клиента
@Profile("http-exchange")
@Configuration
class InternalReportGeneratorHttpExchangeClientConfiguration {
@Bean
fun reportGeneratorClient(@Value("\${report-generator.url}") url: String): InternalHttpExchangeReportGeneratorApi {
val client = RestClient.builder().baseUrl(url).build()
return HttpServiceProxyFactory
.builderFor(RestClientAdapter.create(client)).build()
.createClient(InternalHttpExchangeReportGeneratorApi::class.java)
}
}
// Использование в сервисе
@Service
class ReportService(
private val reportGeneratorClient: InternalHttpExchangeReportGeneratorApi
) {
fun generateReport(request: GenerateReportRequest): GenerateReportResponse {
return reportGeneratorClient.generateReport(request)
}
}// Конфигурация OpenFeign клиента
@FeignClient(
value = "report-generator-client",
url = "\${report-generator.url}",
configuration = [InternalReportGeneratorClientConfiguration::class]
)
interface InternalReportGeneratorFeignClient : ReportGenerationApi
// Использование в сервисе
@Service
class ReportService(
private val reportGeneratorClient: InternalReportGeneratorFeignClient
) {
fun generateReport(request: GenerateReportRequest): GenerateReportResponse {
return reportGeneratorClient.generateReport(request)
}
}Проект использует Pact для контрактного тестирования между сервисами:
- REST API: Report UI (consumer) ↔ Admin Service (provider)
- gRPC API: Admin Service (consumer) ↔ Report Generator Service (provider)
- URL: http://localhost:9292
- Username:
pact - Password:
password - Database: PostgreSQL 17.5 (port 5435)
Запуск только Pact Broker:
docker compose up pact-broker pact-db -dКоманды:
cd report-ui
# Полный цикл: очистка → тестирование → публикация
npm run pact:full
# Только генерация контрактов
npm run test:pact
# Только публикация контрактов
npm run pact:publish
# Очистка артефактов
npm run pact:cleanСтруктура:
- Тестовые файлы:
src/pact/admin-service.pact.test.js - Фикстуры:
src/pact/fixtures/interactions.js,src/pact/fixtures/test-data.js - Контракты:
pacts/ReportUI-AdminService.json
Покрываемые endpoints:
POST /api/admin/reports- создание отчетаGET /api/admin/reports- получение списка отчетовGET /api/admin/reports/{reportId}- получение деталей отчетаDELETE /api/admin/reports/{reportId}- отмена отчетаGET /api/admin/reports/{reportId}/download- скачивание отчета
Команды:
# Consumer тесты (генерация gRPC контрактов)
./gradlew admin-service:admin-service-app:pactConsumerTest
# Публикация контрактов
./gradlew admin-service:admin-service-app:pactPublishСтруктура:
- Тестовый класс:
src/test/kotlin/home/kali/admin/cdc/ReportGeneratorConsumerTest.kt - Контракты:
build/pacts/AdminService-ReportGeneratorService.json
Покрываемые gRPC методы:
GenerateReport- создание запроса на генерацию отчетаGetReportStatus- получение статуса генерации отчетаCancelReport- отмена генерации отчетаDownloadReport- скачивание готового отчета
Запуск:
./gradlew admin-service:admin-service-app:pactProviderTestСтруктура:
- Тестовый класс:
src/test/kotlin/home/kali/admin/cdc/AdminServicePactProviderTest.kt - State change методы: Настроены для всех состояний из контрактов
- Конфигурация: Загружает контракты из Pact Broker автоматически
Запуск:
./gradlew report-generator-service:report-generator-service-app:pactProviderTest# Consumer тесты (gRPC контракты)
./gradlew admin-service:admin-service-app:pactConsumerTest
# Provider тесты (REST контракты)
./gradlew admin-service:admin-service-app:pactProviderTest
# Публикация контрактов
./gradlew admin-service:admin-service-app:pactPublish
# Полный цикл: consumer + provider + publish
./gradlew admin-service:admin-service-app:pactTest# Provider тесты (gRPC контракты)
./gradlew report-generator-service:report-generator-service-app:pactProviderTest-
REST API Consumer (Report UI → Admin Service):
cd report-ui npm run pact:full -
gRPC Consumer (Admin Service → Report Generator Service):
./gradlew admin-service:admin-service-app:pactConsumerTest ./gradlew admin-service:admin-service-app:pactPublish
-
REST Provider (Admin Service):
./gradlew admin-service:admin-service-app:pactProviderTest
-
gRPC Provider (Report Generator Service):
./gradlew report-generator-service:report-generator-service-app:pactProviderTest
- Pact Broker: http://localhost:9292
- REST контракты: http://localhost:9292/pacts/provider/AdminService/consumer/ReportUI
- gRPC контракты: http://localhost:9292/pacts/provider/ReportGeneratorService/consumer/AdminService