Open KamranShahid opened 3 years ago
I'm not sure what you mean - could you please elaborate on your setup and what you're actually trying to do.
i have my application deployed on some linux server. private ip url http://xxx.xxx.xxx.xxx:4000/swagger/index.html is serving fine. I have deployed same url under with ngnix with url like http://mywebsitebasepath/myvitualpath/swagger/index.html but api url is missing myvitualpath and api address is returning 404 error. Any setting i also needed to do?
Changed My function in startup.cs from
private void SwaggerSetup(IApplicationBuilder app)
{
var swaggerOptions = new SwaggerOptions();
Configuration.GetSection(nameof(SwaggerOptions)).Bind(swaggerOptions);
app.UseSwagger(option => { option.RouteTemplate = swaggerOptions.JsonRoute; });
app.UseSwaggerUI(option =>
{
option.SwaggerEndpoint(swaggerOptions.UIEndpoint, swaggerOptions.Description);
});
}
to
private void SwaggerSetup(IApplicationBuilder app)
{
////https://github.com/domaindrivendev/Swashbuckle.AspNetCore#dealing-with-proxies-that-change-the-request-path
app.Use((context, next) =>
{
if (context.Request.Headers.TryGetValue("X-Forwarded-Prefix", out var value))
context.Request.PathBase = value.First();
return next();
});
var swaggerOptions = new SwaggerOptions();
Configuration.GetSection(nameof(SwaggerOptions)).Bind(swaggerOptions);
app.UseSwagger(option => { option.RouteTemplate = swaggerOptions.JsonRoute; });
app.UseSwaggerUI(option =>
{
option.SwaggerEndpoint("v1/swagger.json", swaggerOptions.Description);
});
}
but not effect
I also experience the same issue: the FQDN for the API server is: productname-api.domain-name.com, and we have a web route in front of it. So, people will need to use productname.domain-name.com/api to access the APIs. However, when swagger is displayed in the browser, it uses the original FQDN (productname-api.domain-name.com) instead of productname.domain-name.com/api. Therefore, whenever users click on the Try It button, it fails because it's unable to resolve. The hostname listed in the host drop-down list is the original FQDN instead of the /api ones. I've read the https://github.com/domaindrivendev/Swashbuckle.AspNetCore#dealing-with-proxies-that-change-the-request-path, and it doesn't resolve my issue. I've also using v6.0.7 now and still having the same issue. Any suggestions on how to solve it? Or should I create a pull request? Thank you.
The URL that you pass to SwaggerEndpoint
is what the swagger-ui, a client-side application, uses to retrieve your API metadata. When the leading slash is omitted, you're telling the swagger-ui that the path is relative to itself. So, assuming the default RoutePrefix = "swagger"
for the SwaggerUI middleware, you're telling it that the Swagger endpoint is available at swagger/v1/swagger.json
. While this would be correct with the default setup, it won't work in your case because you've also changed the RouteTemplate
for the Swagger middleware. To account for this, you need to alter the path provided to SwaggerEndpoint
accordingly. For example, something along the following lines should work:
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint($"../{swaggerOptions.JsonRoute}".Replace("{documentName}", "v1"), "V1 Docs");
});
Hi, I think I need to clarify. The swagger.json can be found in its current location; it's never the issue. I'm trying to find out how to modify the hostnames listed in the Server dropdown list in the swagger.json.
I need to customise the Server dropdown list's content; at the moment, swashbuckler automatically uses the server's fqdn (productname-api.domain-name.com) instead of its accessible fqdn (productname.domain-name.com/api). I can't seem to find a way to do that.
If that's what you've been trying to tell me, then I apologise as I've certainly missed your explanation.
Looking forward to your further enlightenment.
The URL that you pass to
SwaggerEndpoint
is what the swagger-ui, a client-side application, uses to retrieve your API metadata. When the leading slash is omitted, you're telling the swagger-ui that the path is relative to itself. So, assuming the defaultRoutePrefix = "swagger"
for the SwaggerUI middleware, you're telling it that the Swagger endpoint is available atswagger/v1/swagger.json
. While this would be correct with the default setup, it won't work in your case because you've also changed theRouteTemplate
for the Swagger middleware. To account for this, you need to alter the path provided toSwaggerEndpoint
accordingly. For example, something along the following lines should work:app.UseSwaggerUI(c => { c.SwaggerEndpoint($"../{swaggerOptions.JsonRoute}".Replace("{documentName}", "v1"), "V1 Docs"); });
not worked
@KamranShahid, @alexkusuma - could you try pulling down the latest version (6.1.0
) to see if this works for you?
In 6.0.0
, I introduced logic to automatically infer and populate the servers
metadata using info from the current request (Host
header etc.), which drives the server dropdown in the swagger-ui. In doing this, I knew it would be problematic for apps that are behind a proxy, and provided guidance to use Microsoft's Forwarded Headers middleware, as this is their recommended solution for apps behind a proxy.
In hindsight though, I think this has caused more problems than it solved, and so as of 6.1.0
, I've reverted to the old behavior that simply leaves the servers
section empty. In this case, the swagger-ui will infer the absolute URL based on the current browser location (the fqdn). I think this should work for your case - can you try it and let me know?
Hi @domaindrivendev - I had just upgraded it to 6.1.0 will test it in the next few days or early next week. I need to focus on the other part of the project for now. I will let you posted.
Hi @domaindrivendev - I had just upgraded it to 6.1.0 will test it in the next few days or early next week. I need to focus on the other part of the project for now. I will let you posted.
Have you able to resolved it?
Hi @domaindrivendev and @KamranShahid,
Unfortunately, it's not resolved yet. I've tried it with 2 servers, both behind webroute. the swagger kept using fqdn for the URL instead of the one that's accessible for user. For illustration:
server's fqdn is: servername-api.domain-name.com/ fqdn that's accessible from user is: service-name.domain-name.com/api
so on swagger page, when I have the the definition, let say for API called: api-endpoint-1 when I click on try it button, swagger kept using: servername-api.domain-name.com/api-endpoint-1 while actually it supposed to use: service-name.domain-name.com/api/api-endpoint-1
Hi @domaindrivendev, should I do a pull request to solve this?
@alexkusuma - if you've upgraded to 6.1.0
and are still seeing issues, this is most likely a config issue. Could you possibly create a minimal app (i.e. starting with blank project) that repro's the issue and post to github so I can pull down and troubleshoot? I can use docker to put a proxy in front of it to mimic the setup you've described.
We're using version 6.1.4
- which is the latest as of this time of writing and we're still having the same issue when our API is deployed in Azure and mapped through Azure Front Door and APIM. The "Try out" functionality does not work as the base path / api route prefix is stripped from the Swagger UI. For example,
Instead of https://{DOMAIN}.com/{BASEPATH}/v1/Foo
, the Swagger UI uses this: https://{DOMAIN}.com/v1/Foo
.
I spent the day trying to fix this, but couldn't get an elegant way to get the base path from swagger configuration. For the time being, here's what I did to fix it:
app.UseSwagger(options =>
{
//Workaround to use the Swagger UI "Try Out" functionality when deployed behind a reverse proxy (APIM) with API prefix /sub context configured
options.PreSerializeFilters.Add((swagger, httpReq) =>
{
if (httpReq.Headers.ContainsKey("X-Forwarded-Host"))
{
//The httpReq.PathBase and httpReq.Headers["X-Forwarded-Prefix"] is what we need to get the base path.
//For some reason, they returning as null/blank. Perhaps this has something to do with how the proxy is configured which we don't have control.
//For the time being, the base path is manually set here that corresponds to the APIM API Url Prefix.
//In this case we set it to 'sample-app'.
var basePath = "sample-app"
var serverUrl = $"{httpReq.Scheme}://{httpReq.Headers["X-Forwarded-Host"]}/{basePath}";
swagger.Servers = new List<OpenApiServer> { new OpenApiServer { Url = serverUrl } };
}
});
})
.UseSwaggerUI(options =>
{
options.RoutePrefix = string.Empty;
options.SwaggerEndpoint("swagger/v1/swagger.json", "My Api (v1)");
});
We're using version
6.1.4
- which is the latest as of this time of writing and we're still having the same issue when our API is deployed in Azure and mapped through Azure Front Door and APIM. The "Try out" functionality does not work as the base path / api route prefix is stripped from the Swagger UI. For example,Instead of
https://{DOMAIN}.com/{BASEPATH}/v1/Foo
, the Swagger UI uses this:https://{DOMAIN}.com/v1/Foo
.I spent the day trying to fix this, but couldn't get an elegant way to get the base path from swagger configuration. For the time being, here's what I did to fix it:
app.UseSwagger(options => { //Workaround to use the Swagger UI "Try Out" functionality when deployed behind a reverse proxy (APIM) with API prefix /sub context configured options.PreSerializeFilters.Add((swagger, httpReq) => { if (httpReq.Headers.ContainsKey("X-Forwarded-Host")) { //The httpReq.PathBase and httpReq.Headers["X-Forwarded-Prefix"] is what we need to get the base path. //For some reason, they returning as null/blank. Perhaps this has something to do with how the proxy is configured which we don't have control. //For the time being, the base path is manually set here that corresponds to the APIM API Url Prefix. //In this case we set it to 'sample-app'. var basePath = "sample-app" var serverUrl = $"{httpReq.Scheme}://{httpReq.Headers["X-Forwarded-Host"]}/{basePath}"; swagger.Servers = new List<OpenApiServer> { new OpenApiServer { Url = serverUrl } }; } }); }) .UseSwaggerUI(options => { options.RoutePrefix = string.Empty; options.SwaggerEndpoint("swagger/v1/swagger.json", "My Api (v1)"); });
this mean's basepath should be there somewhere in configuration
@KamranShahid I would think so, yes. But for the time being, we set it as a static value since the basebath won't change in all of our environments.
@KamranShahid I would think so, yes. But for the time being, we set it as a static value since the basebath won't change in all of our environments.
Thanks Vincent Maverick, I also had similar idea but like to avoid one additional configuration as my application is containerize and almost all configuration is driven via environment variables + vault combination. Anyway thanks for this
So, I could not find what I needed here, but the docs clearly show how to do this here.
Basically, you need to give it a path that it can know where it is starting in on the "swagger stuff". If you set RoutePrefix
to "swagger"
then it will see all URLs that have swagger in them as needing to be handled by swagger and will work from there.
So if you have a url like https://localhost:32332/service/swagger/index.html
it will ignore the stuff before the text that matches RoutePrefix
. It will then start adding on from there.
Here is the example code (copied from the docs):
app.UseSwagger();
app.UseSwaggerUI(options =>
{
options.SwaggerEndpoint("v1/swagger.json", "Addition Service");
options.RoutePrefix = "swagger";
});
Hello,
I've just ran into this as well while deploying apps to a Kubernetes cluster, the intention being development builds will be deployed to prefixed paths on the same domain. I've also hit this problem when deploying apps to IIS using it's virtual applications, which does a similar thing, hosts the application under a subpath of the root domain.
ASP.NET handles this in a standard way, by using the BasePath
property on the incoming request. This can be set by various middlewares or other utilities, for example the IIS Hosting sets this BasePath if the application is hosted under a virtual path. The use cases are documented here:
https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/proxy-load-balancer?view=aspnetcore-6.0
However, it seems the SwaggerUI doesn't respect the BasePath
property, looking at the code it only uses the RoutePrefix
property which as far as I can tell, can only be set once at startup time.
At the moment I can get it to work by having a configuration property which can be set, but doing so locks that application to one specific path, whereas only things that are sent down to the client browser should really care about the BasePath
, so it should be set on a per request basis.
Has anyone come up with a solution for this? My route to my app gets rewritten. So what happens is I can get to swagger UI, but the swagger.json gets requested by a different URI based on the SwaggerEndpoint
configuration. E.g.
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/api/v1/swagger.json", "SagaControllerApp v1");
c.RoutePrefix = "api";
});
Navigate to app at https://domain/api/myapp
but the app requests swagger.json at https://domain/api/v1/swagger.json
.
Has anyone come up with a solution for this? My route to my app gets rewritten. So what happens is I can get to swagger UI, but the swagger.json gets requested by a different URI based on the
SwaggerEndpoint
configuration. E.g.app.UseSwaggerUI(c => { c.SwaggerEndpoint("/api/v1/swagger.json", "SagaControllerApp v1"); c.RoutePrefix = "api"; });
Navigate to app at
https://domain/api/myapp
but the app requests swagger.json athttps://domain/api/v1/swagger.json
.
I did find a workaround by setting the SwaggerEndpoint to a relative path. E.g: c.SwaggerEndpoint("v1/swagger.json", "SagaControllerApp v1");
Thanks everyone for your recommendations!
My case: I deployed my service along the path: https://domain.com/path/... Methods path: https://domain.com/path/api/v1/Method Swagger path: https://domain.com/path/swagger/index.html
What I've done...
location ^~ /path/swagger/ {
proxy_set_header X-Forwarded-Prefix /path;
rewrite ^/path/(.*)$ /$1 break;
...
location ^~ /path/api/ { ... rewrite ^/path/(.*)$ /$1 break; ...
2. Set relative path for swagger.json:
app.UseSwaggerUI(options => { foreach (var description in apiProvider.ApiVersionDescriptions) { options.SwaggerEndpoint($"../swagger/{description.GroupName}/swagger.json", description.GroupName.ToUpperInvariant()); } });
_(You can use `../` or `$"{description.GroupName}/swagger.json"`)_
3. Installed PreSerializeFilters to set up paths to methods:
app.UseSwagger(c =>
{
c.PreSerializeFilters.Add((swaggerDoc, request) =>
{
if (request.Headers.TryGetValue("X-Forwarded-Prefix", out var serverPath))
{
swaggerDoc.Servers = new List
And it works for me!
![image](https://user-images.githubusercontent.com/17874415/216397794-5b6c3369-f5c1-4ece-9d29-79a5fb8a74f1.png)
I am using asp.net core 3.1 with swashbuckle 5. I am not able tofind the way for defining base url. RootUrl option seem to be not coming or (may be i am not able to call it)
Please let me know how to define it