December 20, 2018

525 words 3 mins read

Swashbuckle behind NGINX Reverse Proxy

Swashbuckle behind NGINX Reverse Proxy

If you want to jump straight to the repo, go to https://github.com/lukerogers/swashbuckle-nginx. After cloning the repo you can just run docker-compose up then open http://localhost:5100/api and you should see the swagger UI.

If you're still reading this, thanks for sticking around. Back to the task at hand!

Assumptions: If you got here looking for running Swashbuckle behind NGINX, I'm going to assume you are familiar with my setup. ASP.NET Core WebAPI service running with Swashbuckle to document the API and test it. For the sake of this article let's assume I want to expose this to the end user.

****I wanted to use NGINX as a reverse proxy in front of our independent services since it's so fast and easy to configure. I love the fact that I can deploy a reverse proxy with just a config file via Docker instead of building anything, so nice! Here is a overly simple diagram of what I'm doing:

Cisco

NGINX will accept all requests and forward them on to the correct service based on a URL convention. Here's an example in case it helps: An end user makes a request to https://mydomain.com/a/Account and NGINX see's the /a in the URL so it forwards the request to the Account service. If the URL had a /c it would forward to the Client service, and so on.

It's nice having those services, but I like being able to see what the API supports without loading up the code or perhaps an end user wants to view the documentation for the API's, so we add Swashbuckle.

The basic setup is straight forward. Install the Swashbuckle.AspNetCore package:

dotnet add package Swashbuckle.AspNetCore

In your ConfigureServices method in Startup.cs add the following:

services.AddSwaggerGen();

In your Configure method, add the following:

app.UseSwagger();
app.UseSwaggerUI(c =>
{
  c.SwaggerEndpoint("swagger/v1/swagger.json", "My API V1");
  c.RoutePrefix = string.Empty;
});

After that you have a swagger doc and a UI to interact with it. Since I was using docker I just fired it up at http://localhost:5101/ and it worked great. Now I want to throw NGINX in front of it so I go to http://localhost:5100/api/ and I see this ugly thing:

Cisco

Oh no! After pulling out my hair, trying too many different ways to get it to work and looking through a bunch of issues in the Swashbuckle repository, I finally come up with the following combination of changes to get it to work:

// Enable middleware to serve generated Swagger as a JSON endpoint.
app.UseSwagger(c => {
  //change the path to include /api
  c.RouteTemplate = "/api/swagger/{documentName}/swagger.json";
});

// Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.),
// specifying the Swagger JSON endpoint.
app.UseSwaggerUI(c =>
{
  //Notice the lack of / making it relative
  c.SwaggerEndpoint("swagger/v1/swagger.json", "My API V1");
  //This is the reverse proxy address
  c.RoutePrefix = "api";
});

I added inline comments to explain things a bit but really it comes down to adding the correct paths so it knows how to reach each piece. This wasn't quite as easy as I hoped to get working but now that I know how to get it to work it is easy to replicate for all services. Hopefully this helps someone else out.