Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I make url path in Swashbuckle/Swaggerwork when api is served from inside another project?

all. I am trying to document a WebApi 2 using Swashbuckle package.

All works great if the API is running by itself i.e. localhost/api/swagger brings me to ui and localhost/api/swagger/docs/v1 to json.

However the producation app initializes this same Webapi project by running webapiconfig method of this project from global.asax.cs in another - now web project (the main application one). So the api url looks like localhost/web/api instead of localhost/api.

Now swashbuckle doesn't work like that at all.

  • localhost/api/swagger generates error cannot load 'API.WebApiApplication', well of course
  • localhost/web/swagger = 404
  • localhost/web/api/swagger = 404

I tried to look everywhere, but all I found is workaround.

c.RootUrl(req => req.RequestUri.GetLeftPart(UriPartial.Authority) + VirtualPathUtility.ToAbsolute("~/").TrimEnd('/'));

Unfortunately it doesn't work, now maybe it should and I just need to change something but I don't even know what exactly this property expects and what it should be set to.

May be it's not even applicable - maybe setup we have requires something else or some swashbuckle code changes.

I will appreciate any help you can provide. I really starting to like swagger (and swashbuckle) for rest documentation.

like image 883
Dmitriy Avatar asked May 01 '15 21:05

Dmitriy


1 Answers

For Swashbuckle 5.x:

This appears to be set by an extension method of httpConfiguration called EnableSwagger. Swashbuckle 5.x migration readme notes that this replaces SwaggerSpecConfig. SwaggerDocConfig RootUrl() specifically replaces ResolveBasePathUsing() from 4.x.

This practically works the same as it did before, looks like the biggest change was that it was renamed and moved into SwaggerDocConfig:

public void RootUrl(Func<HttpRequestMessage, string> rootUrlResolver)

An example from the readme, tweaked for brevity:

string myCustomBasePath = @"http://mycustombasepath.com";

httpConfiguration
    .EnableSwagger(c =>
        {
            c.RootUrl(req => myCustomBasePath);

            // The rest of your additional metadata goes here
        });

For Swashbuckle 4.x:

Use SwaggerSpecConfig ResolveBasePathUsing and have your lambda read your known endpoint.

ResolveBasePathUsing:

public SwaggerSpecConfig ResolveBasePathUsing(Func<HttpRequestMessage, string> basePathResolver);

My API is behind a load balancer and this was a helpful workaround to providing a base address. Here's a dumb example to use ResolveBasePathUsing to resolve the path with a known base path.

string myCustomBasePath = @"http://mycustombasepath.com";

SwaggerSpecConfig.Customize(c =>
{
    c.ResolveBasePathUsing((req) => myCustomBasePath);
}

I hardcoded the endpoint for clarity, but you can define it anywhere. You can even use the request object to attempt to cleanup your request uri to point to /web/api instead of /api.

The developer commented on this workaround on GitHub last year:

The lambda takes the current HttpRequest (i.e. the request for a given Swagger ApiDeclaration) and should return a string to be used as the baseUrl for your Api. For load-balanced apps, this should return the load-balancer path.

The default implementation is as follows:

(req) => req.RequestUri.GetLeftPart(UriPartial.Authority) +  req.GetConfiguration().VirtualPathRoot.TrimEnd('/');

...

Re relative paths, the Swagger spec requires absolute paths because the URL at which the Swagger is being served need not be the URL of the actual API.

...

The lambda is passed a HttpRequestMessage instance ... you should be able to use this to get at the RequestUri etc. Another option, you could just place the host name in your web.config and have the lambda just read it from there.

like image 53
Anthony Neace Avatar answered Oct 20 '22 00:10

Anthony Neace