Skip to content

Commit

Permalink
add extension in swagger gen to include api key authentication scheme…
Browse files Browse the repository at this point in the history
…, add extension in open api specification to include api key authentication scheme
  • Loading branch information
Erotokritos Vallianatos committed Jan 30, 2025
1 parent be377bf commit 0ff97ab
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 8 deletions.
36 changes: 31 additions & 5 deletions src/Indice.AspNetCore/Http/Extensions/OpenApiExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,32 @@ public static IEndpointConventionBuilder AddOpenApiSecurityRequirement(this IEnd
});
}

/// <summary>Adds the ApiKey security scheme to the Open API description.</summary>
/// <param name="builder">Builds conventions that will be used for customization of <see cref="EndpointBuilder"/> instances.</param>
/// <param name="scopes">The array of required scopes.</param>

Check warning on line 41 in src/Indice.AspNetCore/Http/Extensions/OpenApiExtensions.cs

View workflow job for this annotation

GitHub Actions / Analyze (csharp)

XML comment has a param tag for 'scopes', but there is no parameter by that name

Check warning on line 41 in src/Indice.AspNetCore/Http/Extensions/OpenApiExtensions.cs

View workflow job for this annotation

GitHub Actions / Analyze (csharp)

XML comment has a param tag for 'scopes', but there is no parameter by that name
/// <returns>The <see cref="IEndpointConventionBuilder"/>.</returns>
public static IEndpointConventionBuilder AddApiKeySecurityRequirement(this IEndpointConventionBuilder builder) {
var scheme = new OpenApiSecurityScheme {
Type = SecuritySchemeType.ApiKey,
Scheme = "ApiKeyScheme",
Description = "Enter the api key to get access",
Name = "X-Api-Key",
Reference = new OpenApiReference {
Type = ReferenceType.SecurityScheme,
Id = "ApiKey"
},
In = ParameterLocation.Header
};

return builder.WithOpenApi(operation => new(operation) {
Security = {
new() {
[scheme] = new List<string>()
}
}
});
}

