swagger-api / swagger-ui

Swagger UI is a collection of HTML, JavaScript, and CSS assets that dynamically generate beautiful documentation from a Swagger-compliant API.
https://swagger.io
Apache License 2.0
26.58k stars 8.96k forks source link

Wrong endpoint URL getting used #5791

Closed sjmorgan81 closed 4 years ago

sjmorgan81 commented 4 years ago

Q&A (please complete the following information)

Content & configuration

Example Swagger/OpenAPI definition:

{
  "openapi": "3.0.1",
  "info": {
    "title": "",
    "contact": {
      "name": "Simon Morgan",
      "email": ""
    },
    "version": "v1"
  },
  "paths": {
    "/Address/LpiKey": {
      "get": {
        "tags": [
          "Address"
        ],
        "summary": "Retrieve the address with the specified LPI key.",
        "parameters": [
          {
            "name": "lpiKey",
            "in": "query",
            "description": "The LPI of the address to retrieve.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/Address"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Address"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/Address"
                }
              }
            }
          }
        }
      }
    },
    "/Address/Uprn": {
      "get": {
        "tags": [
          "Address"
        ],
        "summary": "Retrieve the address with the specified UPRN.",
        "parameters": [
          {
            "name": "uprn",
            "in": "query",
            "description": "The UPRN of the address to retrieve.",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "language",
            "in": "query",
            "description": "The language of the address.",
            "schema": {
              "type": "string",
              "default": "ENG",
              "nullable": true
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/Address"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Address"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/Address"
                }
              }
            }
          }
        }
      }
    },
    "/Address/Postcode": {
      "get": {
        "tags": [
          "Address"
        ],
        "summary": "Search for addresses with the specified postcode.",
        "parameters": [
          {
            "name": "postcode",
            "in": "query",
            "description": "The postcode of the addresses to retrieve.",
            "required": true,
            "schema": {
              "maxLength": 8,
              "minLength": 5,
              "type": "string"
            }
          },
          {
            "name": "language",
            "in": "query",
            "description": "The language of the addresses.",
            "schema": {
              "type": "string",
              "default": "ENG",
              "nullable": true
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Address"
                  },
                  "nullable": true
                }
              },
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Address"
                  },
                  "nullable": true
                }
              },
              "text/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Address"
                  },
                  "nullable": true
                }
              }
            }
          }
        }
      }
    },
    "/Address/IdentifierAndPostcode": {
      "get": {
        "tags": [
          "Address"
        ],
        "summary": "Search for addresses with the specified identifier and postcode.",
        "parameters": [
          {
            "name": "identifier",
            "in": "query",
            "description": "The house name, number or organisation used to identify a property.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "postcode",
            "in": "query",
            "description": "The postcode of the addresses to search.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "language",
            "in": "query",
            "description": "The language of the addresses.",
            "schema": {
              "type": "string",
              "default": "ENG",
              "nullable": true
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Address"
                  },
                  "nullable": true
                }
              },
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Address"
                  },
                  "nullable": true
                }
              },
              "text/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Address"
                  },
                  "nullable": true
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Address": {
        "type": "object",
        "properties": {
          "uprn": {
            "type": "integer",
            "format": "int64"
          },
          "lpiKey": {
            "type": "string",
            "nullable": true
          },
          "organisation": {
            "type": "string",
            "nullable": true
          },
          "saoText": {
            "type": "string",
            "nullable": true
          },
          "saoRange": {
            "type": "string",
            "nullable": true
          },
          "paoText": {
            "type": "string",
            "nullable": true
          },
          "paoRange": {
            "type": "string",
            "nullable": true
          },
          "street": {
            "type": "string",
            "nullable": true
          },
          "locality": {
            "type": "string",
            "nullable": true
          },
          "town": {
            "type": "string",
            "nullable": true
          },
          "administrativeArea": {
            "type": "string",
            "nullable": true
          },
          "postcode": {
            "type": "string",
            "nullable": true
          },
          "xCoordinate": {
            "type": "number",
            "format": "double"
          },
          "yCoordinate": {
            "type": "number",
            "format": "double"
          },
          "latitude": {
            "type": "number",
            "format": "double"
          },
          "longitude": {
            "type": "number",
            "format": "double"
          },
          "language": {
            "type": "string",
            "nullable": true
          },
          "singleLineAddressLabel": {
            "type": "string",
            "nullable": true,
            "readOnly": true
          },
          "multiLineAddressLabel": {
            "type": "string",
            "nullable": true,
            "readOnly": true
          }
        },
        "nullable": true
      }
    }
  }
}

Swagger-UI configuration options:

app.UseSwaggerUI(options =>
{
    options.SwaggerEndpoint("swagger/v1/swagger.json", API_NAME);
    options.RoutePrefix = string.Empty;
});

Describe the bug you're encountering

The root of my deployed API is http://example.net/foo/. However, when I use "Try it out", instead of a the request getting sent to a URL such as http://example.net/foo/Address/LpiKey?lpiKey=123 it gets sent to http://example.net/Address/LpiKey?lpiKey=123 (i.e. the "foo" directory where the app is hosted and where I navigate to get the Swagger UI is missing).

This only happens the app is running under IIS. It works fine when it's running on my local machine using Kestrel.

To reproduce...

  1. Go to http://example.net/foo/
  2. Click on one of the various "Try it out" buttons
  3. Enter the required fields and click "Execute"

Expected behavior

A request is sent to one of the http://example.net/foo/... endpoints.

hkosova commented 4 years ago

Since your API definition does not specify servers, the base path for requests defaults to /. To change the base path to http://example.net/foo, add the following servers section to your API definition:

"servers": [
  {"url": "http://example.net/foo"}   // or just "/foo"
]
velmohan commented 2 years ago

I am having this issue in .NET 6 project. I am sorry but where do we add this setting?

Since your API definition does not specify servers, the base path for requests defaults to /. To change the base path to http://example.net/foo, add the following servers section to your API definition:

"servers": [
  {"url": "http://example.net/foo"}   // or just "/foo"
]

I am having this issue in .NET 6 project. I am sorry but where do we add this setting?

sjmorgan81 commented 2 years ago

@velmohan In my case it's an ASP.NET project and I add it via the Configure method of my Startup.cs:

app.UseSwagger(options => options.PreSerializeFilters.Add((swagger, httpReq) =>
{
    if (httpReq.Host.Host == "example.net")
    {
        swagger.Servers = new List<OpenApiServer> { new OpenApiServer { Url = "/foo", Description = "Blah blah blah" } };
    }
}));
velmohan commented 2 years ago

Thank you @sjmorgan81. That worked for me.

TheHunter commented 11 months ago

Sorry but this is not a real solution, because the path should be deduced by original request sent by behind reverse proxies. An example on nginx ingress controller (k8s), you can have two endpoints for the same application, and only one of them could work.

image

In this case, how can be able to resolve swagger ?