swagger-ui: "Try it Now" functionality stripping path prefixes when run behind nginx-ingress reverse proxy in Kubernetes/K8S.
See original GitHub issueQ&A (please complete the following information)
- OS: Linux (Ubuntu x86_64 LTS 20.04).
- Browser: Firefox.
- Version: v84.0.1 64-bit.
- Method of installation: Helm v3.x in K8S (though trying the manual “dist/index.html” approach yields similar results).
- Swagger-UI version: v3.24.3 (pre-built Docker container), v3.40.0 (plain old “dist/index.html” approach).
- Swagger/OpenAPI version: OpenAPI 3.0.
Content & configuration
- Setup an instance of an application exposed through an nginx-ingress rule in K8S. Sample ingress YAML included below. In this example, the host is
roadrunner.acme.co
, and the service is exposed onhttp://roadrunner.acme.com/meep/v1
.- Note: I’ve found a few other projects on GitHub or via Google searches where the solution is "just expose your app on
hostname/
, rather than a custom path invoking nginx rewrites such ashostname/meep/v1
. - This is not an option, as that would assume only a single application is exposed via the ingress controller. In a typical/production use case, each micro-service in behind the ingress-control would get its own dedicated base path, like
meep/v1
in my example).
- Note: I’ve found a few other projects on GitHub or via Google searches where the solution is "just expose your app on
- Download and extract the contents of the “plain old HTML/JS” archive.
- Modify the
dist/index.html
file so theURL
field points to the OpenAPI spec of my service (i.e.http://roadrunner.acme.co/meep/v1/openapi.json
; the service is a simple Python Flash+Swagger example that auto-exposes theopenapi.json
endpoint). - I am able to access the Swagger-UI web UI example, interact with it, etc. However, if I attempt to use the “Try It Now” ==> “Execute” functionality, the API calls to the live/running app fail due to a “Network error”.
- Upon closer inspection, I see that the “Execute” calls are attempting to communicate with
http://roadrunner.acme.co/v1/
rather thanhttp://roadrunner.acme.co/meep/v1
(i.e. the re-written portion of the URL is absent). - I was able to arrive at the same result by deploying swagger-ui into the cluster directly via a third-party helm chart.
Example ingress:
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: sample-ingress-meep-meep
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
rules:
- http:
paths:
- backend:
serviceName: velocitus-good-with-ketchup-ius
servicePort: 80
path: /meep/(v1/.*)
Example Swagger/OpenAPI definition: N/A.
Swagger-UI configuration options:
window.onload = function() {
// Begin Swagger UI call region
const ui = SwaggerUIBundle({
url: "http://roadrunner.acme.co/meep/v1/openapi.json",
dom_id: '#swagger-ui',
deepLinking: true,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout"
})
// End Swagger UI call region
window.ui = ui
}
Describe the bug you’re encountering
- The “Try It Now” ==> “Execute” functionality does not work, but access to the HTML app in general works.
To reproduce…
Example described above.
Expected behavior
- The “Try It Now” ==> “Execute” functionality uses the exact same URL (i.e. hostname plus base path) that is used to access the running OpenAPI-enabled service (maybe using
X-Forwarded-For
or additional parameters supplied to the ingress-controller, so that re-writes don’t break functionality).
Additional context or thoughts
There’s a hack I’ve figured out in order to make the “Try It Now” ==> “Execute” functionality work, but the downside (severe), is that I need to supply the external hostname to the swagger-ui app at chart installation time (i.e. when I install swagger-ui, it needs to be provided with the string http://roadrunner.acme.co/meep/v1
at installation time). This isn’t a permanent/viable solution though, as various users may “see” a different hostname and base path when accessing this micro-service (e.g. if it’s exposed via multiple domains with a common load balancer, or if some people attempt to access it via IP address rather than this specific host name). It also prevents 100% end-to-end automated installation, as someone needs to supply the external FQDN + base path at chart installation time.
Hack-y workaround:
- Deploy an OpenAPI-enabled microservice, expose it via an ingress rule (below). Can be deployed via
kubectl apply --namespace=acme-ns -f ingress-meep.yaml
.
ingress-meep.yaml
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: sample-ingress-meep-meep
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
rules:
- http:
paths:
- backend:
serviceName: velocitus-good-with-ketchup-ius
servicePort: 80
path: /meep/(v1/.*)
- Pre-create an ingress rule for swagger-ui (below). Can be deployed via
kubectl apply --namespace=acme-ns -f ingress-demo.yaml
.
ingress-demo.yaml
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: sample-ingress-swaggerui-demo
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$1
nginx.ingress.kubernetes.io/enable-cors: "true"
spec:
rules:
- http:
paths:
- backend:
serviceName: swagger-demo-swaggerui
servicePort: 8080
path: /swagger-demo/(.*)
- Using the following commands to deploy the chart.
# Make chart "visible" to Helm.
helm repo add cetic https://cetic.github.io/helm-charts
helm repo update
# Delete old copy if present.
helm delete --namespace=acme-ns swagger-demo
# Install chart.
helm install --namespace=acme-ns swagger-demo cetic/swagger-ui \
--set swaggerui.jsonUrl="http://velocitus-good-with-ketchup-ius.acme-ns.svc.cluster.local/v1/openapi.json" \
--set swaggerui.server.url="http://roadrunner.acme.co/meep/v1/"
- Navigate to
<http://roadrunner.acme.co/swagger-demo/>
in my browser. Application loads and is visible in my browser. - Change the “Servers” via the drop-down UI menu (top-left) from
v1
tohttp://roadrunner.acme.co/meep/v1
. Both the general UI features, and the live debug “Try It Now” features work as expected.
Possibly related issues (external projects)
Issue Analytics
- State:
- Created 3 years ago
- Comments:7
Top GitHub Comments
Hi! I tried to pass different
x-forwarded-prefix
values to multiple backend paths on the ingress-nginx (v1.0.4) and Kubernetes (1.21.7) through thenginx.ingress.kubernetes.io/x-forwarded-prefix
annotation as @DanSibbernsen’s comment.@happyincent Thank you very much!