Search code examples
jsonyamlopenapiopenapi-generator

openAPI unable to resolve ref to external file. Component name contains invalid characters


I'm trying to split a large yml into a bunch of smaller yml documents. I followed the example provided by David Garcia here, and then using OpenAPI CodeGenerator to generate my models. OpenAPI Generator complained that [BUG] attribute components.schemas.Schema name doesn't adhere to regular expression ^[a-zA-Z0-9.-_]+$. So, I tried playing with David Garcia's example by cloning his repo and deploying locally, but I get the same error. I decided to check it in the swagger editor, and I get the same issue, but the error message says

Semantic error at components.schemas.$ref
Component names can only contain the characters A-Z a-z 0-9 - . _
Jump to line 25

I'm using the yaml from David Garcia's example:

openapi: "3.0.0"
info:
  version: 1.0.0
  title: Swagger Petstore
  description: Multi-file boilerplate for OpenAPI Specification.
  license:
    name: MIT
  contact:
    name: API Support
    url: http://www.example.com/support
    email: [email protected]
servers:
  - url: http://petstore.swagger.io/v1
tags:
  - name: pets
paths:
  /pets:
    $ref: "./resources/pets.yaml"
  /pets/{petId}:
    $ref: "./resources/pet.yaml"
components:
  parameters:
    $ref: "./parameters/_index.yaml"
  schemas:
    $ref: "./schemas/_index.yaml"
  responses:
    $ref: "./_index.yaml"

You can easily paste this into the editor and see the errors yourself. The OpenAPI Specification says components objects can either be an Object or a Reference, i.e. Map[string, Schema Object | Reference Object], and the Schema Object definition says, "Alternatively, any time a Schema Object can be used, a Reference Object can be used in its place. "

I'm aware that I can sub it down within the yaml document, like so:

components:
  parameters:
    petId:
      $ref: "./parameters/path/petId.yaml"
  schemas:
    pets:
      $ref: "./schemas/Pets.yaml"
  responses:
    responseSchema:
      $ref: "./response/pets200.yaml"

But why can't I reference an external index? The online example says yes and the open api spec says yes, but I can't get it to work.


Solution

  • It's a common misconception that the OpenAPI Specification allows $ref anywhere. Actually, $ref is only allowed in places where the OpenAPI Specification says the value of a field can be a "Reference Object" or a "Schema Object".

    Specifically, this snippet is NOT valid OpenAPI syntax:

    components:
      parameters:
        $ref: "./parameters/_index.yaml"
      schemas:
        $ref: "./schemas/_index.yaml"
      responses:
        $ref: "./_index.yaml"
    

    Map[string, Schema Object | Reference Object] means that the components.schemas node must be a map where the keys are schema names and the values are either inline schemas or schema references. As in your second example (which is valid OpenAPI syntax):

    components:
      parameters:                              # Map
        petId:                                 #  <string, 
          $ref: "./parameters/path/petId.yaml" #           Reference Object>
      schemas:
        pets:
          $ref: "./schemas/Pets.yaml"
      responses:
        responseSchema:
          $ref: "./response/pets200.yaml"
    

    The workaround that some implementations use to handle $refs in any places is to pre-process the spec using a generic JSON $ref resolver (such as json-refs) to resolve those non-standard $refs. For example, the blog post you took this example from uses swagger-cli to resolve non-standard $refs and create a single merged file.