OpenAPITools / OpenAPITools/openapi-generator

[BUG][spring] HATEAOS is not compatible with main openapi objective

Open
#13,577 6 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Issue: Bug
Dominant language
Java
Stars
26.8k
Forks
7.7k
PR merge metrics
PR metrics pending

Description

Bug Report Checklist
  • Have you provided a full/minimal spec to reproduce the issue?
  • Have you validated the input using an OpenAPI validator (example)?
  • Have you tested with the latest master to confirm the issue still exists?
  • Have you searched for related issues/PRs?
  • What's the actual output vs expected output? => Actual: Undocumented API or compilation error, Expected: Well documented API that compiles
  • [Optional] Sponsorship to speed up the bug fix or feature request (example)
Description

Main openapi objective described here: https://spec.openapis.org/oas/v3.1.0.html#abstract includes:

The OpenAPI Specification (OAS) defines a standard, programming language-agnostic interface description for HTTP APIs, which allows both humans and computers to discover and understand the capabilities of a service without requiring access to source code, additional documentation, or inspection of network traffic. [...]

But if we decide to use spring generator and opt-in hateoas things get complicated.

If we go with basic definition of API spec (simplified pet store) & config - placed below. Then we got API that compiles 🥳, but at the same time is undiscoverable 😭.

Because if we do "implement" findPetsByStatus like this return ResponseEntity.ok().body(List.of(new Pet())); then such request: curl -X GET -i 'http://localhost:8080/pet/findByStatus?status=available' returns [{"links":[],"id":null,"name":null,"category":null,"photoUrls":[],"tags":null,"status":null}].

(yeah I know this is NOT HAL representation, but probably can be changed by spring configuration)
Now we have some part of return value (links) not documented in openapi. But as we like api-first approach and generating client and server from one definition then only one option remains. Add Links to definition:

just add:

        links:
          $ref: '#/components/schemas/Links'

to pet properties, and components:

    Link:
      description: ''
      type: string
    Links:
      description: ''
      type: object
      properties:
        next:
          $ref: '#/components/schemas/Link'
          description: ''

And we will get:

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.10.1:compile (default-compile) on project test: Compilation failure
[ERROR] tmp/pet/src/main/java/com/test/model/Pet.java:[237,23] getLinks() in com.test.model.Pet cannot override getLinks() in org.springframework.hateoas.RepresentationModel
[ERROR]   return type @javax.validation.Valid com.test.model.Links is not compatible with org.springframework.hateoas.Links

If I understand correctly here we should be rescued by https://openapi-generator.tech/docs/usage/#type-mappings-and-import-mappings

but when we add to config:

importMappings:
  Links: "org.springframework.hateoas.Links"

We ended up with API that compiles 🥳 and is discoverable 🥳. Sadly 😭now we have

public class Pet extends RepresentationModel<Pet>  {
//[...]
  @JsonProperty("links")
  private Links links;

generated as Pet model but RepresentationModel has itself:

private final List<Link> links;

Now "builder" API of Pet mixes up with RepresentationModel API and nothing is straightforward for now on. Even worse RepresentationModel API is useless as its property (links) won't end up in JSON.

openapi-generator version

Both docker's v6.1.0 and latest (master)

OpenAPI declaration file content or url

https://gist.github.com/plblueraven/9d844001829d3548f62990cd41a24392 - basic
https://gist.github.com/plblueraven/f1e0481427ae99f980e6d96d963ce845 - with links

Generation Details

Generate server using docker run --rm -v "${PWD}/${generatedApiDirectoryRelativeLocation}:/generated-api" -v "${PWD}/${apiDefinitionFileRelativeLocation}:/spec/api.yaml" -v "${PWD}/${apiGeneratorConfigFileRelativeLocation}:/config.yaml" openapitools/openapi-generator-cli:latest generate -c /config.yaml

With such (effectively) config.yaml:

inputSpec: /spec/api.yaml
outputDir: generated-api
generatorName: spring
additionalProperties:
  apiPackage: com.test
  modelPackage: com.test.model
  supportingFilesToGenerate: "ApiUtil.java"
  groupId: com.test
  artifactId: test
  artifactVersion: 0.0.0
  hateoas: true

or this one:

inputSpec: /spec/api.yaml
outputDir: generated-api
generatorName: spring
importMappings:
  Links: "org.springframework.hateoas.Links"
additionalProperties:
  apiPackage: com.test
  modelPackage: com.test.model
  supportingFilesToGenerate: "ApiUtil.java"
  groupId: com.test
  artifactId: test
  artifactVersion: 0.0.0
  hateoas: true
Steps to reproduce

Generate server with above config and later go to generated directory and run mvn spring-boot:run.

Related issues/PRs

#1130

Suggest a fix

Make hateoas option in spring generator compatible with main openapi objective? IMO way that it should be done needs discussion.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing both configurations with the spring generator, then compare the generated Pet.java model with Spring HATEOAS RepresentationModel and the Maven compilation output. The basic and Links OpenAPI declarations and the docker generation command provide the reproduction path. Done requires a decided compatibility approach that generates a compiling, documented API without conflicting links behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
java, openapi, spring
Domain
api, backend
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.