Core modules

Core modules for Spring Boot microservices

Spring Middleware core modules provide the stable foundation used across the platform. They cover annotation contracts, runtime application wiring, shared infrastructure helpers, and view transformation utilities for Spring Boot microservices.

API contracts Application wiring Shared utilities Request logging Declarative clients Role-based views

What the core provides

The core is the shared platform foundation. It contains the small, stable contracts and runtime helpers that the rest of Spring Middleware builds on top of.

  • Common annotations and contracts
  • Application-level Spring wiring and filters
  • Shared utilities, exceptions, and converters
  • View transformation and role-based shaping

Core module families

  • api: annotation contracts and stable primitives
  • app: runtime wiring, filters, controllers, and boot helpers
  • commons: shared utilities, config, error model, and converters
  • view: response shaping and role-based view helpers

High-level core view

The core modules are intentionally small and focused. Stable annotations live in api, runtime Spring wiring lives in app, shared helpers live in commons, and response shaping lives in view.

User Service api app commons view Shared platform foundation for the rest of Spring Middleware

API module

The api module contains stable annotations and simple contracts that other modules and user services depend on.

Purpose

Keep the public surface annotation-driven and stable. This is where declarative middleware contracts, registry markers, GraphQL annotations, and client security annotations belong.

Key annotations

  • @MiddlewareContract and @MiddlewareContractConnection
  • @MiddlewareCircuitBreaker
  • @Register and @RegisterSchema
  • @GraphQLLink, @GraphQLType, @GraphQLCustomScalar
  • @MiddlewareApiKey, @MiddlewarePassthrough, @MiddlewareClientCredentials

App module

The app module contains most of the runtime wiring used by bootable services. If a helper is expected to exist as a Spring-managed runtime component, it usually belongs here.

Client wiring

Declarative client analysis, proxy configuration, resilience registries, and security appliers live under the client packages.

Web filters and logging

Request context propagation, request/response logging, and forced logging helpers are part of the application runtime layer.

Registration and lifecycle

Bootstrap registration, managers, GraphQL integration, schedulers, controllers, and error handling helpers are exposed here.

Representative runtime classes

  • RegistryClient
  • ProxyClientAnalyzer
  • ClusterCircuitBreakerRegistry
  • ClusterBulkheadRegistry
  • RequestLoggingFilter
  • LogRequestResponse

When to use app

Use app for Spring Boot auto-configuration, filters, runtime managers, and shared Spring-managed components that services should get out of the box.

Commons module

The commons module centralizes small shared helpers used across modules, keeping duplication low and the rest of the codebase more focused.

Config and environment

Property helpers, configuration classes, and environment resolution utilities used by the rest of the platform.

Error model and exceptions

Unified error model classes, exception utilities, and shared error abstractions used across HTTP, GraphQL, and service communication.

Converters and utilities

General converters, validation constraints, controller helpers, and shared utility code that do not belong in more specialized modules.

View module

The view module provides response shaping helpers so controllers can stay thin while role-based representation logic remains centralized.

What it does

  • Role-based response shaping
  • View adaptors and transformation helpers
  • Context-aware property filtering
  • Centralized API representation logic

Key classes

  • View
  • DataAdaptor
  • PropertyRolesAllowedAuthorizer
  • ContextFilterPredicate

Common configuration points

The core modules expose configuration that services commonly use for logging, middleware clients, resilience, and outbound client security.

Request and response logging

middleware:
  log:
    apiKey: ${MIDDLEWARE_LOG_API_KEY:}
    request:
      enabled: true
    response:
      enabled: true
    responseTime:
      enabled: false
    exclude:
      urlPatterns:
        - "/actuator/**"
        - "/health/**"

Client defaults and resilience

