openapi-merge icon indicating copy to clipboard operation
openapi-merge copied to clipboard

Incorrect `$ref` in bundled file

Open bas-kirill opened this issue 6 months ago • 0 comments

Hi!

I am using openapi-merge-cli to merge multiple OpenAPI files. But resulting bundle file contains incorrect $ref.

Steps to reproduce:

image
  1. Create file openapi/specs/common/ServerError.yml:
openapi: "3.0.0"

components:
  schemas:
    ServerError:
      type: object
  1. Create file openapi/specs/instrument/components/GetInstrumentByCriteriaRequestBody.yml:
openapi: "3.0.0"

info:
  version: 1.0.0
  title: Get Instruments Request Body

paths: {}

components:
  schemas:
    GetInstrumentCriteriaRequestBody:
      type: object
      properties:
        instrumentName:
          type: string
        instrumentTypes:
          type: array
          items:
            type: string
        manufacturerNames:
          type: array
          items:
            type: string
        manufactureDateFrom:
          type: string
          format: date
        releaseDateFrom:
          type: string
          format: date
        releaseDateTo:
          type: string
          format: date
        countries:
          type: array
          items:
            type: string
        materials:
          type: array
          items:
            type: string
        instrumentIds:
          type: array
          items:
            type: integer
            format: int64
  1. Create file openapi/specs/instrument/components/InstrumentDetails.yml:
openapi: "3.0.0"

info:
  version: 1.0.0
  title: Instrument Details

paths: {}

components:
  schemas:
    InstrumentDetails:
      type: object
      properties:
        id:
          type: integer
          format: int64
        name:
          type: string
        type:
          type: string
        manufacturer:
          type: string
        manufacturerDate:
          type: string
        releaseDate:
          type: string
        country:
          type: string
        basicMaterials:
          type: array
          items:
            type: string
  1. Create file openapi/specs/instrument/GetInstrumentsByCriteriaApi.yml:
openapi: "3.0.0"

info:
  version: 1.0.0
  title: Get Instruments by Criteria
servers:
  - url: http://localhost:8080/

paths:
  /api/instruments:
    post:
      summary: Get Instruments by Criteria
      operationId: getInstrumentsByCriteria
      tags:
        - getInstrumentsByCriteria
      parameters:
        - name: pageSize
          in: query
          description: Page Size
          required: false
          schema:
            type: integer
            format: int32
        - name: pageNumber
          in: query
          description: Page Number (1-based enumeration)
          required: false
          schema:
            type: integer
            format: int32
      requestBody:
        content:
          application/json:
            schema:
              $ref: "./components/GetInstrumentByCriteriaRequestBody.yml#/components/schemas/GetInstrumentCriteriaRequestBody"
        required: true
      responses:
        "200":
          description: Instrument Details
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GetInstrumentsByCriteriaResponse"
        default:
          description: server error
          content:
            application/json:
              schema:
                $ref: "./../common/ServerError.yml#/components/schemas/ServerError"

components:
  schemas:
    GetInstrumentsByCriteriaResponse:
      type: object
      required: [ content ]
      properties:
        content:
          type: array
          items:
            $ref: './components/InstrumentDetails.yml#/components/schemas/InstrumentDetails'

  1. Create file openapi/specs/instrument/GetInstrumentsByCriteriaPaginatedApi.yml:
openapi: "3.0.0"

info:
  version: 1.0.0
  title: Get Instruments by Criteria Paginated
servers:
  - url: http://localhost:8080/

paths:
  /api/instruments/paginated:
    post:
      summary: Get Instruments by Criteria
      operationId: getInstrumentsByCriteriaPaginated
      tags:
        - getInstrumentsByCriteriaPaginated
      parameters:
        - name: pageSize
          in: query
          description: Page Size
          required: false
          schema:
            type: integer
            format: int32
        - name: pageNumber
          in: query
          description: Page Number (1-based enumeration)
          required: false
          schema:
            type: integer
            format: int32
      requestBody:
        content:
          application/json:
            schema:
              $ref: "./components/GetInstrumentByCriteriaRequestBody.yml#/components/schemas/GetInstrumentCriteriaRequestBody"
        required: true
      responses:
        "200":
          description: Instrument Details
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GetInstrumentByCriteriaPageResponse"
        default:
          description: server error
          content:
            application/json:
              schema:
                $ref: "./../common/ServerError.yml#/components/schemas/ServerError"

