0
0
mirror of https://github.com/alex289/CleanArchitecture.git synced 2025-06-29 18:21:08 +00:00

feat: Add swagger attribute for sorting

This commit is contained in:
Alexander Konietzko 2023-09-09 21:21:23 +02:00
parent 6d63df1eda
commit 3410c8575d
No known key found for this signature in database
GPG Key ID: BA6905F37AEC2B5B
8 changed files with 87 additions and 18 deletions

View File

@ -7,29 +7,29 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AspNetCore.HealthChecks.ApplicationStatus" Version="7.0.0"/>
<PackageReference Include="AspNetCore.HealthChecks.Rabbitmq" Version="7.0.0"/>
<PackageReference Include="AspNetCore.HealthChecks.Redis" Version="7.0.0"/>
<PackageReference Include="AspNetCore.HealthChecks.SqlServer" Version="7.0.0"/>
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="7.1.0"/>
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.10"/>
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.10"/>
<PackageReference Include="AspNetCore.HealthChecks.ApplicationStatus" Version="7.0.0" />
<PackageReference Include="AspNetCore.HealthChecks.Rabbitmq" Version="7.0.0" />
<PackageReference Include="AspNetCore.HealthChecks.Redis" Version="7.0.0" />
<PackageReference Include="AspNetCore.HealthChecks.SqlServer" Version="7.0.0" />
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="7.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.10" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.10">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="7.0.10"/>
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="7.0.10"/>
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="7.0.10"/>
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0"/>
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="6.5.0"/>
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="7.0.10" />
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="7.0.10" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="7.0.10" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="6.5.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\CleanArchitecture.Application\CleanArchitecture.Application.csproj"/>
<ProjectReference Include="..\CleanArchitecture.Domain\CleanArchitecture.Domain.csproj"/>
<ProjectReference Include="..\CleanArchitecture.gRPC\CleanArchitecture.gRPC.csproj"/>
<ProjectReference Include="..\CleanArchitecture.Infrastructure\CleanArchitecture.Infrastructure.csproj"/>
<ProjectReference Include="..\CleanArchitecture.Application\CleanArchitecture.Application.csproj" />
<ProjectReference Include="..\CleanArchitecture.Domain\CleanArchitecture.Domain.csproj" />
<ProjectReference Include="..\CleanArchitecture.gRPC\CleanArchitecture.gRPC.csproj" />
<ProjectReference Include="..\CleanArchitecture.Infrastructure\CleanArchitecture.Infrastructure.csproj" />
</ItemGroup>
</Project>

View File

@ -1,10 +1,13 @@
using System;
using System.Threading.Tasks;
using CleanArchitecture.Api.Models;
using CleanArchitecture.Api.Swagger;
using CleanArchitecture.Application.Interfaces;
using CleanArchitecture.Application.SortProviders;
using CleanArchitecture.Application.ViewModels;
using CleanArchitecture.Application.ViewModels.Sorting;
using CleanArchitecture.Application.ViewModels.Tenants;
using CleanArchitecture.Domain.Entities;
using CleanArchitecture.Domain.Notifications;
using MediatR;
using Microsoft.AspNetCore.Authorization;
@ -34,7 +37,7 @@ public sealed class TenantController : ApiController
[FromQuery] PageQuery query,
[FromQuery] string searchTerm = "",
[FromQuery] bool includeDeleted = false,
[FromQuery] SortQuery? sortQuery = null)
[FromQuery, SortableFieldsAttribute<TenantViewModelSortProvider, TenantViewModel, Tenant>] SortQuery? sortQuery = null)
{
var tenants = await _tenantService.GetAllTenantsAsync(
query,

View File

@ -1,10 +1,13 @@
using System;
using System.Threading.Tasks;
using CleanArchitecture.Api.Models;
using CleanArchitecture.Api.Swagger;
using CleanArchitecture.Application.Interfaces;
using CleanArchitecture.Application.SortProviders;
using CleanArchitecture.Application.ViewModels;
using CleanArchitecture.Application.ViewModels.Sorting;
using CleanArchitecture.Application.ViewModels.Users;
using CleanArchitecture.Domain.Entities;
using CleanArchitecture.Domain.Notifications;
using MediatR;
using Microsoft.AspNetCore.Authorization;
@ -34,7 +37,7 @@ public sealed class UserController : ApiController
[FromQuery] PageQuery query,
[FromQuery] string searchTerm = "",
[FromQuery] bool includeDeleted = false,
[FromQuery] SortQuery? sortQuery = null)
[FromQuery, SortableFieldsAttribute<UserViewModelSortProvider, UserViewModel, User>] SortQuery? sortQuery = null)
{
var users = await _userService.GetAllUsersAsync(
query,

View File

@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.Text;
using CleanArchitecture.Api.Swagger;
using CleanArchitecture.Domain.Settings;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Extensions.Configuration;
@ -34,6 +35,10 @@ public static class ServiceCollectionExtension
Scheme = "bearer"
});
c.ParameterFilter<SortableFieldsAttributeFilter>();
c.SupportNonNullableReferenceTypes();
c.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{

View File

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using CleanArchitecture.Application.ViewModels.Sorting;
namespace CleanArchitecture.Api.Swagger;
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false)]
public sealed class SortableFieldsAttribute<TSortingProvider, TViewModel, TEntity>
: SwaggerSortableFieldsAttribute
where TSortingProvider : ISortingExpressionProvider<TViewModel, TEntity>, new()
{
public override IEnumerable<string> GetFields()
{
return new TSortingProvider().GetSortingExpressions().Keys;
}
}

View File

@ -0,0 +1,32 @@
using System.Linq;
using System.Reflection;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace CleanArchitecture.Api.Swagger;
public sealed class SortableFieldsAttributeFilter : IParameterFilter
{
public void Apply(OpenApiParameter parameter, ParameterFilterContext context)
{
if (context.ParameterInfo is null)
{
return;
}
var attribute = context.ParameterInfo
.GetCustomAttributes<SwaggerSortableFieldsAttribute>()
.SingleOrDefault();
if (attribute is null)
{
return;
}
var description = string.Join("<br/>", attribute.GetFields().Order());
parameter.Description = $"{parameter.Description}<br/><br/>" +
$"**Allowed values:**<br/>{description}";
}
}

View File

@ -0,0 +1,9 @@
using System;
using System.Collections.Generic;
namespace CleanArchitecture.Api.Swagger;
public abstract class SwaggerSortableFieldsAttribute : Attribute
{
public abstract IEnumerable<string> GetFields();
}

View File

@ -10,6 +10,7 @@ public sealed class SortQuery
public ReadOnlyCollection<SortParameter> Parameters { get; private set; } = new(Array.Empty<SortParameter>());
[FromQuery(Name = "order_by")]
public string? Query
{