asyncapi / saunter

Saunter is a code-first AsyncAPI documentation generator for dotnet.
https://www.asyncapi.com/
MIT License
195 stars 55 forks source link

Added support for using Saunter in a proxy-reverse environment #127

Closed rogerzanelato closed 2 years ago

rogerzanelato commented 2 years ago

To cover #126.

I put an example on this branch to test the implementation and get some feedback:

$ cd examples/StreetlightsAPI
$ dotnet publish -c Release
$ docker-compose up

# Open in browser: http://localhost:5000/service-a/asyncapi/ui/index.html
# Open in browser: http://localhost:5000/service-b/asyncapi/ui/index.html
rogerzanelato commented 2 years ago

The first try was with a new "Endpoint" options used exclusively to load the Document JSON.

This could enable using relative paths with the advantage of not nedding to know the base path of the application.

But, a little bug is that although it works fine when accessing http://localhost:5000/service-b/asyncapi/ui/index.html directly, when we visit http://localhost:5000/service-b/asyncapi/ui we got redirected to http://localhost:5000/asyncapi/ui/index.html.

rogerzanelato commented 2 years ago

The second try was with a new "ProxyReverseBasePath" option. This option is gonna be prepended to the redirect and document URL, when provided with a string not nullable or empty.

This solved both problems (wrong redirection and json document not being loaded). I think maybe we could achieve the same result without the new option, taking advantage of the UseBasePath Middleware.

If we set the proxy-reverse prefix on the startup like this: app.UseBasePath("/service-a"), then we could access it on the Request in our middleware, something like:

private string PrependProxyReverseBasePath(HttpRequest httpRequest, string url)
    => httpRequest.PathBase.Add(url);
rogerzanelato commented 2 years ago

Nope, "UseBasePath" won't work. The problem is that the middleware extracts the BasePath from the Request.

It's gonna be empty when using a reverse-proxy like nginx because the request arrives without the prefix.

m-wild commented 2 years ago

Thanks for doing this investigation and testing. Have you tried this with app.UseBasePath (from https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/proxy-load-balancer)

If the proxy trims the path (for example, forwarding /foo/api/1 to /api/1), fix redirects and links by setting the request's PathBase property:

app.Use((context, next) =>
{
context.Request.PathBase = new PathString("/foo");
return next();
});
rogerzanelato commented 2 years ago

Thanks for the suggestion! I'll try it later but I think it'll work

rogerzanelato commented 2 years ago

Thanks for doing this investigation and testing. Have you tried this with app.UseBasePath (from https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/proxy-load-balancer)

If the proxy trims the path (for example, forwarding /foo/api/1 to /api/1), fix redirects and links by setting the request's PathBase property:

app.Use((context, next) =>
{
    context.Request.PathBase = new PathString("/foo");
    return next();
});

Nice, it works with this suggestion! third try

I modified the AsyncApiUiMiddleware to use the context.Request.PathBase to create the redirection and document endpoints, now it works in a proxy-reverse environment when the middleware is applied, but also works in normal circumstances.

m-wild commented 2 years ago

Looks good. Do you want to mark this as non-draft and I can get it merged and get a new version released.

rogerzanelato commented 2 years ago

Looks good. Do you want to mark this as non-draft and I can get it merged and get a new version released.

Done!