HiDeoo / starlight-openapi

Starlight plugin to generate documentation from OpenAPI/Swagger specifications
https://starlight-openapi.vercel.app
MIT License
112 stars 14 forks source link

Multiple methods with the same path result in incorrect behavior #25

Closed DaniFoldi closed 7 months ago

DaniFoldi commented 7 months ago

Describe the bug

Hi :wave:,

Thanks for creating this library, it's great to have api docs integrated into regular docs ✨ . When migrating, I found an issue with more complex schemas:

When using an openapi schema that contains multiple operations on the same pathItem (say DELETE and POST), the one that's defined later in the schema "wins", as they are assigned the same static path url, since the method is their only differentiator, which isn't taken into account.

To Reproduce

Expected behavior

I believe the solution would be to add the method as part of the url, so they do not collide, so the plugin would generate multiple files.

How often does this bug happen?

Every time

System Info

No response

Additional Context

No response

HiDeoo commented 7 months ago

Thanks for your report :raised_hands:

I tried reproducing using the schemas/v3.0/animals.yaml which I believe contains a schema like you are describing:

openapi: '3.1.0'
info:
  version: 1.0.0
  title: Animals
  license:
    name: MIT
security:
  - animals_auth:
      - 'read:animals'
externalDocs:
  description: Find out more about our animals
  url: https://example.com/more-info
servers:
  - url: //example.com/api
    description: Default server
  - url: //sandbox.example.com/api
    description: Sandbox server
tags:
  - name: places
  - name: animals
paths:
  /animals:
    parameters:
      - name: limit
        in: query
        description: The path item level limit parameter
        required: false
        schema:
          type: integer
          maximum: 100
          format: int32
      - name: tags
        in: query
        description: tags to filter by
        required: true
        style: form
        schema:
          type: array
          items:
            type: string
            enum:
              - fish
              - horse
    get:
      summary: List all animals
      operationId: listAnimals
      description: |
        returns _all_ animals
      deprecated: true
      externalDocs:
        description: Find out more about our animals
        url: https://example.com/more-info
      tags:
        - animals
      parameters:
        - name: limit
          in: query
          description: How many animals to return at one time (max 100)
          deprecated: true
          schema:
            type: integer
            maximum: 50
            format: int32
            nullable: true
        - name: offset
          in: header
          description: The number of animals to skip before starting to collect the result set
          required: false
          schema:
            type: integer
            format: int32
      responses:
        '200':
          description: A paged array of animals
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Animals'
        default:
          description: unexpected error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
    post:
      summary: Create an animal
      description: Creates a new animal
      operationId: addAnimal
      tags:
        - animals
      parameters:
        - name: authorization
          in: header
          description: The authorization token
          required: true
      requestBody:
        description: Animal to add
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Animal'
      security:
        - {}
        - animals_auth:
            - 'write:animals'
            - 'read:animals'
        - api_key: []
      responses:
        '200':
          description: animal response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Animal'
        default:
          description: unexpected error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

/animals contains 2 methods grouped under the animals tag and render the following pages:

Would you be able to provide a small reproduction of the issue you are facing?

DaniFoldi commented 7 months ago

Hi,

Thanks for checking it out. I believe it doesn't repro with the example schema because of these lines: https://github.com/HiDeoo/starlight-openapi/blob/22bc6bdb153ef989e8a5aca3c1235c34d59cc3e3/packages/starlight-openapi/libs/operation.ts#L25-L35

the operationId from the schema takes precedence and shows up in the url as listanimals and addanimal (screenshot 1). After removing all operationId fields, as they are optional, I saw the urls default to an escaped version of the path (screenshot 2), which causes the collision. image Screenshot 2024-04-16 at 12 42 57

HiDeoo commented 7 months ago

Thanks for your explanations, really helped a lot, I totally missed the operation IDs.

This should now be fixed in v0.6.2 that I just released.

If we take the example I gave earlier, with no operation IDs, the following pages will now be generated: