21

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.

Anthony Neace
  • 25,013
  • 7
  • 114
  • 129
Dmitriy
  • 638
  • 1
  • 6
  • 12

1 Answers1

24

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.

Anthony Neace
  • 25,013
  • 7
  • 114
  • 129
  • This github article was the first I read, the last comment is exactly where I got the code that I put in my question. It didn't work. I would love to try it the way you describe, because at least now I see what is expected as a value. But the code that you provided doesn't work as is. VS complains about SwaggerSpecConfig as undefined. Can you provide full code and a version of swashbuckle that this code works with? Please. – Dmitriy May 02 '15 at 13:39
  • @user1803063 See my update. I am using Swashbuckle.Core 4 with some unrelated extensions. Looking at Swashbuckle 5, it looks like this feature for base url has been cleaned up quite a bit and made easier to find and use. Don't worry about SwaggerSpecConfig and `ResolveBasePathUsing` if you're using 5, it has been replaced with the httpConfiguration extension method `EnableSwagger`. Sorry about the confusion, I haven't needed to update to 5 yet and this looked like a very similar problem that I've had before. :) – Anthony Neace May 02 '15 at 15:31
  • Unfortunately it doesn't work. I am starting to think it might be a bug. I tried to put everything in the RootUrl http://localhost, http://localhost/web and http://localhost/web/api it still generates 404 for me. – Dmitriy May 02 '15 at 22:14
  • 1
    The above provided answer is correct, the problem I was having the swashbuckle was installed in API. Once it was installed in the Web project (and some URI rewriting changed) it started to function correctly. It is complicated to have this mix of routes and realtive and absolute paths. But it works now. Thank you for your help. – Dmitriy May 20 '15 at 04:45
  • @Dmitry Do you mean that You installed swagger in web proj, but it worked for api aproj? – Kate Sep 09 '20 at 10:35