package-names from location

The package-names from location feature allows the processor to create package names based on the file location of $ref’erenced parts of the OpenAPI description.

This gets enabled by setting the package-names:location option.

package-names:location

package-names:location is the parent package for location based package names.

Only (OpenAPI) file locations below the parent package will be generated with a location based package name. Any other (OpenAPI) file location will use package-names.base (or package-name) as the package name.

Enabling this has a few conditions:

  • to create an interface or resource in a specific package, its OpenAPI description has to be in the target package and must be reachable from the root OpenAPI description.

  • it only works with the INTERNAL OpenAPI parser (it is the default parser). It will not work with the SWAGGER OpenAPI parser.

mapping.yaml

The first step is to enable the feature in the mapping.yaml:

mapping.yaml
openapi-processor-mapping: v13

options:
  # this must be a parent package of the target packages
  #package-name: io.openapiprocessor.openapi  (1)

  package-names:
    base: io.openapiprocessor.openapi (2)
    # this enables package generation from the endpoint $ref file location
    location:  io.openapiprocessor.samples (3)
1 the shortcut for setting package-names.base. If location based packages should be used, setting package-names.base is preferred.
2 this is the base package for all generated code. This is identical to the current behaviour (i.e. package-name). Any file the is not below package-names.location will be generated with this as the base package.
3 package-name.location is the parent package name of the project’s target packages. If the processor finds a file ref’erenced from the main OpenAPI in a subpackage of package-name.location the generated sources will be generated with that package.

OpenAPI and $refs

The second step is to split the OpenAPI definition into multiple files and place them into the desired packages.

The openapi.yaml is placed into the usual place, in this example in the source folder src/api.

openapi.yaml
openapi: 3.1.0
info:
  title: openapi-processor-spring sample api
  version: 1.0.0

servers:
  - url: "https://openapiprocessor.io/{path}"
    variables:
      path:
        default: api

paths:
  /foo:
    $ref: '../main/kotlin/io/openapiprocessor/samples/foo/foo.yaml' (1)

The project directories so far look like this, where sample is the root folder of the project.

directory structure, api
sample
\---- src
      \---- api
            +---- mapping.yaml
            \---- openapi.yaml

foo endpoint $ref

The foo path item in openapi.yaml $ref’erences the endpoint definition in foo.yaml.

foo.yaml
post:
  tags:
    - foo
  summary: echo a Foo.
  description: simple sample endpoint
  requestBody:
    $ref: 'resources.yaml#/FooBody'
  responses:
    '200':
      description: foo
      content:
        application/json:
          schema:
            $ref: 'resources.yaml#/Foo'

foo.yaml is placed into the main source folder of the project into the target package the generated interface should have.

In this case the target package of FooApi.java will be io.openapiprocessor.samples.foo

The controller implementation and services for this endpoint will go into the same package.

foo.yaml also $ref’erences a resources.yaml file placed in the same package that defines the Foo payload schema:

resources.yaml
FooBody:
  content:
    application/json:
      schema:
        $ref: '#/Foo'

Foo:
  type: object
  description: Foo object description
  properties:
    foo:
      type: string
      maxLength: 10
      description: foo property description
    id:
      type: string
      format: uuid
      description: id property description

The final directory structure then looks like this:

directory structure, api and sources
sample
\---- src
      +---- api
      |     +---- mapping.yaml
      |     \---- openapi.yaml
      \---- main
            +---- kotlin
            |     \---- io
            |           \---- openapiprocessor
            |                 \---- samples
            |                       +---- foo
            |                       |     +---- FooController.kt
            |                       |     +---- foo.yaml
            |                       |     \---- resources.yaml
            |                       +---- bar
            |                       |      \---- ...
            |                       \ Application.kt
            \---- resources
                  \---- application.properties

parent package name

Having an idea now how the files are organized, it is possible to explain which package is the parent package.

From the file tree above:

The package name of the foo endpoint files is io.openapiprocessor.samples.foo and the nearest parent package is io.openapiprocessor.samples. This is then the package-names.location option value.

It is possible to use io.openapiprocessor or even io as the parent package.

directory structure after processing

Assuming a Gradle build, the directory structure after processing is:

sample
+---- build
|     \---- openapi
|            +--- java
|            |    \---- io
|            |          \---- openapiprocessor
|            |                \---- samples
|            |                      +---- foo
|            |                      |     +---- Foo.java
|            |                      |     \---- FooApi.java
|            |                      \---- bar
|            |                            \---- ...
|            \---- resources
|                  \---- api.properties
\---- src
      +---- api
      |     +---- mapping.yaml
      |     \---- openapi.yaml
      \---- main
            +---- kotlin
            |     +---- io
            |     |     \---- openapiprocessor
            |     |           \---- samples
            |     |                 +---- foo
            |     |                 |     +---- FooController.kt
            |     |                 |     +---- foo.yaml
            |     |                 |     \---- resources.yaml
            |     |                 \---- bar
            |     |                       \---- ...
            \---- resources
                  \---- application.properties

sample code

A full working example with multiple endpoints is available in the samples repository.