Skip to content

Commit

Permalink
feat(dir): ✨ migrate OpenAPI & SwaggerUI
Browse files Browse the repository at this point in the history
  • Loading branch information
collinbarrett committed Jun 5, 2024
1 parent 7ecc18d commit 238d02b
Show file tree
Hide file tree
Showing 7 changed files with 242 additions and 26 deletions.
110 changes: 86 additions & 24 deletions services/Directory/FilterLists.Directory.Api/Endpoints.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
using FilterLists.Directory.Application.Queries;
using MediatR;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using static FilterLists.Directory.Api.OpenApi.OpenApiTags;

namespace FilterLists.Directory.Api;

Expand All @@ -8,43 +11,102 @@ internal static class Endpoints
internal static void MapEndpoints(this WebApplication app)
{
app.MapGet("/languages",
(IMediator mediator, CancellationToken ct) =>
mediator.CreateStream(new GetLanguages.Request(), ct)
);
(IMediator mediator, CancellationToken ct) =>
mediator.CreateStream(new GetLanguages.Request(), ct)
)
.WithOpenApi(operation => new OpenApiOperation(operation)
{
Tags = [LanguagesTag],
Summary = "Gets the languages targeted by the FilterLists.",
OperationId = nameof(GetLanguages)
});

app.MapGet("/licenses",
(IMediator mediator, CancellationToken ct) =>
mediator.CreateStream(new GetLicenses.Request(), ct)
);
(IMediator mediator, CancellationToken ct) =>
mediator.CreateStream(new GetLicenses.Request(), ct)
)
.WithOpenApi(operation => new OpenApiOperation(operation)
{
Tags = [LicensesTag],
Summary = "Gets the licenses applied to the FilterLists.",
OperationId = nameof(GetLicenses)
});

app.MapGet("/lists",
(IMediator mediator, CancellationToken ct) =>
mediator.CreateStream(new GetLists.Request(), ct)
);
(IMediator mediator, CancellationToken ct) =>
mediator.CreateStream(new GetLists.Request(), ct)
)
.WithOpenApi(operation => new OpenApiOperation(operation)
{
Tags = [FilterListsTag],
Summary = "Gets the FilterLists.",
OperationId = nameof(GetLists)
});

app.MapGet("/lists/{id:int}",
async (int id, IMediator mediator, CancellationToken ct) =>
await mediator.Send(new GetListDetails.Request(id), ct)
);
async (int id, IMediator mediator, CancellationToken ct) =>
await mediator.Send(new GetListDetails.Request(id), ct)
)
.WithOpenApi(operation => new OpenApiOperation(operation)
{
Tags = [FilterListsTag],
Summary = "Gets the details of the FilterList.",
OperationId = nameof(GetListDetails),
Parameters =
[
new OpenApiParameter
{
Name = "id",
In = ParameterLocation.Path,
Description = "The identifier of the FilterList.",
Required = true,
Example = new OpenApiInteger(1)
}
]
});

app.MapGet("/maintainers",
(IMediator mediator, CancellationToken ct) =>
mediator.CreateStream(new GetMaintainers.Request(), ct)
);
(IMediator mediator, CancellationToken ct) =>
mediator.CreateStream(new GetMaintainers.Request(), ct)
)
.WithOpenApi(operation => new OpenApiOperation(operation)
{
Tags = [MaintainersTag],
Summary = "Gets the maintainers of the FilterLists.",
OperationId = nameof(GetMaintainers)
});

app.MapGet("/software",
(IMediator mediator, CancellationToken ct) =>
mediator.CreateStream(new GetSoftware.Request(), ct)
);
(IMediator mediator, CancellationToken ct) =>
mediator.CreateStream(new GetSoftware.Request(), ct)
)
.WithOpenApi(operation => new OpenApiOperation(operation)
{
Tags = [SoftwareTag],
Summary = "Gets the software that subscribes to the FilterLists.",
OperationId = nameof(GetSoftware)
});

app.MapGet("/syntaxes",
(IMediator mediator, CancellationToken ct) =>
mediator.CreateStream(new GetSyntaxes.Request(), ct)
);
(IMediator mediator, CancellationToken ct) =>
mediator.CreateStream(new GetSyntaxes.Request(), ct)
)
.WithOpenApi(operation => new OpenApiOperation(operation)
{
Tags = [SyntaxesTag],
Summary = "Gets the syntaxes of the FilterLists.",
OperationId = nameof(GetSyntaxes)
});

app.MapGet("/tags",
(IMediator mediator, CancellationToken ct) =>
mediator.CreateStream(new GetTags.Request(), ct)
);
(IMediator mediator, CancellationToken ct) =>
mediator.CreateStream(new GetTags.Request(), ct)
)
.WithOpenApi(operation => new OpenApiOperation(operation)
{
Tags = [TagsTag],
Summary = "Gets the tags of the FilterLists.",
OperationId = nameof(GetTags)
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,9 @@
<ProjectReference Include="..\FilterLists.Directory.Application\FilterLists.Directory.Application.csproj"/>
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.6"/>
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2"/>
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using Microsoft.OpenApi.Models;
using ConfigurationExtensions = FilterLists.Directory.Application.ConfigurationExtensions;

namespace FilterLists.Directory.Api.OpenApi;

internal static class OpenApiConfigurationExtensions
{
internal static void AddOpenApiGen(this IServiceCollection services)
{
services.AddEndpointsApiExplorer();
services.AddSwaggerGen(options =>
{
options.SwaggerDoc(
"v1",
new OpenApiInfo
{
Title = "FilterLists Directory API",
Description = "An ASP.NET Core API serving the core FilterList information.",
Version = "v1",
TermsOfService =
new Uri("https://github.com/collinbarrett/FilterLists/blob/main/.github/CODE_OF_CONDUCT.md"),
Contact = new OpenApiContact { Name = "FilterLists", Url = new Uri("https://filterlists.com") },
License = new OpenApiLicense
{
Name = "MIT License",
Url = new Uri("https://github.com/collinbarrett/FilterLists/blob/main/LICENSE")
}
});
// include view model xml comments
var xmlFilename = $"{typeof(ConfigurationExtensions).Assembly.GetName().Name}.xml";
options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFilename));
// include OpenApiTag Description and ExternalDocs
options.DocumentFilter<OpenApiTags.TagDescriptionsDocumentFilter>();
});
}
}
106 changes: 106 additions & 0 deletions services/Directory/FilterLists.Directory.Api/OpenApi/OpenApiTags.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
using FilterLists.Directory.Infrastructure.Persistence.Queries.Context;
using FilterLists.Directory.Infrastructure.Persistence.Queries.Entities;
using JetBrains.Annotations;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;

