Skip to content

papatil-mdsol/demo-openapi-multi-module

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Demo: Generate Spring Boot APIs into different Maven modules from a single OpenAPI spec

This demo shows how to keep one OpenAPI contract and still generate Spring Boot API code into separate Maven modules by filtering which APIs are generated per module.

Additionally, each module is runnable as its own Spring Boot application (no separate “app module”).


Key idea (Option B)

  • Keep a single OpenAPI spec: doc/contract/openapi.yaml
  • Group endpoints using OpenAPI tags
    • tags: [ModuleA] → generates API group ModuleA (e.g., ModuleAApi)
    • tags: [ModuleB] → generates API group ModuleB (e.g., ModuleBApi)
  • Run the OpenAPI generator twice (once per module) against the same spec, filtering by API group:
    • module-a-api generates only ModuleA
    • module-b-api generates only ModuleB

Generator: org.openapitools:openapi-generator-maven-plugin
Filter mechanism: globalProperties.apis


Project structure

demo-openapi-multi-module/
├── pom.xml
├── doc/
│   └── contract/
│       └── openapi.yaml
├── module-a-api/
│   ├── pom.xml
│   └── src/main/java/
│       └── com/example/demo/modulea/
│           ├── ModuleAApiApplication.java
│           └── impl/ModuleAApiControllerImpl.java
└── module-b-api/
    ├── pom.xml
    └── src/main/java/
        └── com/example/demo/moduleb/
            ├── ModuleBApiApplication.java
            └── impl/ModuleBApiControllerImpl.java

OpenAPI contract location

Contract file:

  • doc/contract/openapi.yaml

The spec should tag operations like:

  • /a/... endpoints tagged ModuleA
  • /b/... endpoints tagged ModuleB

With useTags=true, the generator groups operations by tag and typically creates interfaces like:

  • ModuleAApi
  • ModuleBApi

Module generation configuration

Both modules point to the same inputSpec but filter on different API groups:

module-a-api

  • inputSpec=../doc/contract/openapi.yaml
  • globalProperties.apis=ModuleA

module-b-api

  • inputSpec=../doc/contract/openapi.yaml
  • globalProperties.apis=ModuleB

This ensures each module only generates its own API interfaces/controllers.


Spring Boot main classes inside each module

Instead of a separate runnable app module, each API module contains its own Spring Boot entry point.

Module A main class

module-a-api/src/main/java/com/example/demo/modulea/ModuleAApiApplication.java

Configured to scan only Module A packages so only Module A controllers are loaded:

@SpringBootApplication(scanBasePackages = "com.example.demo.modulea")

Module B main class

module-b-api/src/main/java/com/example/demo/moduleb/ModuleBApiApplication.java

Scans only Module B packages:

@SpringBootApplication(scanBasePackages = "com.example.demo.moduleb")

Controller implementations

Each module implements its generated interface in a Spring @RestController, e.g.:

  • Module A: ModuleAApiControllerImpl implements ModuleAApi
  • Module B: ModuleBApiControllerImpl implements ModuleBApi

Note: exact method names/signatures depend on generator settings. Always match the generated interface method signature.


Build

From repository root:

mvn clean install

This will:

  • generate sources for module-a-api and module-b-api
  • compile both modules

Run module-a-api

From repository root:

mvn -pl module-a-api spring-boot:run

Test:

curl http://localhost:8080/a/ping

/b/ping should not exist (404), because module B is not running.


Run module-b-api

From repository root:

mvn -pl module-b-api spring-boot:run

Test:

curl http://localhost:8080/b/ping

/a/ping should not exist (404), because module A is not running.


Notes / common gotchas

  1. API naming depends on tags

    • The <apis>ModuleA</apis> and <apis>ModuleB</apis> values must match the generator’s API group names (usually derived from tags).
    • If your generator produces different names (e.g., Modulea), update the filter accordingly.
  2. Models / shared schemas

    • If both modules generate the same model classes, you can get duplicate classes across jars.
    • Common approaches:
      • Generate models in a separate shared-model module (recommended for large specs), OR
      • Disable model generation in leaf modules and depend on a shared jar, OR
      • Accept duplicates if you never run them together (still not ideal).
  3. Ports

    • If you run module A and module B at the same time locally, configure different ports (e.g., --server.port=8081).

Example:

mvn -pl module-b-api spring-boot:run -Dspring-boot.run.arguments=--server.port=8081

About

A minimal demo multi-module Maven project showing Option B: single OpenAPI spec, generate Spring Boot interfaces/controllers into different modules by filtering APIs to generate.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages