question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

swagger-ui: "Try it Now" functionality stripping path prefixes when run behind nginx-ingress reverse proxy in Kubernetes/K8S.

See original GitHub issue

Q&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 on http://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 as hostname/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).
  • Download and extract the contents of the “plain old HTML/JS” archive.
  • Modify the dist/index.html file so the URL 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 the openapi.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 than http://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 to http://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:open
  • Created 3 years ago
  • Comments:7

github_iconTop GitHub Comments

4reactions
happyincentcommented, Feb 7, 2022

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 the nginx.ingress.kubernetes.io/x-forwarded-prefix annotation as @DanSibbernsen’s comment.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-demo
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/use-regex: "true"
    nginx.ingress.kubernetes.io/rewrite-target: /$3
    nginx.ingress.kubernetes.io/x-forwarded-prefix: /$1
spec:
  rules:
  - http:
      paths:
      - path: /()()(.*)
        pathType: Prefix
        backend:
          service:
            name: web
            port:
              number: 80
      - path: /(XXXApi)(/|$)(.*)
        pathType: Prefix
        backend:
          service:
            name: xxx-api
            port:
              number: 80
      - path: /(YYYApi)(/|$)(.*)
        pathType: Prefix
        backend:
          service:
            name: yyy-api
            port:
              number: 80
1reaction
ov-petrovcommented, Jul 8, 2022

@happyincent Thank you very much!

Read more comments on GitHub >

github_iconTop Results From Across the Web

Fixing Swagger UI "Try it out" Functionality When Deployed in ...
You have an API that sits behind a reverse proxy. For example in Azure Front Door /API Management, etc, you name it.
Read more >
Deploying and Scaling Microservices with Docker and ...
... **all commands must be run from the first VM, `node1`** - We will only check out/copy the code on `node1` ... Example:...
Read more >
Accessing flasgger_static endpoints behind a reverse proxy?
... proxy (traefik) using the prefix my_app (the proxy has to strip the prefix, however when I use the "try it out" function...
Read more >
Removing url prefixes in nginx Kubernetes Ingress
Getting an NGINX ingress running on a cluster is really easy, but the documentation did not immediately tell me how to strip the...
Read more >
Release 1.0 The Acumos Project. Licensed under CC BY 4.0.
Support for Pipeline (NiFi‡0 ) tools are integrated with Acumos. ... running under docker or kubernetes (k8s) on a single virtual machine or ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found