namespace FilterLists.Directory.Api.OpenApi;

internal static class OpenApiTags
{
internal static readonly OpenApiTag LanguagesTag = new()
{
Name = nameof(QueryDbContext.Languages),
Description = "A written form of communication used by sites targeted by a FilterList",
ExternalDocs = new OpenApiExternalDocs
{
Description = $"{nameof(FilterLists)} {nameof(Language)} Wiki",
Url = new Uri($"https://github.com/collinbarrett/FilterLists/wiki/{nameof(Language)}")
}
};

internal static readonly OpenApiTag LicensesTag = new()
{
Name = nameof(QueryDbContext.Licenses),
Description = "A legal document governing the use or redistribution of a FilterList",
ExternalDocs = new OpenApiExternalDocs
{
Description = $"{nameof(FilterLists)} {nameof(License)} Wiki",
Url = new Uri($"https://github.com/collinbarrett/FilterLists/wiki/{nameof(License)}")
}
};

internal static readonly OpenApiTag FilterListsTag = new()
{
Name = nameof(QueryDbContext.FilterLists),
Description = "A text file containing a list of rules for blocking or manipulating internet traffic",
ExternalDocs = new OpenApiExternalDocs
{
Description = $"{nameof(FilterLists)} {nameof(FilterList)} Wiki",
Url = new Uri($"https://github.com/collinbarrett/FilterLists/wiki/{nameof(FilterList)}")
}
};

internal static readonly OpenApiTag MaintainersTag = new()
{
Name = nameof(QueryDbContext.Maintainers),
Description = "An individual, group, or organization who maintains one or more FilterLists",
ExternalDocs = new OpenApiExternalDocs
{
Description = $"{nameof(FilterLists)} {nameof(Maintainer)} Wiki",
Url = new Uri($"https://github.com/collinbarrett/FilterLists/wiki/{nameof(Maintainer)}")
}
};

internal static readonly OpenApiTag SoftwareTag = new()
{
Name = nameof(QueryDbContext.Software),
Description = "An application, browser extension, or other utility that consumes FilterLists",
ExternalDocs = new OpenApiExternalDocs
{
Description = $"{nameof(FilterLists)} {nameof(Software)} Wiki",
Url = new Uri($"https://github.com/collinbarrett/FilterLists/wiki/{nameof(Software)}")
}
};

internal static readonly OpenApiTag SyntaxesTag = new()
{
Name = nameof(QueryDbContext.Syntaxes),
Description = "A named set of rules that govern the format of a FilterList",
ExternalDocs = new OpenApiExternalDocs
{
Description = $"{nameof(FilterLists)} {nameof(Syntax)} Wiki",
Url = new Uri($"https://github.com/collinbarrett/FilterLists/wiki/{nameof(Syntax)}")
}
};

internal static readonly OpenApiTag TagsTag = new()
{
Name = nameof(QueryDbContext.Tags),
Description =
"A generic taxonomy applied to a FilterList to provide information about its contents and/or purpose",
ExternalDocs = new OpenApiExternalDocs
{
Description = $"{nameof(FilterLists)} {nameof(Tag)} Wiki",
Url = new Uri($"https://github.com/collinbarrett/FilterLists/wiki/{nameof(Tag)}")
}
};

[UsedImplicitly]
internal class TagDescriptionsDocumentFilter : IDocumentFilter
{
public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
{
swaggerDoc.Tags =
[
LanguagesTag,
LicensesTag,
FilterListsTag,
MaintainersTag,
SoftwareTag,
SyntaxesTag,
TagsTag
];
}
}
}
4 changes: 4 additions & 0 deletions services/Directory/FilterLists.Directory.Api/Program.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
using FilterLists.Directory.Api;
using FilterLists.Directory.Api.OpenApi;
using FilterLists.Directory.Application;

var builder = WebApplication.CreateBuilder(args);

builder.WebHost.ConfigureKestrel(serverOptions => serverOptions.AddServerHeader = false);
builder.AddServiceDefaults();
builder.Services.AddProblemDetails();
builder.Services.AddOpenApiGen();
builder.AddApplication();

var app = builder.Build();

app.UseExceptionHandler();
app.MapEndpoints();
app.MapDefaultEndpoints();
app.UseSwagger();
app.UseSwaggerUI();

app.Run();
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "lists",
"launchUrl": "swagger/index.html",
"applicationUrl": "http://localhost:5444",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
Expand All @@ -15,7 +15,7 @@
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "lists",
"launchUrl": "swagger/index.html",
"applicationUrl": "https://localhost:7490;http://localhost:5444",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>

<ItemGroup>
Expand Down

0 comments on commit 238d02b

Please sign in to comment.