/// <summary>Adds enum support if needed to a query parameter. Experimental</summary>
/// <param name="builder">Builds conventions that will be used for customization of <see cref="EndpointBuilder"/> instances.</param>
/// <param name="paramName">The parameter name to fix</param>
Expand All @@ -47,7 +73,7 @@ public static IEndpointConventionBuilder WithOpenApiEnum<TEnum>(this IEndpointCo
var isNullable = (enumType.IsValueType && Nullable.GetUnderlyingType(enumType) != null) || true;
var paramSchemaType = enumType.IsFlagsEnum() ? "array" : "string";
var param = op.Parameters.Where(x => paramName.Equals(x.Name, StringComparison.OrdinalIgnoreCase)).First();

param.Schema = new OpenApiSchema() {
Type = "array",
Format = null,
Expand All @@ -69,8 +95,8 @@ public static IEndpointConventionBuilder WithOpenApiEnum<TEnum>(this IEndpointCo
/// <param name="statusCode">The response status code.</param>
/// <param name="contentType">The response content type. Defaults to "application/problem+json".</param>
/// <returns>A <see cref="RouteGroupBuilder"/> that can be used to further customize the endpoint.</returns>
public static RouteGroupBuilder ProducesProblem(this RouteGroupBuilder builder, int statusCode, string? contentType = null) =>
builder.WithMetadata(new ProducesResponseTypeMetadata(statusCode, typeof(ProblemDetails), [ contentType ?? MediaTypeNames.Application.ProblemJson ]));
public static RouteGroupBuilder ProducesProblem(this RouteGroupBuilder builder, int statusCode, string? contentType = null) =>
builder.WithMetadata(new ProducesResponseTypeMetadata(statusCode, typeof(ProblemDetails), [contentType ?? MediaTypeNames.Application.ProblemJson]));

/// <summary>
/// Adds an <see cref="IProducesResponseTypeMetadata"/> with a <see cref="HttpValidationProblemDetails"/> type
Expand All @@ -80,6 +106,6 @@ public static RouteGroupBuilder ProducesProblem(this RouteGroupBuilder builder,
/// <param name="statusCode">The response status code. Defaults to <see cref="StatusCodes.Status400BadRequest"/>.</param>
/// <param name="contentType">The response content type. Defaults to "application/problem+json".</param>
/// <returns>A <see cref="RouteGroupBuilder"/> that can be used to further customize the endpoint.</returns>
public static RouteGroupBuilder ProducesValidationProblem(this RouteGroupBuilder builder, int statusCode = 400, string? contentType = null)
=> builder.WithMetadata(new ProducesResponseTypeMetadata(statusCode, typeof(HttpValidationProblemDetails), [ contentType ?? MediaTypeNames.Application.ProblemJson]));
public static RouteGroupBuilder ProducesValidationProblem(this RouteGroupBuilder builder, int statusCode = 400, string? contentType = null)
=> builder.WithMetadata(new ProducesResponseTypeMetadata(statusCode, typeof(HttpValidationProblemDetails), [contentType ?? MediaTypeNames.Application.ProblemJson]));
}
24 changes: 21 additions & 3 deletions src/Indice.AspNetCore/Swagger/SwaggerConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
namespace Microsoft.Extensions.DependencyInjection;

/// <summary>Swagger configuration extensions the Indice way. Exposes useful defaults for hosting an API. Also leverages appsettings.json configuration through <see cref="GeneralSettings"/> for API setup.</summary>
public static class SwaggerConfig {
public static class SwaggerConfig
{
/// <summary>
/// Since Swashbuckle 4.0 release the support for parameters of type IFormFile is out-of-the-box.
/// That is, the generator will automatically detect these and generate the correct Swagger to describe parameters that are passed in formData.
Expand All @@ -28,7 +29,7 @@ public static void AddFormFileSupport(this SwaggerGenOptions options) {

/// <summary>Adds support for Fluent validation.</summary>
/// <param name="options">The options used to generate the swagger.json file.</param>
public static void AddFluentValidationSupport(this SwaggerGenOptions options) {
public static void AddFluentValidationSupport(this SwaggerGenOptions options) {
options.RequestBodyFilter<RequestBodyFluentValidationSwaggerFilter>();
options.SchemaFilter<SchemaFluentValidationFilter>();
}
Expand Down Expand Up @@ -128,7 +129,7 @@ public static OpenApiInfo AddDoc(this SwaggerGenOptions options, GeneralSettings
if (scope is null) {
title = $"{apiSettings.FriendlyName}. {scopeOrGroup}";
}

Check notice

Code scanning / CodeQL

Inefficient use of ContainsKey Note

Inefficient use of 'ContainsKey' and
indexer
.
if (!options.SwaggerGeneratorOptions.SwaggerDocs.ContainsKey(scopeOrGroup)) {
if (!options.SwaggerGeneratorOptions.SwaggerDocs.ContainsKey(scopeOrGroup)) {
return options.AddDoc(scopeOrGroup, title!, description, version, apiSettings.TermsOfServiceUrl, license, contact);
}
return options.SwaggerGeneratorOptions.SwaggerDocs[scopeOrGroup];
Expand Down Expand Up @@ -303,6 +304,23 @@ public static SwaggerGenOptions AddOAuth2ImplicitFlow(this SwaggerGenOptions opt
return options;
}

/// <summary>Adds api key header security scheme.</summary>
/// <param name="options">The options used to generate the swagger.json file.</param>
/// <param name="settings">General settings for an ASP.NET Core application.</param>
/// <param name="name">A unique name for the scheme.</param>
public static SwaggerGenOptions AddApiKeyAuthentication(this SwaggerGenOptions options, GeneralSettings settings, string name = "ApiKey") {
options.AddSecurityDefinition(name, new OpenApiSecurityScheme {
Type = SecuritySchemeType.ApiKey,
Scheme = "ApiKeyScheme",
Description = "Enter the api key to get access",
Name = "X-Api-Key",
In = ParameterLocation.Header,
});

options.AddSecurityRequirements(name, settings);
return options;
}

/// <summary>A set of default settings for exposing an API.</summary>
/// <param name="options">The options used to generate the swagger.json file.</param>
/// <param name="settings">General settings for an ASP.NET Core application.</param>
Expand Down

0 comments on commit 0ff97ab

Please sign in to comment.