https://github.com/domaindrivendev/Swashbuckle.AspNetCore
By default, Swagger JSON will be exposed at the following route -
"/swagger/{documentName}/swagger.json". If necessary, you can change
this when enabling the Swagger middleware. Custom routes MUST include
the {documentName} parameter.
Why does the template config require this placeholder but the UI config does not?
app.UseSwagger(c =>
{
c.RouteTemplate = "api-docs/{documentName}/swagger.json";
})
NOTE: If you're using the SwaggerUI middleware, you'll also need to update its configuration to reflect the new endpoints:
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/api-docs/v1/swagger.json", "My API V1");
})
What is {documentName} for? Is there a feature to swap it out dynamically or something? Because the UI config in the example has it statically configured. why wouldn't it just be "/api-docs/v1/swagger.json" in the RouteTemplate config too?
documentName
The {documentName} refers to the name you specify in the AddSwaggerGen() method.
The following code uses myapi as the name for a swagger document.
builder.Services.AddSwaggerGen(options =>
options.SwaggerDoc("myapi", new OpenApiInfo { Title = "My API", Version = "v1" })
);
Using UseSwagger as follows
app.UseSwagger(options =>
options.RouteTemplate = "swagger/{documentName}/swagger.json");
leads to a swagger file being created the following location:
/swagger/myapi/swagger.json
Which means your Swagger UI configuration must be
app.UseSwaggerUI(options => {
options.SwaggerEndpoint("/swagger/myapi/swagger.json", "Swagger v1");
});
The Swagger UI can make a UI based on any swagger file, whether it comes from this project or not. That's why it doesn't include the {documentName} placeholder. There isn't a relationship between these, necessarily.
Multiple Swagger UIs
This, for example, is the configuration where I have 1 Swagger Doc, 2 swagger files, and two UI endpoints. I describe the same API, but once using the OpenAPI v3 standard, and once using the old Swagger v2 standard.
builder.Services.AddSwaggerGen(options =>
{
options.SwaggerDoc("myapi", new OpenApiInfo { Title = "My API", Version = "v1" });
});
app.UseSwagger(options =>
{
options.SerializeAsV2 = true;
options.RouteTemplate = "swagger/{documentName}/swaggerV2.json";
});
app.UseSwagger(options =>
{
options.SerializeAsV2 = false;
options.RouteTemplate = "swagger/{documentName}/openapiV3.json";
});
app.UseSwaggerUI(options => {
options.SwaggerEndpoint("/swagger/myapi/openapiV3.json", "OpenApi v3");
options.SwaggerEndpoint("/swagger/myapi/swaggerV2.json", "Swagger v2");
});
When you go to the swagger UI, you will see a dropdown to select one of the two endpoints.
Multiple Swagger Docs
Your app can also have multiple swagger docs. E.g. your 'normal' API + some legacy API stuff.
options.SwaggerDoc("myapi", new OpenApiInfo { Title = "My API", Version = "v1" });
options.SwaggerDoc("myapiLegacy", new OpenApiInfo { Title = "My Legacy API", Version = "v1" });
There are several ways to specify when a method of your project belongs to a certain swagger doc. But the easiest way is to mark it with an attribute:
[HttpPost]
[ApiExplorerSettings(GroupName = "myapiLegacy")]
public void Post([Product product)
So since you can have multiple swagger docs, it makes sense to create a placeholder for it. i.e., {documentName}.
In my swagger UI I now end up with 4 endpoints:
normal api as Swagger V2
normal api as OpenApi V3
legacy api as Swagger V2
legacy api as OpenApi V3
Related
I have a AspNetZero .NetCore + Angular project and I need to implement api versioning to the project for backwards compatibility. I followed a few examples online, but they either don't specify all the steps, or are specific to mvc, and this project uses the AppService pattern. If any one has successfully managed to implement api versioning in a AspNetZero project, I would really appreciate your help.
I'm currently at the swagger page showing two version, but for v1, I get an AmbiguousMatchException and for v2 swagger can't find the v2 file, so I assume it's not getting generated.
In my Application project, I changed the current AppService's namespace to .v1, and created a new AppService with namespace v2, that inherits the old one, and overrides 1 method which will be the v2.
The aim is to be able to call both methods once it's done with i.e:
(http://localhost:9901/api/services/app/Equities/Get_Snapshot or http://localhost:9901/api/services/v1/Equities/Get_Snapshot) and
http://localhost:9901/api/services/v2/Equities/Get_Snapshot
Open Startup.cs in YOURCOMPANY.Web.Host project.
In the ConfigureServices method, scroll down and find services.AddSwaggerGen ...
Implement the following code:
services.AddSwaggerGen(options =>
{
options.SwaggerDoc("v1", new OpenApiInfo()
{
Title = "MY API",
Version = "v1",
Description = "Any description for your V1 APIs."
});
options.SwaggerDoc("public", new OpenApiInfo()
{
Title = "CMS API",
Version = "v2",
Description = "Any description for your V2 APIs."
});
options.DocInclusionPredicate((docName, apiDesc) =>
{
switch (docName)
{
case "v1":
return true;
case "v2":
return apiDesc.GroupName == null || apiDesc.GroupName == "v2";
default:
return false;
}
});
options.ParameterFilter<SwaggerEnumParameterFilter>();
options.SchemaFilter<SwaggerEnumSchemaFilter>();
options.OperationFilter<SwaggerOperationIdFilter>();
options.OperationFilter<SwaggerOperationFilter>();
options.CustomDefaultSchemaIdSelector();
}).AddSwaggerGenNewtonsoftSupport();
Next, in the Configure method, scroll down and find app.UseSwaggerUI ...
Open appsettings.json in YOURCOMPANY.Web.Host and add a new endpoint configuration variable in the "App" field:
"SwaggerEndPoint": "/swagger/v1/swagger.json",
"SwaggerV2EndPoint": "/swagger/v2/swagger.json"
Implement the following code:
app.UseSwaggerUI(options =>
{
options.SwaggerEndpoint(_appConfiguration["App:SwaggerEndPoint"], "MY API V1");
options.SwaggerEndpoint(_appConfiguration["App:SwaggerPublicEndPoint"], "MY API V2");
options.IndexStream = () => Assembly.GetExecutingAssembly()
.GetManifestResourceStream("YOURCOMPANY.Web.wwwroot.swagger.ui.index.html");
options.InjectBaseUrl(_appConfiguration["App:ServerRootAddress"]);
});
Now you can implement APIs in V2 group by adding ApiExplorerSettings attribute in your YOURCOMPANY.Application project; let's assume you have a service named (TestAppService),
Then implement your methods (APIs) in the below namespace, and simply open your Swagger UI and test it.
namespace CMS.TestNameSpace
{
[ApiExplorerSettings(GroupName = "v2")]
[Route("api/[controller]/[action]")]
public class TestAppService : (YOUR)AppServiceBase, ITestAppService
{
[HttpGet]
public async Task<TestDto> GetTest(TestDtoInput input)
{
}
}
}
I am migrating a Web API that has Swagger documenation generated using Swashbuckle from .NET Framework to ASP.NET Core. In the new AspNetCore version I'm using Swashbuckle.AspNetCore v5.0.0-rc2.
This is an internal service and authentication uses an API key provided in a custom HTTP header. In the .NET Framework application, I configured Swashbuckle to enable my API key as follows:
c.ApiKey("apiKey")
.Description("My description")
.Name("MyHttpHeaderName")
.In("header);
and
c.EnableApiKeySupport("MyHtpHeaderName", "header);
How can I enable support for the same API key using Swashbuckle.AspNetCore v5.0.0-rc2?
Much of the information I've found by searching seems to relate to versions of Swashbuckle.AspNetCode prior to v5.0.0-rc2.
This answer is for v5.0.0-rc2 but only covers Bearer Authorization, and doesn't seem to relate to using a custom HTTP header: https://stackoverflow.com/a/57872872/13087
In Swashbuckle.AspNetCore, the authorization setup is all handled with the AddSecurityDefinition method.
In 4.x, you could set up an ApiKeyScheme that describes how to use an API key to authorize requests:
c.AddSecurityDefinition("ApiKey", new ApiKeyScheme()
{
Description = "My description",
Name = "MyHttpHeaderName",
In = "header",
});
Starting with 5.x, Swashbuckle.AspNetCore is no longer using its own models but instead relies on OpenAPI.NET. This means that the above security definition would look like this in 5.x:
c.AddSecurityDefinition("ApiKey", new OpenApiSecurityScheme()
{
Type = SecuritySchemeType.ApiKey,
In = ParameterLocation.Header,
Name = "MyHttpHeaderName",
Description = "My description",
});
Note that you will also have to set up security requirements to configure which security definition is required for what operations. In 5.x, the syntax for that will look like this:
c.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "ApiKey" }
},
new string[] { }
}
});
You can read more about all this in the documentation on security definitions and requirements.
I'm trying to integrate swagger / swashbuckler into a project with UI into a project based on the latest Bot Framework V4 template. However it seems I'm getting only 500 http status codes when I try to navigate to /swagger or /swagger/v1/swagger.json.
The things I'm trying to add are in ConfigureServices:
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new Info { Title = "My API", Version = "v1" });
});
and in Configure:
loggerFactory = loggerFactory;
app.UseDefaultFiles()
.UseStaticFiles()
.UseBotFramework();
app.UseSwagger()
.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
});
I also tried to put the UseSwagger parts before the other but then the bot didn't work anymore as well. Likely there's some collision in endpoints being generated by the different parts but I'd really like to get that swagger part working.
The problem is Swagger requires MVC features to work and it looks like you're using the default templates for a bot which don't actually need MVC so it's not added to avoid the massive overhead that feature brings to the table.
So, you need to add the following in ConfigureServices:
services.AddMvc();
And then the following to Configure. NOTE: The order of the UseXXX calls do matter, but the order you're doing them in right now is fine and I would just do this:
app.UseDefaultFiles()
.UseStaticFiles()
.UseBotFramework()
.UseMvc()
.UseSwagger()
.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
});
In my asp.net core 2.0 solution I want to add Azure AD authentication. With the Azure AD templates inside of VS 2017 you either get JWTBearer authentication-implementation or OpenIdConnect implementation. Open Id also has the reputation of being more secure than OAuth.
How can I use Open ID / JWT with the Swagger Ui, provided by NSwag?
My current workaround would be to allow both OAuth and Open Id, but I need to implement that myself and there is almost no documentation on the new 2.0 APIs. Its also less secure having two authentication workflows. Especially when one is less secure than the other.
Sample by renepape:
app.UseSwaggerUi(typeof(Startup).GetTypeInfo().Assembly, settings =>
{
settings.GeneratorSettings.OperationProcessors.Add(new OperationSecurityScopeProcessor("JWT Token"));
settings.GeneratorSettings.DocumentProcessors.Add(new SecurityDefinitionAppender("JWT Token",
new SwaggerSecurityScheme
{
Type = SwaggerSecuritySchemeType.ApiKey,
Name = "Authorization",
Description = "Copy 'Bearer ' + valid JWT token into field",
In = SwaggerSecurityApiKeyLocation.Header
}));
});
It works with UseSwaggerUi3 also.
I'm using NSwag v13.0.6, and adding JWT support with UseSwaggerUi3 in Startup.Configure (per the answer from #Der_Meister) no longer works.
Instead, I found I had to define the settings in the AddSwaggerDocument call in Startup.ConfigureServices:
// In the ConfigureServices method -- FWIW my app has this right after services.AddMvc()
services.AddSwaggerDocument(config => {
config.DocumentProcessors.Add(new SecurityDefinitionAppender("JWT Token",
new OpenApiSecurityScheme {
Type = OpenApiSecuritySchemeType.ApiKey,
Name = "Authorization",
Description = "Copy 'Bearer ' + valid JWT token into field",
In = OpenApiSecurityApiKeyLocation.Header
}));
});
Note:
Add using NSwag.Generation.Processors.Security up top to resolve SecurityDefinitionAppender
All other types resolve with using NSwag
Then in Startup.Configure all you need is this:
app.UseSwaggerUi3();
Actually my working code in Startup.Configure differs slightly from the above because I use a custom swagger.json (it's a project requirement):
// Required for serving up a static, hand-rolled JSON file for Swagger doc.
app.UseStaticFiles();
// Specify the custom JSON location.
app.UseSwaggerUi3(settings => settings.DocumentPath = "/swagger/v1/swagger.json");
My custom swagger.json includes Bearer Authentication definitions. If you're letting NSwag generate the Swagger authentication definitions then your mileage may vary.
You can use config.AddSecurity as well and it seems a bit more designed for it:
services.AddSwaggerDocument(config => {
config.AddSecurity("JWT token", new OpenApiSecurityScheme
{
Type = OpenApiSecuritySchemeType.ApiKey,
Name = "Authorization",
Description = "Copy 'Bearer ' + valid JWT token into field",
In = OpenApiSecurityApiKeyLocation.Header
});
config.PostProcess = (document) =>
{
document.Info.Version = "v1";
document.Info.Title = "MyRest-API";
document.Info.Description = "ASP.NET Core 3.1 MyRest-API";
};
});
However, both constructions resulted in an option to add a token in the Swagger UI, but didn't result in sending the Authorization header. When I added this line:
config.OperationProcessors.Add(new OperationSecurityScopeProcessor("JWT token"));
it worked. The complete code in ConfigureServices:
services.AddSwaggerDocument(config => {
config.OperationProcessors.Add(new OperationSecurityScopeProcessor("JWT token"));
config.AddSecurity("JWT token", new OpenApiSecurityScheme
{
Type = OpenApiSecuritySchemeType.ApiKey,
Name = "Authorization",
Description = "Copy 'Bearer ' + valid JWT token into field",
In = OpenApiSecurityApiKeyLocation.Header
});
config.PostProcess = (document) =>
{
document.Info.Version = "v1";
document.Info.Title = "MyRest-API";
document.Info.Description = "ASP.NET Core 3.1 MyRest-API";
};
});
And in Configure
app.UseOpenApi();
app.UseSwaggerUi3();
The NSwag settings for the Swagger UI 2.x are very limited. First you need check how Swagger UI supports this and maybe you need to host Swagger UI yourself so that you can parametrize it more (and just generate the Swagger spec with NSwag).
In NSwag v11.7.2 you also have the option to use Swagger UI 3.x, maybe this is supported out-of-the-box in this version (UseSwaggerUi3()).
I am trying to configure swagger for my .Netcore App (1.1) and couldnt generate the docs.
Here is my configuration
public void ConfigureServices(IServiceCollection services) {
services.AddMvcCore().AddVersionedApiExplorer(o => o.GroupNameFormat = "1.0");
services.AddMvc();
services.AddApiVersioning(opt =>
{
opt.ApiVersionReader = new HeaderApiVersionReader("api-version");
opt.DefaultApiVersion = new ApiVersion(1, 0);
opt.ReportApiVersions = true;
opt.AssumeDefaultVersionWhenUnspecified = true;
});
services.AddSwaggerGen(
options =>
{
options.SwaggerDoc("1.0",new Info {Contact = new Contact() {Name="Admin" } });
// add a custom operation filter which sets default values
options.OperationFilter<SwaggerDefaultValues>();
});
}
In the Configure Method
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=User}/{action=Get}/{requestString?}");
});
app.UseSwagger(o=>
{
o.RouteTemplate = "docs/{documentName}/swagger.json";
});
app.UseSwaggerUI(
options =>
{
options.SwaggerEndpoint("/docs/1.0/swagger.json", "1.0");
});
When I run the application,
http://localhost:5000/docs/1.0/swagger.json
I am getting the below methods, None of my API's are discovered.
{"swagger":"2.0","info":{"contact":{"name":"Admin"}},"basePath":"/","paths":{},"definitions":{},"securityDefinitions":{}}
OK, I have reproduced your problem and found that the reason is the value in GroupNameFormat option.
If quickly, instead of const version string you should specify version format. As you want to have version in url as 1.0 you may use:
services.AddMvcCore().AddVersionedApiExplorer( o => o.GroupNameFormat = "VVVV" );
From Version Format section in Documentation:
Format Specifier: VVVV
Description: Major, minor version, and status
Examples: 1-RC -> 1.0-RC, 1.1 -> 1.1, 1 -> 1.0
Regarding AddMvcCore() vs AddMvc():
From the swagger docs at https://github.com/domaindrivendev/Swashbuckle.AspNetCore
Swashbuckle relies heavily on ApiExplorer, the API metadata layer that ships with ASP.NET Core. If you're using the AddMvc helper to bootstrap the MVC stack, then ApiExplorer will be automatically registered and SB will work without issue. However, if you're using AddMvcCore for a more paired-down MVC stack, you'll need to explicitly add the Api Explorer service:
services.AddMvcCore().AddApiExplorer();
If you also want AddVersionedApiExplorer(), chain that after AddApiExplorer()