middleware:
  client:
    registry-endpoint: ${REGISTRY_ENDPOINT:http://localhost:8080/registry}
    defaultMaxConcurrent: 25
    product:
      connection:
        timeout: 30000
        max-connections: 50
        max-concurrent-calls: 200
        max-retries: 3
        retry-backoff-millis: 1000
      circuit-breaker:
        enabled: true
        failure-rate-threshold: 50
        wait-duration-in-open-state-ms: 10000

What these properties drive

  • middleware.log.* drives request/response logging behavior
  • middleware.client.*.connection.* maps to middleware client connection settings
  • middleware.client.*.circuit-breaker.* configures resilience registries
  • middleware.client.*.security.* configures outbound client authentication

Forced logging

Sending a request with X-Logging-Key matching the configured middleware.log.apiKey forces request/response logging even when INFO-level logging would otherwise be suppressed.

Middleware contract example

The core modules work together around annotation-driven contracts. A declarative client can define connection, resilience, and security behavior through the api annotations, while the app module handles runtime wiring.

@MiddlewareContract example

@MiddlewareContract(
  name = "product",
  connection = @MiddlewareContractConnection(
    timeout = "${middleware.client.product.connection.timeout:30000}",
    maxConnections = "${middleware.client.product.connection.max-connections:50}",
    maxConcurrentCalls = "${middleware.client.product.connection.max-concurrent-calls:200}",
    maxRetries = "${middleware.client.product.connection.max-retries:3}",
    retryBackoffMillis = "${middleware.client.product.connection.retry-backoff-millis:1000}"
  ),
  circuitBreaker = @MiddlewareCircuitBreaker(
    enabled = "${middleware.client.product.circuit-breaker.enabled:true}",
    failureRateThreshold = "${middleware.client.product.circuit-breaker.failure-rate-threshold:50}",
    waitDurationInOpenStateMs = "${middleware.client.product.circuit-breaker.wait-duration-in-open-state-ms:10000}",
    slidingWindowSize = "${middleware.client.product.circuit-breaker.sliding-window-size:20}",
    minimumNumberOfCalls = "${middleware.client.product.circuit-breaker.minimum-number-of-calls:10}",
    permittedNumberOfCallsInHalfOpenState = "${middleware.client.product.circuit-breaker.permitted-number-of-calls-in-half-open-state:3}",
    statusShouldOpenBreaker = {"${middleware.client.product.circuit-breaker.status-should-open-breaker:5xx}"},
    statusShouldIgnoreBreaker = {"${middleware.client.product.circuit-breaker.status-should-ignore-breaker:4xx}"}
  ),
  security = "${middleware.client.product.security.type:API_KEY}"
)
public interface ProductApiClient {
    @GetMapping("/api/v1/products/{id}")
    ProductDto getProduct(@PathVariable("id") UUID id);
}

Common patterns

Most services interact with the core modules through a few repeated platform patterns.

Declarative middleware clients

Services declare contracts with annotations from api, while runtime wiring and resilience live in app.

Request logging and forced logging

The logging filter and its helpers combine property-driven behavior with a header-based forced logging mechanism for incident debugging.

Unified error propagation

The shared error abstractions from commons integrate with HTTP and GraphQL handling through the runtime wiring in app.

Design guidance

The core is intentionally focused. Public APIs should stay stable and annotation-driven, while runtime complexity should remain in small Spring-managed helpers.

Keep api stable

Prefer adding a small annotation and a focused helper contract instead of exposing a large mutable runtime API surface.

Use app for runtime wiring

Spring-managed runtime helpers, auto-configuration, filters, and managers belong in app.

Centralize shared helpers in commons

If a helper is reused across modules, place it in commons rather than duplicating it in specialized modules.

Where to look in the code

The core area is spread across the main foundational modules of the repository.

API annotations

api module

.../api/src/main/java/io/github/spring/middleware/annotation

Application wiring

app module

.../app/src/main/java/io/github/spring/middleware

Shared utilities

commons module

.../commons/src/main/java/io/github/spring/middleware

View helpers

view module

.../view/api/src/main/java/io/github/spring/middleware/view