components:
  schemas:
    GetInstrumentByCriteriaPageResponse:
      type: object
      properties:
        content:
          type: array
          items:
            $ref: './components/InstrumentDetails.yml#/components/schemas/InstrumentDetails'
        contentSize:
          type: integer
          format: int32
          description: The number of items in the content.
        pageSize:
          type: integer
          format: int32
          description: The number of items per page.
        pageNumber:
          type: integer
          format: int32
          description: The current page number (0-based index).
        totalElements:
          type: integer
          format: int32
          description: The total number of elements across all pages.
        totalPages:
          type: integer
          format: int32
          description: The total number of pages.
  1. Create file openapi/specs/login/BasicLoginEndpointApi.yml:
openapi: "3.0.0"

info:
  version: 1.0.0
  title: Basic Login
servers:
  - url: http://localhost:8080/

paths:
  /api/auth/login:
    post:
      summary: Basic Login
      operationId: basicLogin
      tags:
        - basicLogin
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UsernameAndPasswordRequestBody"
        required: true
      responses:
        "200":
          description: Profile Details
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/JwtResponse"
        default:
          description: server error
          content:
            application/json:
              schema:
                $ref: "./../common/ServerError.yml#/components/schemas/ServerError"

components:
  schemas:
    UsernameAndPasswordRequestBody:
      type: object
      required: [ username, password ]
      properties:
        username:
          type: string
        password:
          type: string

    JwtResponse:
      type: object
      required: [ jwt ]
      properties:
        jwt:
          type: string
  1. Create file openapi/specs/profile/GetProfileApi.yml:
openapi: "3.0.0"

info:
  version: 1.0.0
  title: Get Profile
servers:
  - url: http://localhost:8080/

paths:
  /api/profile:
    get:
      summary: Get Profile Info
      operationId: getProfile
      tags:
        - profile
      responses:
        "200":
          description: Profile Details
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProfileDetailsResponse"
        default:
          description: server error
          content:
            application/json:
              schema:
                $ref: "./../common/ServerError.yml#/components/schemas/ServerError"

components:
  schemas:
    ProfileDetailsResponse:
      type: object
      required: [ username, role, fullName ]
      properties:
        username:
          type: string
        role:
          type: string
        fullName:
          type: string
  1. Create config file openapi/bundle-config.yml:
inputs:
  - inputFile: "./specs/common/ServerError.yml"
  - inputFile: "./specs/instrument/GetInstrumentsByCriteriaPaginatedApi.yml"
  - inputFile: "./specs/instrument/components/GetInstrumentByCriteriaRequestBody.yml"
  - inputFile: "./specs/instrument/components/InstrumentDetails.yml"
  - inputFile: "./specs/instrument/GetInstrumentsByCriteriaApi.yml"
  - inputFile: "./specs/login/BasicLoginEndpointApi.yml"
  - inputFile: "./specs/profile/GetProfileApi.yml"

output: "./specs/bundle.yml"
  1. Run bundler from openapi folder: npx openapi-merge-cli --config ./bundle-config.yml

Expected result: YML with correct $ref's

Real result:

openapi: 3.0.3
servers:
  - url: 'http://localhost:8080/'
