Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Embedded assets base path #41

Closed
dicki opened this issue Sep 25, 2023 · 5 comments
Closed

Embedded assets base path #41

dicki opened this issue Sep 25, 2023 · 5 comments

Comments

@dicki
Copy link

dicki commented Sep 25, 2023

I’m having trouble using the v5emb module with my current setup, as the static assets are being referenced to without the base path of my application.

In my environments applications run behind an ingress with path-based routing inside a Kubernetes cluster.

Meaning for instance that Api1 receives its request with URL http://localhost/api1/…. All of the static assets are being attempted to be loaded using http://localhost/…] (notice the missing api1.

I believe there is way of configuring this asset base path using vearutop/statigz? But I don’t understand how to do so.

Any chance of someone shedding some light on this for me?

@vearutop
Copy link
Member

Hi, base path can be provided as an argument of handler constructor.

Please check an example.

package main

import (
	"net/http"

	"github.com/swaggest/swgui/v5emb"
)

func main() {
	http.Handle("/api1/docs/", v5emb.New(
		"Petstore",
		"https://petstore3.swagger.io/api/v3/openapi.json",
		"/api1/docs/",						// <----------- base path
	))

	http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
		_, _ = writer.Write([]byte("Hello World!"))
	})

	println("docs at http://localhost:8080/api1/docs/")
	_ = http.ListenAndServe("localhost:8080", http.DefaultServeMux)
}

Let me know if I misunderstood the issue.

@dicki
Copy link
Author

dicki commented Sep 27, 2023

I can't manage to get that working correctly.

Because my service is behind a path-based ingress the static assets need to have the path from the ingress added to them for the HTML.

So my current config looks like this:

...
h := swgui.New("api1", "/api1/docs/openapi.json", "/docs")
s.router.GET("/docs", gin.WrapH(h))
s.router.GET("/docs/openapi.json", gin.WrapH(s.oapiCollector))
...

So when invoking my service I don't do http://localhost/docs but http://localhost/api1/docs and the api1 is handled by the ingress which routes the request to my API. Hence I would need to be able to specify a static assets base path, for the generation of the Swagger UI HTML.

I can however just use the CDN version which works fine but I would've been happier with the embedded version.

@vearutop
Copy link
Member

Is there a reason to have

h := swgui.New("api1", "/api1/docs/openapi.json", "/docs")

instead of

h := swgui.New("api1", "/api1/docs/openapi.json", "/api1/docs")

?

@dicki
Copy link
Author

dicki commented Sep 28, 2023

The request are being forwarded and rewritten by the ingress. They change from localhost/api1/docs to localhost:8080/docs.

Here’s an example of someone dealing with the same issue.

Maybe I could prepend the external route, that gets rewritten by the ingress, to the Swagger UI generation by utilising the x-forwarded-prefix header. Like mentioned here.

But it’s only the static assets that need to have this prepended to them.

@dicki
Copy link
Author

dicki commented Sep 28, 2023

I've solved it.

...
basePath := "/docs"
uiPath := basePath + "/*any"
jsonPath := "/openapi.json"

s.router.GET(jsonPath, gin.WrapH(s.oapiCollector))
s.router.GET(uiPath, func(c *gin.Context) {
	// This helps with reverse proxying done by ingress
	// It allows us to serve the OpenAPI UI using a dynamic path specified by the ingress
	// without the application having to know about it
	forwardedPrefix := c.GetHeader("x-forwarded-prefix") // This returns an empty string if not found
	c.Request.URL.Path = forwardedPrefix + c.Request.URL.Path
	swgui.New(s.oapiCollector.Reflector().Spec.Title(), forwardedPrefix+jsonPath, forwardedPrefix+basePath).ServeHTTP(c.Writer, c.Request)
})
...

A prerequisite here is applying the following config to the service's ingress. Which populates request redirected to the service with the x-forwarded-prefix.

This allows my service to be agnostic to any reverse proxy rewriting the incoming requests.

{{- if .Values.ingress.enabled -}}
{{- $fullName := include "microservice.fullname" . -}}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: {{ $fullName }}
  labels:
    {{- include "microservice.labels" . | nindent 4 }}
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/ssl-redirect: "false"
    nginx.ingress.kubernetes.io/rewrite-target: /$2
    nginx.ingress.kubernetes.io/x-forwarded-prefix: /{{ $fullName }} <------
    cert-manager.io/cluster-issuer: letsencrypt-production
spec:
...

Thanks for taking the time for responding to me.

@dicki dicki closed this as completed Sep 29, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants