swagger-api / swagger-api/swagger-parser

Parameters with the same name but different locations are incorrectly returned when using JSON references ($ref) with openapi 3.0.x.

Open
#2,102 1 comment 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Java
Stars
867
Forks
560
Avg merge
2d 21h
Merged PRs (30d)
7

Description

Multiple parameters with the same name but different locations (for instance, in: query vs in: header) are wrongly handled by the parser if:

  • the parameters are described using JSON references ($ref).
  • and the OpenAPI file declares its version as v3.0.x ("openapi": "3.0.0" or "openapi": "3.0.3").

The issue does NOT occur when either not using $ref, or declaring "openapi": "3.1.0".

This looks like a bug because:

a) It violates the OpenAPI spec (both v3.0 and v3.1):

A unique parameter is defined by a combination of a name and location.

https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.0.md#parameter-object

This should be respected regardless of whether the parameter is defined with, or without $ref.

b) I don't see a mention of a change in this area between v3.0 and v3.1 (for instance here or here) which would justify the difference of behaviour.


How to reproduce (holds at least for swagger-parser 2.1.22 and 2.1.19):

package parsertest;

import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.parameters.Parameter;
import io.swagger.v3.parser.OpenAPIV3Parser;
import io.swagger.v3.parser.core.models.ParseOptions;

import java.io.IOException;
import java.util.List;

public class ParserTest {
    public static void main(String[] args) throws IOException {
        test("src/test/resources/parsertest/openapi-ok.json");
        test("src/test/resources/jparsertest/openapi-ko.json");
    }
    
    private static void test(String openapiFile) throws IOException {
        System.out.println("=== OpenAPI file:" + openapiFile);
        final ParseOptions options = new ParseOptions();
        options.setResolve(true);
        options.setResolveCombinators(true);
        options.setResolveFully(true);
        
        final OpenAPI openAPI = new OpenAPIV3Parser().read(openapiFile, null, options);
        
        final List<Parameter> parameters = openAPI.getPaths().get("/myoperation").getGet().getParameters();
        parameters.forEach(parameter -> {
            if (parameter != null) {
                System.out.println("Parameter name: " + parameter.getName() + " in: " + parameter.getIn());
            }
        });
    }
}

openapi-ko.json:

{
  "openapi": "3.0.0",
  "paths": {
    "/myoperation": {
      "get": {
        "parameters": [
          {"$ref": "#/components/parameters/schemaParam1"},
          {"$ref": "#/components/parameters/schemaParam2"}
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
  }}}}}}},
  "components": {
    "parameters": {
      "schemaParam1": {
        "name": "myParam",
        "in": "query",
        "schema": {
          "type": "string"
        }
      },
      "schemaParam2": {
        "name": "myParam",
        "in": "header",
        "schema": {
          "type": "string"
        }
   }}}
}

openapi-ok.json:

{
  "openapi": "3.0.0",
  "paths": {
    "/myoperation": {
      "get": {
        "parameters": [
          {
            "in": "query",
            "name": "myParam",
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "myParam",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
  }}}}}}}
}

Output:

=== OpenAPI file:src/test/resources/parsertest/openapi-ok.json
Parameter name: myParam in: query
Parameter name: myParam in: header
=== OpenAPI file:src/test/resources/parsertest/openapi-ko.json
Parameter name: myParam in: query

That is, for the OpenAPI using $ref, only one of the two parameters is returned by getParameters().

For comparison, if modifying the OpenAPI files to declare "openapi": 3.1.0, both the header and query parameter are returned:

=== OpenAPI file:src/test/resources/parsertest/openapi-ok.json
Parameter name: myParam in: query
Parameter name: myParam in: header
=== OpenAPI file:src/test/resources/parsertest/openapi-ko.json
Parameter name: myParam in: query
Parameter name: myParam in: header

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 with the Java reproducer and the two referenced resource files, src/test/resources/parsertest/openapi-ok.json and src/test/resources/jparsertest/openapi-ko.json, using the shown ParseOptions. Trace how the parser resolves referenced parameters for OpenAPI 3.0.x versus 3.1.0, then add a regression test showing that both same-name parameters with different locations are returned.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
api
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.