paths:
  /api/instruments/paginated:
    post:
      summary: Get Instruments by Criteria
      operationId: getInstrumentsByCriteriaPaginated
      tags:
        - getInstrumentsByCriteriaPaginated
      parameters:
        - name: pageSize
          in: query
          description: Page Size
          required: false
          schema:
            type: integer
            format: int32
        - name: pageNumber
          in: query
          description: Page Number (1-based enumeration)
          required: false
          schema:
            type: integer
            format: int32
      requestBody:
        content:
          application/json:
            schema:
              $ref: >-
                ./components/GetInstrumentByCriteriaRequestBody.yml#/components/schemas/GetInstrumentCriteriaRequestBody
        required: true
      responses:
        '200':
          description: Instrument Details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/GetInstrumentByCriteriaPageResponse'
        default:
          description: server error
          content:
            application/json:
              schema:
                $ref: ./../common/ServerError.yml#/components/schemas/ServerError
  /api/instruments:
    post:
      summary: Get Instruments by Criteria
      operationId: getInstrumentsByCriteria
      tags:
        - getInstrumentsByCriteria
      parameters:
        - name: pageSize
          in: query
          description: Page Size
          required: false
          schema:
            type: integer
            format: int32
        - name: pageNumber
          in: query
          description: Page Number (1-based enumeration)
          required: false
          schema:
            type: integer
            format: int32
      requestBody:
        content:
          application/json:
            schema:
              $ref: >-
                ./components/GetInstrumentByCriteriaRequestBody.yml#/components/schemas/GetInstrumentCriteriaRequestBody
        required: true
      responses:
        '200':
          description: Instrument Details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/GetInstrumentsByCriteriaResponse'
        default:
          description: server error
          content:
            application/json:
              schema:
                $ref: ./../common/ServerError.yml#/components/schemas/ServerError
  /api/auth/login:
    post:
      summary: Basic Login
      operationId: basicLogin
      tags:
        - basicLogin
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UsernameAndPasswordRequestBody'
        required: true
      responses:
        '200':
          description: Profile Details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JwtResponse'
        default:
          description: server error
          content:
            application/json:
              schema:
                $ref: ./../common/ServerError.yml#/components/schemas/ServerError
  /api/profile:
    get:
      summary: Get Profile Info
      operationId: getProfile
      tags:
        - profile
      responses:
        '200':
          description: Profile Details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProfileDetailsResponse'
        default:
          description: server error
          content:
            application/json:
              schema:
                $ref: ./../common/ServerError.yml#/components/schemas/ServerError
components:
  schemas:
    ServerError:
      type: object
    GetInstrumentByCriteriaPageResponse:
      type: object
      properties:
        content:
          type: array
          items:
            $ref: >-
              ./components/InstrumentDetails.yml#/components/schemas/InstrumentDetails
        contentSize:
          type: integer
          format: int32
          description: The number of items in the content.
        pageSize:
          type: integer
          format: int32
          description: The number of items per page.
        pageNumber:
          type: integer
          format: int32
          description: The current page number (0-based index).
        totalElements:
          type: integer
          format: int32
          description: The total number of elements across all pages.
        totalPages:
          type: integer
          format: int32
          description: The total number of pages.
    GetInstrumentCriteriaRequestBody:
      type: object
      properties:
        instrumentName:
          type: string
        instrumentTypes:
          type: array
          items:
            type: string
        manufacturerNames:
          type: array
          items:
            type: string
        manufactureDateFrom:
          type: string
          format: date
        releaseDateFrom:
          type: string
          format: date
        releaseDateTo:
          type: string
          format: date
        countries:
          type: array
          items:
            type: string
        materials:
          type: array
          items:
            type: string
        instrumentIds:
          type: array
          items:
            type: integer
            format: int64
    InstrumentDetails:
      type: object
      properties:
        id:
          type: integer
          format: int64
        name:
          type: string
        type:
          type: string
        manufacturer:
          type: string
        manufacturerDate:
          type: string
        releaseDate:
          type: string
        country:
          type: string
        basicMaterials:
          type: array
          items:
            type: string
    GetInstrumentsByCriteriaResponse:
      type: object
      required:
        - content
      properties:
        content:
          type: array
          items:
            $ref: >-
              ./components/InstrumentDetails.yml#/components/schemas/InstrumentDetails
    UsernameAndPasswordRequestBody:
      type: object
      required:
        - username
        - password
      properties:
        username:
          type: string
        password:
          type: string
    JwtResponse:
      type: object
      required:
        - jwt
      properties:
        jwt:
          type: string
    ProfileDetailsResponse:
      type: object
      required:
        - username
        - role
        - fullName
      properties:
        username:
          type: string
        role:
          type: string
        fullName:
          type: string

bas-kirill avatar Aug 21 '24 15:08 bas-kirill