cjbooms / fabrikt

Generates Kotlin Code from OpenApi3 Specifications
Apache License 2.0
152 stars 39 forks source link

JSDelivr OpenAPI spec fails #262

Closed avwie closed 7 months ago

avwie commented 7 months ago

I am trying to generate https://data.jsdelivr.com/v1/spec.yaml, however it fails for Fabrikt on:

INFO: Generating code and dumping to /Users/avanwieringen/Development/private/kotlin/ktor-wired/utils/jsdelivr-client/build/generated/
Exception in thread "main" java.lang.IllegalArgumentException: The Kaizen openapi-parser library threw a NPE exception when parsing this API. This is commonly due to an external schema reference that is unresolvable, possibly due to a lack of internet connection
    at com.cjbooms.fabrikt.util.YamlUtils.parseOpenApi(YamlUtils.kt:41)
    at com.cjbooms.fabrikt.model.SourceApi.<init>(SourceApi.kt:35)
    at com.cjbooms.fabrikt.model.SourceApi$Companion.create(SourceApi.kt:31)
    at com.cjbooms.fabrikt.cli.CodeGen.generate(CodeGen.kt:66)
    at com.cjbooms.fabrikt.cli.CodeGen.main(CodeGen.kt:22)
Caused by: java.lang.NullPointerException: Cannot invoke "java.lang.CharSequence.length()" because "this.text" is null
    at java.base/java.util.regex.Matcher.getTextLength(Matcher.java:1769)
    at java.base/java.util.regex.Matcher.reset(Matcher.java:415)
    at java.base/java.util.regex.Matcher.<init>(Matcher.java:252)
    at java.base/java.util.regex.Pattern.matcher(Pattern.java:1134)
    at com.reprezen.kaizen.oasparser.val.ValidatorBase.checkPattern(ValidatorBase.java:99)
    at com.reprezen.kaizen.oasparser.val.ValidatorBase.validateStringField(ValidatorBase.java:89)
    at com.reprezen.kaizen.oasparser.val.ValidatorBase.validateStringField(ValidatorBase.java:79)
    at com.reprezen.kaizen.oasparser.val3.SchemaValidator.runObjectValidations(SchemaValidator.java:79)
    at com.reprezen.kaizen.oasparser.val.ObjectValidatorBase.runValidations(ObjectValidatorBase.java:18)
Caused by: java.lang.NullPointerException: Cannot invoke "java.lang.CharSequence.length()" because "this.text" is null

However, using the OpenApiTools Kotlin generator it works. I am unable to find any external schema reference in the code.

cjbooms commented 7 months ago

Fabrikt does not support this kind of definition:

            version:
              type:
                - string
                - 'null'
avwie commented 7 months ago

Okay. How could I’ve found that out? And, is it documented somewhere?

cjbooms commented 7 months ago

Fabrikt was only built to support OpenApi 3.0 The OpenApi 3.1 specification made some breaking changes to 3.0, this is one of them. I have created this little hack to fix it: https://github.com/cjbooms/fabrikt/pull/263

cjbooms commented 7 months ago

I have created two PRs which improve support for this API. However, there is a pretty crazy amount of inlining of schema definitions, and the synthetic schema names that Fabrikt is generating are conflicting with each other.

When fabrikt sees an inlined object, it uses the top-level enclosing schema as the prefix, and the property name as the suffix when generating the data classes. Example:

    Dog:
      type: object
      properties:
        walker:
          allOf:
            - $ref: "#/components/schemas/Person"
            - $ref: "#/components/schemas/Company"

Will result in a synthetic schema name of DogWalker. If the Dog object has another nested properties, called walker, that also defines an inlined object, it will result in the same synthetic DogWalker schema name. eg:

    Dog:
      type: object
      properties:
        walker:
          allOf:
            - $ref: "#/components/schemas/Person"
            - $ref: "#/components/schemas/Company"
        owner:
          type: object
          properties:
            walker:
              allOf:
                - $ref: "#/components/schemas/Person"
cjbooms commented 7 months ago

I'm closing this issue as I have fixed what issues I could. To enable generation, the JsDelivr API will need to be restructured to extract some of the inlined schemas into top-level schemas. This can be achieved without changing the contract of the API