From 9798f4f6849cbef3fdaf57c586ed041aa5da920d Mon Sep 17 00:00:00 2001 From: maurei Date: Fri, 3 Sep 2021 16:38:04 +0200 Subject: [PATCH 01/23] Add minimal Swashbuckle setup --- JsonApiDotNetCore.sln | 30 +++++++++++++++++++ .../Properties/AssemblyInfo.cs | 1 + src/OpenApi/OpenApi.csproj | 18 +++++++++++ src/OpenApi/OpenApiEndpointConvention.cs | 20 +++++++++++++ src/OpenApi/ServiceCollectionExtensions.cs | 22 ++++++++++++++ 5 files changed, 91 insertions(+) create mode 100644 src/OpenApi/OpenApi.csproj create mode 100644 src/OpenApi/OpenApiEndpointConvention.cs create mode 100644 src/OpenApi/ServiceCollectionExtensions.cs diff --git a/JsonApiDotNetCore.sln b/JsonApiDotNetCore.sln index e5e97193c2..7747bf34a1 100644 --- a/JsonApiDotNetCore.sln +++ b/JsonApiDotNetCore.sln @@ -44,6 +44,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MultiDbContextTests", "test EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestBuildingBlocks", "test\TestBuildingBlocks\TestBuildingBlocks.csproj", "{210FD61E-FF5D-4CEE-8E0D-C739ECCCBA21}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenApi", "src\OpenApi\OpenApi.csproj", "{71287D6F-6C3B-44B4-9FCA-E78FE3F02289}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenApiTests", "test\OpenApiTests\OpenApiTests.csproj", "{B693DE14-BB28-496F-AB39-B4E674ABCA80}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -210,6 +214,30 @@ Global {210FD61E-FF5D-4CEE-8E0D-C739ECCCBA21}.Release|x64.Build.0 = Release|Any CPU {210FD61E-FF5D-4CEE-8E0D-C739ECCCBA21}.Release|x86.ActiveCfg = Release|Any CPU {210FD61E-FF5D-4CEE-8E0D-C739ECCCBA21}.Release|x86.Build.0 = Release|Any CPU + {71287D6F-6C3B-44B4-9FCA-E78FE3F02289}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {71287D6F-6C3B-44B4-9FCA-E78FE3F02289}.Debug|Any CPU.Build.0 = Debug|Any CPU + {71287D6F-6C3B-44B4-9FCA-E78FE3F02289}.Debug|x64.ActiveCfg = Debug|Any CPU + {71287D6F-6C3B-44B4-9FCA-E78FE3F02289}.Debug|x64.Build.0 = Debug|Any CPU + {71287D6F-6C3B-44B4-9FCA-E78FE3F02289}.Debug|x86.ActiveCfg = Debug|Any CPU + {71287D6F-6C3B-44B4-9FCA-E78FE3F02289}.Debug|x86.Build.0 = Debug|Any CPU + {71287D6F-6C3B-44B4-9FCA-E78FE3F02289}.Release|Any CPU.ActiveCfg = Release|Any CPU + {71287D6F-6C3B-44B4-9FCA-E78FE3F02289}.Release|Any CPU.Build.0 = Release|Any CPU + {71287D6F-6C3B-44B4-9FCA-E78FE3F02289}.Release|x64.ActiveCfg = Release|Any CPU + {71287D6F-6C3B-44B4-9FCA-E78FE3F02289}.Release|x64.Build.0 = Release|Any CPU + {71287D6F-6C3B-44B4-9FCA-E78FE3F02289}.Release|x86.ActiveCfg = Release|Any CPU + {71287D6F-6C3B-44B4-9FCA-E78FE3F02289}.Release|x86.Build.0 = Release|Any CPU + {B693DE14-BB28-496F-AB39-B4E674ABCA80}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B693DE14-BB28-496F-AB39-B4E674ABCA80}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B693DE14-BB28-496F-AB39-B4E674ABCA80}.Debug|x64.ActiveCfg = Debug|Any CPU + {B693DE14-BB28-496F-AB39-B4E674ABCA80}.Debug|x64.Build.0 = Debug|Any CPU + {B693DE14-BB28-496F-AB39-B4E674ABCA80}.Debug|x86.ActiveCfg = Debug|Any CPU + {B693DE14-BB28-496F-AB39-B4E674ABCA80}.Debug|x86.Build.0 = Debug|Any CPU + {B693DE14-BB28-496F-AB39-B4E674ABCA80}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B693DE14-BB28-496F-AB39-B4E674ABCA80}.Release|Any CPU.Build.0 = Release|Any CPU + {B693DE14-BB28-496F-AB39-B4E674ABCA80}.Release|x64.ActiveCfg = Release|Any CPU + {B693DE14-BB28-496F-AB39-B4E674ABCA80}.Release|x64.Build.0 = Release|Any CPU + {B693DE14-BB28-496F-AB39-B4E674ABCA80}.Release|x86.ActiveCfg = Release|Any CPU + {B693DE14-BB28-496F-AB39-B4E674ABCA80}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -228,6 +256,8 @@ Global {6CAFDDBE-00AB-4784-801B-AB419C3C3A26} = {026FBC6C-AF76-4568-9B87-EC73457899FD} {EC3202C6-1D4C-4B14-A599-B9D3F27FE3BA} = {24B15015-62E5-42E1-9BA0-ECE6BE7AA15F} {210FD61E-FF5D-4CEE-8E0D-C739ECCCBA21} = {24B15015-62E5-42E1-9BA0-ECE6BE7AA15F} + {71287D6F-6C3B-44B4-9FCA-E78FE3F02289} = {7A2B7ADD-ECB5-4D00-AA6A-D45BD11C97CF} + {B693DE14-BB28-496F-AB39-B4E674ABCA80} = {24B15015-62E5-42E1-9BA0-ECE6BE7AA15F} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {A2421882-8F0A-4905-928F-B550B192F9A4} diff --git a/src/JsonApiDotNetCore/Properties/AssemblyInfo.cs b/src/JsonApiDotNetCore/Properties/AssemblyInfo.cs index e4f127b725..038bd92975 100644 --- a/src/JsonApiDotNetCore/Properties/AssemblyInfo.cs +++ b/src/JsonApiDotNetCore/Properties/AssemblyInfo.cs @@ -1,5 +1,6 @@ using System.Runtime.CompilerServices; +[assembly: InternalsVisibleTo("OpenApi")] [assembly: InternalsVisibleTo("Benchmarks")] [assembly: InternalsVisibleTo("JsonApiDotNetCoreTests")] [assembly: InternalsVisibleTo("UnitTests")] diff --git a/src/OpenApi/OpenApi.csproj b/src/OpenApi/OpenApi.csproj new file mode 100644 index 0000000000..b626d4c029 --- /dev/null +++ b/src/OpenApi/OpenApi.csproj @@ -0,0 +1,18 @@ + + + + net5.0 + + + + + + + + + + + + + + diff --git a/src/OpenApi/OpenApiEndpointConvention.cs b/src/OpenApi/OpenApiEndpointConvention.cs new file mode 100644 index 0000000000..ffdcd60c34 --- /dev/null +++ b/src/OpenApi/OpenApiEndpointConvention.cs @@ -0,0 +1,20 @@ +using System.Linq; +using JsonApiDotNetCore; +using Microsoft.AspNetCore.Mvc.ApplicationModels; +using Microsoft.AspNetCore.Mvc.Routing; + +namespace OpenApi +{ + internal sealed class OpenApiEndpointConvention : IActionModelConvention + { + public void Apply(ActionModel action) + { + ArgumentGuard.NotNull(action, nameof(action)); + + if (!action.ActionMethod.GetCustomAttributes(true).OfType().Any()) + { + action.ApiExplorer.IsVisible = false; + } + } + } +} diff --git a/src/OpenApi/ServiceCollectionExtensions.cs b/src/OpenApi/ServiceCollectionExtensions.cs new file mode 100644 index 0000000000..aba9485522 --- /dev/null +++ b/src/OpenApi/ServiceCollectionExtensions.cs @@ -0,0 +1,22 @@ +using System; +using JsonApiDotNetCore; +using Microsoft.Extensions.DependencyInjection; +using Swashbuckle.AspNetCore.SwaggerGen; + +namespace OpenApi +{ + public static class ServiceCollectionExtensions + { + public static void AddOpenApi(this IServiceCollection services, IMvcCoreBuilder builder, Action setupSwaggerGenAction) + { + ArgumentGuard.NotNull(services, nameof(services)); + ArgumentGuard.NotNull(builder, nameof(builder)); + + builder.AddApiExplorer(); + + builder.AddMvcOptions(options => options.Conventions.Add(new OpenApiEndpointConvention())); + + services.AddSwaggerGen(setupSwaggerGenAction); + } + } +} From cf699c9c8d3c071fd38a096c763b763f24cb02d5 Mon Sep 17 00:00:00 2001 From: maurei Date: Mon, 6 Sep 2021 17:49:22 +0200 Subject: [PATCH 02/23] add tests, run ci build for openapi, use build props for openapi projects --- Directory.Build.props | 1 + appveyor.yml | 7 + src/OpenApi/OpenApi.csproj | 11 +- test/OpenApiTests/Airplane.cs | 21 + test/OpenApiTests/AirplanesController.cs | 15 + test/OpenApiTests/Flight.cs | 17 + test/OpenApiTests/FlightsController.cs | 15 + test/OpenApiTests/OpenApiDbContext.cs | 26 + test/OpenApiTests/OpenApiDocumentTests.cs | 59 ++ test/OpenApiTests/OpenApiStartup.cs | 40 + test/OpenApiTests/OpenApiTests.csproj | 27 + test/OpenApiTests/openapi.json | 963 ++++++++++++++++++++++ 12 files changed, 1195 insertions(+), 7 deletions(-) create mode 100644 test/OpenApiTests/Airplane.cs create mode 100644 test/OpenApiTests/AirplanesController.cs create mode 100644 test/OpenApiTests/Flight.cs create mode 100644 test/OpenApiTests/FlightsController.cs create mode 100644 test/OpenApiTests/OpenApiDbContext.cs create mode 100644 test/OpenApiTests/OpenApiDocumentTests.cs create mode 100644 test/OpenApiTests/OpenApiStartup.cs create mode 100644 test/OpenApiTests/OpenApiTests.csproj create mode 100644 test/OpenApiTests/openapi.json diff --git a/Directory.Build.props b/Directory.Build.props index dbd5c5ab26..5541886347 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -4,6 +4,7 @@ 5.0.* 5.0.* 5.0.* + 6.1.* $(MSBuildThisFileDirectory)CodingGuidelines.ruleset diff --git a/appveyor.yml b/appveyor.yml index e5b0f781ad..3c61231177 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -15,6 +15,7 @@ environment: branches: only: - master + - openapi - develop - unstable - /release\/.+/ @@ -36,6 +37,12 @@ for: services: - postgresql101 # REF: https://github.com/docascode/docfx-seed/blob/master/appveyor.yml + clone_script: + # This ensures the base branch is loaded which is required for regitlint to run. + - ps: | + git clone --branch=$env:APPVEYOR_REPO_BRANCH git@github.com:$env:APPVEYOR_REPO_NAME.git $env:APPVEYOR_BUILD_FOLDER + git fetch -q origin +refs/pull/$env:APPVEYOR_PULL_REQUEST_NUMBER/merge: + git checkout -qf FETCH_HEAD before_build: - pwsh: | if (-Not $env:APPVEYOR_PULL_REQUEST_TITLE) { diff --git a/src/OpenApi/OpenApi.csproj b/src/OpenApi/OpenApi.csproj index b626d4c029..6b27d5c5f7 100644 --- a/src/OpenApi/OpenApi.csproj +++ b/src/OpenApi/OpenApi.csproj @@ -1,18 +1,15 @@ - - net5.0 + $(NetCoreAppVersion) - - - - + + + - diff --git a/test/OpenApiTests/Airplane.cs b/test/OpenApiTests/Airplane.cs new file mode 100644 index 0000000000..9c035d9c80 --- /dev/null +++ b/test/OpenApiTests/Airplane.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using JetBrains.Annotations; +using JsonApiDotNetCore.Resources; +using JsonApiDotNetCore.Resources.Annotations; + +namespace OpenApiTests +{ + [UsedImplicitly(ImplicitUseTargetFlags.Members)] + public sealed class Airplane : Identifiable + { + [Attr] + public int SeatingCapacity { get; set; } + + [Attr] + public DateTimeOffset ManufacturedAt { get; set; } + + [HasMany] + public ISet Flights { get; set; } + } +} diff --git a/test/OpenApiTests/AirplanesController.cs b/test/OpenApiTests/AirplanesController.cs new file mode 100644 index 0000000000..40c95d1975 --- /dev/null +++ b/test/OpenApiTests/AirplanesController.cs @@ -0,0 +1,15 @@ +using JsonApiDotNetCore.Configuration; +using JsonApiDotNetCore.Controllers; +using JsonApiDotNetCore.Services; +using Microsoft.Extensions.Logging; + +namespace OpenApiTests +{ + public sealed class AirplanesController : JsonApiController + { + public AirplanesController(IJsonApiOptions options, ILoggerFactory loggerFactory, IResourceService resourceService) + : base(options, loggerFactory, resourceService) + { + } + } +} diff --git a/test/OpenApiTests/Flight.cs b/test/OpenApiTests/Flight.cs new file mode 100644 index 0000000000..57dd44abe7 --- /dev/null +++ b/test/OpenApiTests/Flight.cs @@ -0,0 +1,17 @@ +using System; +using JetBrains.Annotations; +using JsonApiDotNetCore.Resources; +using JsonApiDotNetCore.Resources.Annotations; + +namespace OpenApiTests +{ + [UsedImplicitly(ImplicitUseTargetFlags.Members)] + public sealed class Flight : Identifiable + { + [Attr] + public string Destination { get; set; } + + [Attr] + public DateTimeOffset PlannedDeparture { get; set; } + } +} diff --git a/test/OpenApiTests/FlightsController.cs b/test/OpenApiTests/FlightsController.cs new file mode 100644 index 0000000000..aa24d72f32 --- /dev/null +++ b/test/OpenApiTests/FlightsController.cs @@ -0,0 +1,15 @@ +using JsonApiDotNetCore.Configuration; +using JsonApiDotNetCore.Controllers; +using JsonApiDotNetCore.Services; +using Microsoft.Extensions.Logging; + +namespace OpenApiTests +{ + public sealed class FlightsController : JsonApiController + { + public FlightsController(IJsonApiOptions options, ILoggerFactory loggerFactory, IResourceService resourceService) + : base(options, loggerFactory, resourceService) + { + } + } +} diff --git a/test/OpenApiTests/OpenApiDbContext.cs b/test/OpenApiTests/OpenApiDbContext.cs new file mode 100644 index 0000000000..e44e74505b --- /dev/null +++ b/test/OpenApiTests/OpenApiDbContext.cs @@ -0,0 +1,26 @@ +using JetBrains.Annotations; +using Microsoft.EntityFrameworkCore; + +// @formatter:wrap_chained_method_calls chop_always +// @formatter:keep_existing_linebreaks true + +namespace OpenApiTests +{ + [UsedImplicitly(ImplicitUseTargetFlags.Members)] + public sealed class OpenApiDbContext : DbContext + { + public DbSet Airplanes { get; set; } + public DbSet Flights { get; set; } + + public OpenApiDbContext(DbContextOptions options) + : base(options) + { + } + + protected override void OnModelCreating(ModelBuilder builder) + { + builder.Entity() + .HasMany(airplane => airplane.Flights); + } + } +} diff --git a/test/OpenApiTests/OpenApiDocumentTests.cs b/test/OpenApiTests/OpenApiDocumentTests.cs new file mode 100644 index 0000000000..1a9dab73a4 --- /dev/null +++ b/test/OpenApiTests/OpenApiDocumentTests.cs @@ -0,0 +1,59 @@ +using System; +using System.IO; +using System.Net.Http; +using System.Reflection; +using System.Threading.Tasks; +using FluentAssertions; +using TestBuildingBlocks; +using Xunit; + +namespace OpenApiTests +{ + public sealed class OpenApiDocumentTests : IntegrationTestContext, OpenApiDbContext> + { + public OpenApiDocumentTests() + { + UseController(); + UseController(); + } + + [Fact] + public async Task Retrieved_document_should_match_expected_document() + { + // Arrange + string embeddedResourceName = $"{nameof(OpenApiTests)}.openapi.json"; + string expectedDocument = await LoadEmbeddedResourceAsync(embeddedResourceName); + string requestUrl = $"swagger/{nameof(OpenApiTests)}/swagger.json"; + + // Act + string actualDocument = await GetAsync(requestUrl); + + // Assert + actualDocument.Should().BeJson(expectedDocument); + } + + private async Task GetAsync(string requestUrl) + { + var request = new HttpRequestMessage(HttpMethod.Get, requestUrl); + + using HttpClient client = Factory.CreateClient(); + HttpResponseMessage responseMessage = await client.SendAsync(request); + + return await responseMessage.Content.ReadAsStringAsync(); + } + + private static async Task LoadEmbeddedResourceAsync(string name) + { + var assembly = Assembly.GetExecutingAssembly(); + await using Stream stream = assembly.GetManifestResourceStream(name); + + if (stream == null) + { + throw new Exception($"Failed to load embedded resource '{name}'. Set Build Action to Embedded Resource in properties."); + } + + using var reader = new StreamReader(stream); + return await reader.ReadToEndAsync(); + } + } +} diff --git a/test/OpenApiTests/OpenApiStartup.cs b/test/OpenApiTests/OpenApiStartup.cs new file mode 100644 index 0000000000..926443f587 --- /dev/null +++ b/test/OpenApiTests/OpenApiStartup.cs @@ -0,0 +1,40 @@ +using JsonApiDotNetCore.Configuration; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.OpenApi.Models; +using OpenApi; +using TestBuildingBlocks; + +namespace OpenApiTests +{ + public sealed class OpenApiStartup : TestableStartup + where TDbContext : DbContext + { + public override void ConfigureServices(IServiceCollection services) + { + IMvcCoreBuilder mvcCoreBuilder = services.AddMvcCore(); + + services.AddJsonApi(SetJsonApiOptions, mvcBuilder: mvcCoreBuilder); + + services.AddOpenApi(mvcCoreBuilder, options => options.SwaggerDoc(nameof(OpenApiTests), new OpenApiInfo + { + Title = nameof(OpenApiTests), + Version = "1" + })); + } + + public override void Configure(IApplicationBuilder app, IWebHostEnvironment environment, ILoggerFactory loggerFactory) + { + app.UseRouting(); + + app.UseJsonApi(); + + app.UseSwagger(); + + app.UseEndpoints(endpoints => endpoints.MapControllers()); + } + } +} diff --git a/test/OpenApiTests/OpenApiTests.csproj b/test/OpenApiTests/OpenApiTests.csproj new file mode 100644 index 0000000000..2ef3b1aad0 --- /dev/null +++ b/test/OpenApiTests/OpenApiTests.csproj @@ -0,0 +1,27 @@ + + + $(NetCoreAppVersion) + + + + + PreserveNewest + + + + + + + + + + + + + + + + + + + diff --git a/test/OpenApiTests/openapi.json b/test/OpenApiTests/openapi.json new file mode 100644 index 0000000000..aebd87ce3b --- /dev/null +++ b/test/OpenApiTests/openapi.json @@ -0,0 +1,963 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "OpenApiTests", + "version": "1" + }, + "paths": { + "/airplanes": { + "get": { + "tags": [ + "Airplanes" + ], + "responses": { + "200": { + "description": "Success" + } + } + }, + "head": { + "tags": [ + "Airplanes" + ], + "responses": { + "200": { + "description": "Success" + } + } + }, + "post": { + "tags": [ + "Airplanes" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Airplane" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/Airplane" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/Airplane" + } + } + } + }, + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/airplanes/{id}": { + "get": { + "tags": [ + "Airplanes" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + }, + "head": { + "tags": [ + "Airplanes" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + }, + "patch": { + "tags": [ + "Airplanes" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Airplane" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/Airplane" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/Airplane" + } + } + } + }, + "responses": { + "200": { + "description": "Success" + } + } + }, + "delete": { + "tags": [ + "Airplanes" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/airplanes/{id}/{relationshipName}": { + "get": { + "tags": [ + "Airplanes" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "relationshipName", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + }, + "head": { + "tags": [ + "Airplanes" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "relationshipName", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/airplanes/{id}/relationships/{relationshipName}": { + "get": { + "tags": [ + "Airplanes" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "relationshipName", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + }, + "head": { + "tags": [ + "Airplanes" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "relationshipName", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + }, + "post": { + "tags": [ + "Airplanes" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "relationshipName", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "uniqueItems": true, + "type": "array", + "items": { + "$ref": "#/components/schemas/IIdentifiable" + } + } + }, + "text/json": { + "schema": { + "uniqueItems": true, + "type": "array", + "items": { + "$ref": "#/components/schemas/IIdentifiable" + } + } + }, + "application/*+json": { + "schema": { + "uniqueItems": true, + "type": "array", + "items": { + "$ref": "#/components/schemas/IIdentifiable" + } + } + } + } + }, + "responses": { + "200": { + "description": "Success" + } + } + }, + "patch": { + "tags": [ + "Airplanes" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "relationshipName", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": {} + }, + "text/json": { + "schema": {} + }, + "application/*+json": { + "schema": {} + } + } + }, + "responses": { + "200": { + "description": "Success" + } + } + }, + "delete": { + "tags": [ + "Airplanes" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "relationshipName", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "uniqueItems": true, + "type": "array", + "items": { + "$ref": "#/components/schemas/IIdentifiable" + } + } + }, + "text/json": { + "schema": { + "uniqueItems": true, + "type": "array", + "items": { + "$ref": "#/components/schemas/IIdentifiable" + } + } + }, + "application/*+json": { + "schema": { + "uniqueItems": true, + "type": "array", + "items": { + "$ref": "#/components/schemas/IIdentifiable" + } + } + } + } + }, + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/flights": { + "get": { + "tags": [ + "Flights" + ], + "responses": { + "200": { + "description": "Success" + } + } + }, + "head": { + "tags": [ + "Flights" + ], + "responses": { + "200": { + "description": "Success" + } + } + }, + "post": { + "tags": [ + "Flights" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Flight" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/Flight" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/Flight" + } + } + } + }, + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/flights/{id}": { + "get": { + "tags": [ + "Flights" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + }, + "head": { + "tags": [ + "Flights" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + }, + "patch": { + "tags": [ + "Flights" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Flight" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/Flight" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/Flight" + } + } + } + }, + "responses": { + "200": { + "description": "Success" + } + } + }, + "delete": { + "tags": [ + "Flights" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/flights/{id}/{relationshipName}": { + "get": { + "tags": [ + "Flights" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "relationshipName", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + }, + "head": { + "tags": [ + "Flights" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "relationshipName", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/flights/{id}/relationships/{relationshipName}": { + "get": { + "tags": [ + "Flights" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "relationshipName", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + }, + "head": { + "tags": [ + "Flights" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "relationshipName", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + }, + "post": { + "tags": [ + "Flights" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "relationshipName", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "uniqueItems": true, + "type": "array", + "items": { + "$ref": "#/components/schemas/IIdentifiable" + } + } + }, + "text/json": { + "schema": { + "uniqueItems": true, + "type": "array", + "items": { + "$ref": "#/components/schemas/IIdentifiable" + } + } + }, + "application/*+json": { + "schema": { + "uniqueItems": true, + "type": "array", + "items": { + "$ref": "#/components/schemas/IIdentifiable" + } + } + } + } + }, + "responses": { + "200": { + "description": "Success" + } + } + }, + "patch": { + "tags": [ + "Flights" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "relationshipName", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": {} + }, + "text/json": { + "schema": {} + }, + "application/*+json": { + "schema": {} + } + } + }, + "responses": { + "200": { + "description": "Success" + } + } + }, + "delete": { + "tags": [ + "Flights" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "relationshipName", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "uniqueItems": true, + "type": "array", + "items": { + "$ref": "#/components/schemas/IIdentifiable" + } + } + }, + "text/json": { + "schema": { + "uniqueItems": true, + "type": "array", + "items": { + "$ref": "#/components/schemas/IIdentifiable" + } + } + }, + "application/*+json": { + "schema": { + "uniqueItems": true, + "type": "array", + "items": { + "$ref": "#/components/schemas/IIdentifiable" + } + } + } + } + }, + "responses": { + "200": { + "description": "Success" + } + } + } + } + }, + "components": { + "schemas": { + "Airplane": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "stringId": { + "type": "string", + "nullable": true + }, + "localId": { + "type": "string", + "nullable": true + }, + "seatingCapacity": { + "type": "integer", + "format": "int32" + }, + "manufacturedAt": { + "type": "string", + "format": "date-time" + }, + "flights": { + "uniqueItems": true, + "type": "array", + "items": { + "$ref": "#/components/schemas/Flight" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "Flight": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "stringId": { + "type": "string", + "nullable": true + }, + "localId": { + "type": "string", + "nullable": true + }, + "destination": { + "type": "string", + "nullable": true + }, + "plannedDeparture": { + "type": "string", + "format": "date-time" + } + }, + "additionalProperties": false + }, + "IIdentifiable": { + "type": "object", + "properties": { + "stringId": { + "type": "string", + "nullable": true + }, + "localId": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + } + } + } +} From f4cd2a303a3332860c9550a6f2701168515dd6fe Mon Sep 17 00:00:00 2001 From: maurei Date: Mon, 6 Sep 2021 18:02:49 +0200 Subject: [PATCH 03/23] review feedback --- JsonApiDotNetCore.sln | 2 +- appveyor.yml | 4 ++-- .../JsonApiDotNetCore.OpenApi.csproj} | 2 +- .../OpenApiEndpointConvention.cs | 3 +-- .../ServiceCollectionExtensions.cs | 3 +-- src/JsonApiDotNetCore/Properties/AssemblyInfo.cs | 2 +- test/OpenApiTests/Airplane.cs | 2 +- test/OpenApiTests/AirplanesController.cs | 2 +- test/OpenApiTests/Flight.cs | 4 ++-- test/OpenApiTests/FlightsController.cs | 4 ++-- test/OpenApiTests/OpenApiStartup.cs | 2 +- test/OpenApiTests/OpenApiTests.csproj | 2 +- 12 files changed, 15 insertions(+), 17 deletions(-) rename src/{OpenApi/OpenApi.csproj => JsonApiDotNetCore.OpenApi/JsonApiDotNetCore.OpenApi.csproj} (95%) rename src/{OpenApi => JsonApiDotNetCore.OpenApi}/OpenApiEndpointConvention.cs (92%) rename src/{OpenApi => JsonApiDotNetCore.OpenApi}/ServiceCollectionExtensions.cs (93%) diff --git a/JsonApiDotNetCore.sln b/JsonApiDotNetCore.sln index 7747bf34a1..fcb0603b0e 100644 --- a/JsonApiDotNetCore.sln +++ b/JsonApiDotNetCore.sln @@ -44,7 +44,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MultiDbContextTests", "test EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestBuildingBlocks", "test\TestBuildingBlocks\TestBuildingBlocks.csproj", "{210FD61E-FF5D-4CEE-8E0D-C739ECCCBA21}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenApi", "src\OpenApi\OpenApi.csproj", "{71287D6F-6C3B-44B4-9FCA-E78FE3F02289}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JsonApiDotNetCore.OpenApi", "src\JsonApiDotNetCore.OpenApi\JsonApiDotNetCore.OpenApi.csproj", "{71287D6F-6C3B-44B4-9FCA-E78FE3F02289}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenApiTests", "test\OpenApiTests\OpenApiTests.csproj", "{B693DE14-BB28-496F-AB39-B4E674ABCA80}" EndProject diff --git a/appveyor.yml b/appveyor.yml index 3c61231177..deaf1e528a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -36,13 +36,13 @@ for: - image: Visual Studio 2019 services: - postgresql101 - # REF: https://github.com/docascode/docfx-seed/blob/master/appveyor.yml + # This ensures the base branch is loaded which is required for regitlint to run. clone_script: - # This ensures the base branch is loaded which is required for regitlint to run. - ps: | git clone --branch=$env:APPVEYOR_REPO_BRANCH git@github.com:$env:APPVEYOR_REPO_NAME.git $env:APPVEYOR_BUILD_FOLDER git fetch -q origin +refs/pull/$env:APPVEYOR_PULL_REQUEST_NUMBER/merge: git checkout -qf FETCH_HEAD + # REF: https://github.com/docascode/docfx-seed/blob/master/appveyor.yml before_build: - pwsh: | if (-Not $env:APPVEYOR_PULL_REQUEST_TITLE) { diff --git a/src/OpenApi/OpenApi.csproj b/src/JsonApiDotNetCore.OpenApi/JsonApiDotNetCore.OpenApi.csproj similarity index 95% rename from src/OpenApi/OpenApi.csproj rename to src/JsonApiDotNetCore.OpenApi/JsonApiDotNetCore.OpenApi.csproj index 6b27d5c5f7..a0dbd9568d 100644 --- a/src/OpenApi/OpenApi.csproj +++ b/src/JsonApiDotNetCore.OpenApi/JsonApiDotNetCore.OpenApi.csproj @@ -4,7 +4,7 @@ - + diff --git a/src/OpenApi/OpenApiEndpointConvention.cs b/src/JsonApiDotNetCore.OpenApi/OpenApiEndpointConvention.cs similarity index 92% rename from src/OpenApi/OpenApiEndpointConvention.cs rename to src/JsonApiDotNetCore.OpenApi/OpenApiEndpointConvention.cs index ffdcd60c34..a9b58bdd16 100644 --- a/src/OpenApi/OpenApiEndpointConvention.cs +++ b/src/JsonApiDotNetCore.OpenApi/OpenApiEndpointConvention.cs @@ -1,9 +1,8 @@ using System.Linq; -using JsonApiDotNetCore; using Microsoft.AspNetCore.Mvc.ApplicationModels; using Microsoft.AspNetCore.Mvc.Routing; -namespace OpenApi +namespace JsonApiDotNetCore.OpenApi { internal sealed class OpenApiEndpointConvention : IActionModelConvention { diff --git a/src/OpenApi/ServiceCollectionExtensions.cs b/src/JsonApiDotNetCore.OpenApi/ServiceCollectionExtensions.cs similarity index 93% rename from src/OpenApi/ServiceCollectionExtensions.cs rename to src/JsonApiDotNetCore.OpenApi/ServiceCollectionExtensions.cs index aba9485522..af76320c76 100644 --- a/src/OpenApi/ServiceCollectionExtensions.cs +++ b/src/JsonApiDotNetCore.OpenApi/ServiceCollectionExtensions.cs @@ -1,9 +1,8 @@ using System; -using JsonApiDotNetCore; using Microsoft.Extensions.DependencyInjection; using Swashbuckle.AspNetCore.SwaggerGen; -namespace OpenApi +namespace JsonApiDotNetCore.OpenApi { public static class ServiceCollectionExtensions { diff --git a/src/JsonApiDotNetCore/Properties/AssemblyInfo.cs b/src/JsonApiDotNetCore/Properties/AssemblyInfo.cs index 038bd92975..2cc2ee88bc 100644 --- a/src/JsonApiDotNetCore/Properties/AssemblyInfo.cs +++ b/src/JsonApiDotNetCore/Properties/AssemblyInfo.cs @@ -1,6 +1,6 @@ using System.Runtime.CompilerServices; -[assembly: InternalsVisibleTo("OpenApi")] +[assembly: InternalsVisibleTo("JsonApiDotNetCore.OpenApi")] [assembly: InternalsVisibleTo("Benchmarks")] [assembly: InternalsVisibleTo("JsonApiDotNetCoreTests")] [assembly: InternalsVisibleTo("UnitTests")] diff --git a/test/OpenApiTests/Airplane.cs b/test/OpenApiTests/Airplane.cs index 9c035d9c80..33a94b5013 100644 --- a/test/OpenApiTests/Airplane.cs +++ b/test/OpenApiTests/Airplane.cs @@ -7,7 +7,7 @@ namespace OpenApiTests { [UsedImplicitly(ImplicitUseTargetFlags.Members)] - public sealed class Airplane : Identifiable + public sealed class Airplane : Identifiable { [Attr] public int SeatingCapacity { get; set; } diff --git a/test/OpenApiTests/AirplanesController.cs b/test/OpenApiTests/AirplanesController.cs index 40c95d1975..b82c431142 100644 --- a/test/OpenApiTests/AirplanesController.cs +++ b/test/OpenApiTests/AirplanesController.cs @@ -5,7 +5,7 @@ namespace OpenApiTests { - public sealed class AirplanesController : JsonApiController + public sealed class AirplanesController : JsonApiController { public AirplanesController(IJsonApiOptions options, ILoggerFactory loggerFactory, IResourceService resourceService) : base(options, loggerFactory, resourceService) diff --git a/test/OpenApiTests/Flight.cs b/test/OpenApiTests/Flight.cs index 57dd44abe7..9ec0443b8e 100644 --- a/test/OpenApiTests/Flight.cs +++ b/test/OpenApiTests/Flight.cs @@ -6,12 +6,12 @@ namespace OpenApiTests { [UsedImplicitly(ImplicitUseTargetFlags.Members)] - public sealed class Flight : Identifiable + public sealed class Flight : Identifiable { [Attr] public string Destination { get; set; } [Attr] - public DateTimeOffset PlannedDeparture { get; set; } + public DateTimeOffset DepartsAt { get; set; } } } diff --git a/test/OpenApiTests/FlightsController.cs b/test/OpenApiTests/FlightsController.cs index aa24d72f32..3b226673a2 100644 --- a/test/OpenApiTests/FlightsController.cs +++ b/test/OpenApiTests/FlightsController.cs @@ -5,9 +5,9 @@ namespace OpenApiTests { - public sealed class FlightsController : JsonApiController + public sealed class FlightsController : JsonApiController { - public FlightsController(IJsonApiOptions options, ILoggerFactory loggerFactory, IResourceService resourceService) + public FlightsController(IJsonApiOptions options, ILoggerFactory loggerFactory, IResourceService resourceService) : base(options, loggerFactory, resourceService) { } diff --git a/test/OpenApiTests/OpenApiStartup.cs b/test/OpenApiTests/OpenApiStartup.cs index 926443f587..14885242ff 100644 --- a/test/OpenApiTests/OpenApiStartup.cs +++ b/test/OpenApiTests/OpenApiStartup.cs @@ -1,11 +1,11 @@ using JsonApiDotNetCore.Configuration; +using JsonApiDotNetCore.OpenApi; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.OpenApi.Models; -using OpenApi; using TestBuildingBlocks; namespace OpenApiTests diff --git a/test/OpenApiTests/OpenApiTests.csproj b/test/OpenApiTests/OpenApiTests.csproj index 2ef3b1aad0..d1e9dd5b53 100644 --- a/test/OpenApiTests/OpenApiTests.csproj +++ b/test/OpenApiTests/OpenApiTests.csproj @@ -11,7 +11,7 @@ - + From dd3f79448a7feb40b7bcbc8b1efe37a5a88707a0 Mon Sep 17 00:00:00 2001 From: maurei Date: Mon, 6 Sep 2021 18:27:19 +0200 Subject: [PATCH 04/23] CI clone_script fix --- appveyor.yml | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index deaf1e528a..27be79f479 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -20,6 +20,13 @@ branches: - unstable - /release\/.+/ +# This ensures the base branch is loaded which is required for regitlint to run. +clone_script: + - ps: | + git clone -q --branch=$env:APPVEYOR_REPO_BRANCH https://github.com/$env:APPVEYOR_REPO_NAME.git $env:APPVEYOR_BUILD_FOLDER + git fetch -q origin +refs/pull/$env:APPVEYOR_PULL_REQUEST_NUMBER/merge: + git checkout -qf FETCH_HEAD + pull_requests: do_not_increment_build_number: true @@ -36,12 +43,6 @@ for: - image: Visual Studio 2019 services: - postgresql101 - # This ensures the base branch is loaded which is required for regitlint to run. - clone_script: - - ps: | - git clone --branch=$env:APPVEYOR_REPO_BRANCH git@github.com:$env:APPVEYOR_REPO_NAME.git $env:APPVEYOR_BUILD_FOLDER - git fetch -q origin +refs/pull/$env:APPVEYOR_PULL_REQUEST_NUMBER/merge: - git checkout -qf FETCH_HEAD # REF: https://github.com/docascode/docfx-seed/blob/master/appveyor.yml before_build: - pwsh: | From efa98f598239ea4900afac52e5ba551ce47acc06 Mon Sep 17 00:00:00 2001 From: maurei Date: Mon, 6 Sep 2021 18:27:44 +0200 Subject: [PATCH 05/23] review feedback --- test/OpenApiTests/OpenApiTests.csproj | 1 - 1 file changed, 1 deletion(-) diff --git a/test/OpenApiTests/OpenApiTests.csproj b/test/OpenApiTests/OpenApiTests.csproj index d1e9dd5b53..f12e272bb7 100644 --- a/test/OpenApiTests/OpenApiTests.csproj +++ b/test/OpenApiTests/OpenApiTests.csproj @@ -10,7 +10,6 @@ - From 901d2d01912129867511d6c27154e34235b36b51 Mon Sep 17 00:00:00 2001 From: maurei Date: Mon, 6 Sep 2021 20:27:22 +0200 Subject: [PATCH 06/23] fix CI build --- Build.ps1 | 8 ++++++++ appveyor.yml | 7 ------- test/OpenApiTests/openapi.json | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Build.ps1 b/Build.ps1 index ee1dd68cfb..f27b460a5b 100644 --- a/Build.ps1 +++ b/Build.ps1 @@ -93,6 +93,14 @@ function CreateNuGetPackage { CheckLastExitCode } +function LoadBaseBranchIfNotMaster(){ + if ($env:APPVEYOR_REPO_BRANCH -ne "master") { + git fetch origin ${env:APPVEYOR_REPO_BRANCH}:${env:APPVEYOR_REPO_BRANCH} + } +} + +LoadBaseBranchIfNotMaster + dotnet tool restore CheckLastExitCode diff --git a/appveyor.yml b/appveyor.yml index 27be79f479..f7f78a94a5 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -20,13 +20,6 @@ branches: - unstable - /release\/.+/ -# This ensures the base branch is loaded which is required for regitlint to run. -clone_script: - - ps: | - git clone -q --branch=$env:APPVEYOR_REPO_BRANCH https://github.com/$env:APPVEYOR_REPO_NAME.git $env:APPVEYOR_BUILD_FOLDER - git fetch -q origin +refs/pull/$env:APPVEYOR_PULL_REQUEST_NUMBER/merge: - git checkout -qf FETCH_HEAD - pull_requests: do_not_increment_build_number: true diff --git a/test/OpenApiTests/openapi.json b/test/OpenApiTests/openapi.json index aebd87ce3b..ba15f39946 100644 --- a/test/OpenApiTests/openapi.json +++ b/test/OpenApiTests/openapi.json @@ -937,7 +937,7 @@ "type": "string", "nullable": true }, - "plannedDeparture": { + "departsAt": { "type": "string", "format": "date-time" } From 64671c07fda36467eed8213e612b7b261e420eeb Mon Sep 17 00:00:00 2001 From: Bart Koelman Date: Tue, 7 Sep 2021 09:38:09 +0200 Subject: [PATCH 07/23] Reformat project files (using VS, doesn't appear to work in Rider) --- .../JsonApiDotNetCore.OpenApi.csproj | 22 +++++----- test/OpenApiTests/OpenApiTests.csproj | 40 +++++++++---------- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiDotNetCore.OpenApi.csproj b/src/JsonApiDotNetCore.OpenApi/JsonApiDotNetCore.OpenApi.csproj index a0dbd9568d..1572e41c65 100644 --- a/src/JsonApiDotNetCore.OpenApi/JsonApiDotNetCore.OpenApi.csproj +++ b/src/JsonApiDotNetCore.OpenApi/JsonApiDotNetCore.OpenApi.csproj @@ -1,15 +1,15 @@ - - $(NetCoreAppVersion) - + + $(NetCoreAppVersion) + - - - - - + + + + + - - - + + + diff --git a/test/OpenApiTests/OpenApiTests.csproj b/test/OpenApiTests/OpenApiTests.csproj index f12e272bb7..5de2f1ac52 100644 --- a/test/OpenApiTests/OpenApiTests.csproj +++ b/test/OpenApiTests/OpenApiTests.csproj @@ -1,26 +1,26 @@ - - $(NetCoreAppVersion) - + + $(NetCoreAppVersion) + - - - PreserveNewest - - + + + PreserveNewest + + - - - - + + + + - - - - - + + + + + - - - + + + From e80478d622a6e2e8ac6b1382824678eb3d4adb8d Mon Sep 17 00:00:00 2001 From: Bart Koelman Date: Tue, 7 Sep 2021 09:41:28 +0200 Subject: [PATCH 08/23] Fixed schema error in VS --- test/OpenApiTests/OpenApiTests.csproj | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/OpenApiTests/OpenApiTests.csproj b/test/OpenApiTests/OpenApiTests.csproj index 5de2f1ac52..5818ea4ac3 100644 --- a/test/OpenApiTests/OpenApiTests.csproj +++ b/test/OpenApiTests/OpenApiTests.csproj @@ -23,4 +23,11 @@ + + + + + + + From 204bcf9cf571d04fce790e88f48da262c17e6e9d Mon Sep 17 00:00:00 2001 From: maurei Date: Tue, 7 Sep 2021 09:45:06 +0200 Subject: [PATCH 09/23] reorder csproj --- .../JsonApiDotNetCore.OpenApi.csproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiDotNetCore.OpenApi.csproj b/src/JsonApiDotNetCore.OpenApi/JsonApiDotNetCore.OpenApi.csproj index 1572e41c65..cb9edfd066 100644 --- a/src/JsonApiDotNetCore.OpenApi/JsonApiDotNetCore.OpenApi.csproj +++ b/src/JsonApiDotNetCore.OpenApi/JsonApiDotNetCore.OpenApi.csproj @@ -4,12 +4,12 @@ - - - + - + + + From a61d5719117c8c9a9bc84f783d8667ace51245cb Mon Sep 17 00:00:00 2001 From: maurei Date: Tue, 7 Sep 2021 11:19:05 +0200 Subject: [PATCH 10/23] review feedback --- Build.ps1 | 9 ++-- .../JsonApiDotNetCoreExample.csproj | 1 + .../JsonApiDotNetCoreExample/Program.cs | 1 - .../{Startups => }/Startup.cs | 2 +- .../JsonApiDotNetCore.OpenApi.csproj | 1 + .../ServiceCollectionExtensions.cs | 2 +- test/OpenApiTests/AirplanesController.cs | 2 +- test/OpenApiTests/OpenApiDocumentTests.cs | 4 +- test/OpenApiTests/OpenApiStartup.cs | 9 ++-- test/OpenApiTests/OpenApiTests.csproj | 48 ++++++++----------- 10 files changed, 37 insertions(+), 42 deletions(-) rename src/Examples/JsonApiDotNetCoreExample/{Startups => }/Startup.cs (98%) diff --git a/Build.ps1 b/Build.ps1 index f27b460a5b..e099f62655 100644 --- a/Build.ps1 +++ b/Build.ps1 @@ -93,13 +93,14 @@ function CreateNuGetPackage { CheckLastExitCode } -function LoadBaseBranchIfNotMaster(){ - if ($env:APPVEYOR_REPO_BRANCH -ne "master") { - git fetch origin ${env:APPVEYOR_REPO_BRANCH}:${env:APPVEYOR_REPO_BRANCH} +# In a PR the base branch needs to be fetched in order for regitlint to work. +function FetchBaseBranchIfNotMaster(){ + if ($env:APPVEYOR_PULL_REQUEST_NUMBER -And $env:APPVEYOR_REPO_BRANCH -ne "master"){ + git fetch -q origin ${env:APPVEYOR_REPO_BRANCH}:${env:APPVEYOR_REPO_BRANCH} } } -LoadBaseBranchIfNotMaster +FetchBaseBranchIfNotMaster dotnet tool restore CheckLastExitCode diff --git a/src/Examples/JsonApiDotNetCoreExample/JsonApiDotNetCoreExample.csproj b/src/Examples/JsonApiDotNetCoreExample/JsonApiDotNetCoreExample.csproj index 95c1faf884..5bd119dcb9 100644 --- a/src/Examples/JsonApiDotNetCoreExample/JsonApiDotNetCoreExample.csproj +++ b/src/Examples/JsonApiDotNetCoreExample/JsonApiDotNetCoreExample.csproj @@ -4,6 +4,7 @@ + diff --git a/src/Examples/JsonApiDotNetCoreExample/Program.cs b/src/Examples/JsonApiDotNetCoreExample/Program.cs index 4c97d8a7f4..e185c3b4c2 100644 --- a/src/Examples/JsonApiDotNetCoreExample/Program.cs +++ b/src/Examples/JsonApiDotNetCoreExample/Program.cs @@ -1,4 +1,3 @@ -using JsonApiDotNetCoreExample.Startups; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Hosting; diff --git a/src/Examples/JsonApiDotNetCoreExample/Startups/Startup.cs b/src/Examples/JsonApiDotNetCoreExample/Startup.cs similarity index 98% rename from src/Examples/JsonApiDotNetCoreExample/Startups/Startup.cs rename to src/Examples/JsonApiDotNetCoreExample/Startup.cs index d7c6a19e42..85740b83e1 100644 --- a/src/Examples/JsonApiDotNetCoreExample/Startups/Startup.cs +++ b/src/Examples/JsonApiDotNetCoreExample/Startup.cs @@ -12,7 +12,7 @@ using Newtonsoft.Json; using Newtonsoft.Json.Converters; -namespace JsonApiDotNetCoreExample.Startups +namespace JsonApiDotNetCoreExample { public sealed class Startup { diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiDotNetCore.OpenApi.csproj b/src/JsonApiDotNetCore.OpenApi/JsonApiDotNetCore.OpenApi.csproj index cb9edfd066..df3c042003 100644 --- a/src/JsonApiDotNetCore.OpenApi/JsonApiDotNetCore.OpenApi.csproj +++ b/src/JsonApiDotNetCore.OpenApi/JsonApiDotNetCore.OpenApi.csproj @@ -11,5 +11,6 @@ + diff --git a/src/JsonApiDotNetCore.OpenApi/ServiceCollectionExtensions.cs b/src/JsonApiDotNetCore.OpenApi/ServiceCollectionExtensions.cs index af76320c76..f9f29e87eb 100644 --- a/src/JsonApiDotNetCore.OpenApi/ServiceCollectionExtensions.cs +++ b/src/JsonApiDotNetCore.OpenApi/ServiceCollectionExtensions.cs @@ -6,7 +6,7 @@ namespace JsonApiDotNetCore.OpenApi { public static class ServiceCollectionExtensions { - public static void AddOpenApi(this IServiceCollection services, IMvcCoreBuilder builder, Action setupSwaggerGenAction) + public static void AddOpenApi(this IServiceCollection services, IMvcCoreBuilder builder, Action setupSwaggerGenAction = null) { ArgumentGuard.NotNull(services, nameof(services)); ArgumentGuard.NotNull(builder, nameof(builder)); diff --git a/test/OpenApiTests/AirplanesController.cs b/test/OpenApiTests/AirplanesController.cs index b82c431142..002f4b7b1e 100644 --- a/test/OpenApiTests/AirplanesController.cs +++ b/test/OpenApiTests/AirplanesController.cs @@ -7,7 +7,7 @@ namespace OpenApiTests { public sealed class AirplanesController : JsonApiController { - public AirplanesController(IJsonApiOptions options, ILoggerFactory loggerFactory, IResourceService resourceService) + public AirplanesController(IJsonApiOptions options, ILoggerFactory loggerFactory, IResourceService resourceService) : base(options, loggerFactory, resourceService) { } diff --git a/test/OpenApiTests/OpenApiDocumentTests.cs b/test/OpenApiTests/OpenApiDocumentTests.cs index 1a9dab73a4..baa758452e 100644 --- a/test/OpenApiTests/OpenApiDocumentTests.cs +++ b/test/OpenApiTests/OpenApiDocumentTests.cs @@ -18,12 +18,12 @@ public OpenApiDocumentTests() } [Fact] - public async Task Retrieved_document_should_match_expected_document() + public async Task Retrieved_document_matches_expected_document() { // Arrange string embeddedResourceName = $"{nameof(OpenApiTests)}.openapi.json"; string expectedDocument = await LoadEmbeddedResourceAsync(embeddedResourceName); - string requestUrl = $"swagger/{nameof(OpenApiTests)}/swagger.json"; + string requestUrl = $"swagger/{OpenApiStartup.OpenApiDocumentName}/swagger.json"; // Act string actualDocument = await GetAsync(requestUrl); diff --git a/test/OpenApiTests/OpenApiStartup.cs b/test/OpenApiTests/OpenApiStartup.cs index 14885242ff..4800813a52 100644 --- a/test/OpenApiTests/OpenApiStartup.cs +++ b/test/OpenApiTests/OpenApiStartup.cs @@ -13,15 +13,17 @@ namespace OpenApiTests public sealed class OpenApiStartup : TestableStartup where TDbContext : DbContext { + internal const string OpenApiDocumentName = nameof(OpenApiTests); + public override void ConfigureServices(IServiceCollection services) { IMvcCoreBuilder mvcCoreBuilder = services.AddMvcCore(); services.AddJsonApi(SetJsonApiOptions, mvcBuilder: mvcCoreBuilder); - services.AddOpenApi(mvcCoreBuilder, options => options.SwaggerDoc(nameof(OpenApiTests), new OpenApiInfo + services.AddOpenApi(mvcCoreBuilder, options => options.SwaggerDoc(OpenApiDocumentName, new OpenApiInfo { - Title = nameof(OpenApiTests), + Title = OpenApiDocumentName, Version = "1" })); } @@ -29,11 +31,8 @@ public override void ConfigureServices(IServiceCollection services) public override void Configure(IApplicationBuilder app, IWebHostEnvironment environment, ILoggerFactory loggerFactory) { app.UseRouting(); - app.UseJsonApi(); - app.UseSwagger(); - app.UseEndpoints(endpoints => endpoints.MapControllers()); } } diff --git a/test/OpenApiTests/OpenApiTests.csproj b/test/OpenApiTests/OpenApiTests.csproj index 5818ea4ac3..00a8040eb5 100644 --- a/test/OpenApiTests/OpenApiTests.csproj +++ b/test/OpenApiTests/OpenApiTests.csproj @@ -1,33 +1,27 @@ - - $(NetCoreAppVersion) - + + $(NetCoreAppVersion) + - - - PreserveNewest - - + + + + - - - - + + + + + - - - - - + + + - - - - - - - - - - + + + + + + From c0d4918c8b9c3c836b0f33e6d4e7fca29bf9e18e Mon Sep 17 00:00:00 2001 From: maurei Date: Tue, 7 Sep 2021 12:04:29 +0200 Subject: [PATCH 11/23] add SwaggerUI to example project --- .../JsonApiDotNetCoreExample.csproj | 1 + src/Examples/JsonApiDotNetCoreExample/Startup.cs | 10 +++++++++- .../JsonApiDotNetCore.OpenApi.csproj | 1 - 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/Examples/JsonApiDotNetCoreExample/JsonApiDotNetCoreExample.csproj b/src/Examples/JsonApiDotNetCoreExample/JsonApiDotNetCoreExample.csproj index 5bd119dcb9..e3ef994658 100644 --- a/src/Examples/JsonApiDotNetCoreExample/JsonApiDotNetCoreExample.csproj +++ b/src/Examples/JsonApiDotNetCoreExample/JsonApiDotNetCoreExample.csproj @@ -11,5 +11,6 @@ + diff --git a/src/Examples/JsonApiDotNetCoreExample/Startup.cs b/src/Examples/JsonApiDotNetCoreExample/Startup.cs index 85740b83e1..4128a8dc53 100644 --- a/src/Examples/JsonApiDotNetCoreExample/Startup.cs +++ b/src/Examples/JsonApiDotNetCoreExample/Startup.cs @@ -1,6 +1,7 @@ using System; using JsonApiDotNetCore.Configuration; using JsonApiDotNetCore.Diagnostics; +using JsonApiDotNetCore.OpenApi; using JsonApiDotNetCoreExample.Data; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Builder; @@ -44,6 +45,10 @@ public void ConfigureServices(IServiceCollection services) #endif }); + IMvcCoreBuilder mvcCoreBuilder = services.AddMvcCore(); + + services.AddOpenApi(mvcCoreBuilder); + using (CodeTimingSessionManager.Current.Measure("Configure JSON:API (startup)")) { services.AddJsonApi(options => @@ -57,7 +62,7 @@ public void ConfigureServices(IServiceCollection services) #if DEBUG options.IncludeExceptionStackTraceInErrors = true; #endif - }, discovery => discovery.AddCurrentAssembly()); + }, discovery => discovery.AddCurrentAssembly(), mvcBuilder: mvcCoreBuilder); } } } @@ -77,6 +82,9 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment environment, app.UseRouting(); + app.UseSwagger(); + app.UseSwaggerUI(); + using (CodeTimingSessionManager.Current.Measure("Initialize JSON:API (startup)")) { app.UseJsonApi(); diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiDotNetCore.OpenApi.csproj b/src/JsonApiDotNetCore.OpenApi/JsonApiDotNetCore.OpenApi.csproj index df3c042003..cb9edfd066 100644 --- a/src/JsonApiDotNetCore.OpenApi/JsonApiDotNetCore.OpenApi.csproj +++ b/src/JsonApiDotNetCore.OpenApi/JsonApiDotNetCore.OpenApi.csproj @@ -11,6 +11,5 @@ - From fa448f5545e4953e81dfa971489b7f75de47917a Mon Sep 17 00:00:00 2001 From: maurei Date: Tue, 7 Sep 2021 12:15:13 +0200 Subject: [PATCH 12/23] rm redundant bit from dbcontext --- test/OpenApiTests/OpenApiDbContext.cs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/test/OpenApiTests/OpenApiDbContext.cs b/test/OpenApiTests/OpenApiDbContext.cs index e44e74505b..46aeee8804 100644 --- a/test/OpenApiTests/OpenApiDbContext.cs +++ b/test/OpenApiTests/OpenApiDbContext.cs @@ -16,11 +16,5 @@ public OpenApiDbContext(DbContextOptions options) : base(options) { } - - protected override void OnModelCreating(ModelBuilder builder) - { - builder.Entity() - .HasMany(airplane => airplane.Flights); - } } } From 3aad46694616dd782a894ba5b8bc5cb62a3edb24 Mon Sep 17 00:00:00 2001 From: maurei Date: Tue, 7 Sep 2021 12:32:53 +0200 Subject: [PATCH 13/23] add documentation --- docs/getting-started/install.md | 2 +- docs/usage/openapi.md | 72 +++++++++++++++++++++++++++++++++ docs/usage/toc.md | 2 + 3 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 docs/usage/openapi.md diff --git a/docs/getting-started/install.md b/docs/getting-started/install.md index 11a5e53471..64cc1edac9 100644 --- a/docs/getting-started/install.md +++ b/docs/getting-started/install.md @@ -19,6 +19,6 @@ Install-Package JsonApiDotnetCore ```xml - + ``` diff --git a/docs/usage/openapi.md b/docs/usage/openapi.md new file mode 100644 index 0000000000..40fed9b50c --- /dev/null +++ b/docs/usage/openapi.md @@ -0,0 +1,72 @@ +# OpenAPI + +You can describe your API with an OpenAPI specification using the [Swashbuckle](https://github.com/domaindrivendev/Swashbuckle.AspNetCore) integration for JsonApiDotNetCore. + +## Installation + +Install the `JsonApiDotnetCore.OpenApi` NuGet package. + +### CLI + +``` +dotnet add package JsonApiDotnetCore.OpenApi +``` + +### Visual Studio + +```powershell +Install-Package JsonApiDotnetCore.OpenApi +``` + +### *.csproj + +```xml + + + + +``` + +## Usage + +Add the integration in your `Startup` class. + +```c# +public class Startup +{ + public void ConfigureServices(IServiceCollection services) + { + IMvcCoreBuilder builder = services.AddMvcCore(); + services.AddJsonApi(mvcBuilder: builder); + + // Adds the Swashbuckle integration + services.AddOpenApi(builder); + } + + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + app.UseRouting(); + app.UseJsonApi(); + + // Adds the Swashbuckle middleware + app.UseSwagger(); + + app.UseEndpoints(endpoints => endpoints.MapControllers()); + } +} +``` + +By default, the OpenAPI specification will be available at `http://localhost:/swagger/v1/swagger.json`. + +Swashbuckle also ships with [SwaggerUI](https://swagger.io/tools/swagger-ui/), tooling for a generated documentation page. This can be enabled by adding the following to your `Startup` class. + +```c# +// Startup.cs +public void Configure(IApplicationBuilder app, IWebHostEnvironment env) +{ + app.UseSwaggerUI(); +} +``` + +By default, SwaggerUI will be available at `http://localhost:/swagger`. + diff --git a/docs/usage/toc.md b/docs/usage/toc.md index a8b5473007..f6fa0a0f88 100644 --- a/docs/usage/toc.md +++ b/docs/usage/toc.md @@ -30,3 +30,5 @@ ## [Resource Repositories](extensibility/repositories.md) ## [Middleware](extensibility/middleware.md) ## [Query Strings](extensibility/query-strings.md) + +# [OpenAPI](openapi.md) From bfab00fb300a4e8ca4e1e3acc68909febdd76714 Mon Sep 17 00:00:00 2001 From: maurei Date: Tue, 7 Sep 2021 12:35:17 +0200 Subject: [PATCH 14/23] typo --- docs/usage/openapi.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/usage/openapi.md b/docs/usage/openapi.md index 40fed9b50c..76bc78e219 100644 --- a/docs/usage/openapi.md +++ b/docs/usage/openapi.md @@ -39,7 +39,7 @@ public class Startup IMvcCoreBuilder builder = services.AddMvcCore(); services.AddJsonApi(mvcBuilder: builder); - // Adds the Swashbuckle integration + // Adds the Swashbuckle integration. services.AddOpenApi(builder); } @@ -48,7 +48,7 @@ public class Startup app.UseRouting(); app.UseJsonApi(); - // Adds the Swashbuckle middleware + // Adds the Swashbuckle middleware. app.UseSwagger(); app.UseEndpoints(endpoints => endpoints.MapControllers()); From 8ab5b7cfd88e98b2627a4e0ce4fac2c49b4bfc27 Mon Sep 17 00:00:00 2001 From: maurei Date: Tue, 7 Sep 2021 12:36:15 +0200 Subject: [PATCH 15/23] remove redundant formatter instructions --- test/OpenApiTests/OpenApiDbContext.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/OpenApiTests/OpenApiDbContext.cs b/test/OpenApiTests/OpenApiDbContext.cs index 46aeee8804..77e99aaddc 100644 --- a/test/OpenApiTests/OpenApiDbContext.cs +++ b/test/OpenApiTests/OpenApiDbContext.cs @@ -1,9 +1,6 @@ using JetBrains.Annotations; using Microsoft.EntityFrameworkCore; -// @formatter:wrap_chained_method_calls chop_always -// @formatter:keep_existing_linebreaks true - namespace OpenApiTests { [UsedImplicitly(ImplicitUseTargetFlags.Members)] From a46fc4dc04efe79c661b97e7a36f60bd013df93c Mon Sep 17 00:00:00 2001 From: maurei Date: Tue, 7 Sep 2021 15:16:50 +0200 Subject: [PATCH 16/23] review feedback --- docs/usage/openapi.md | 6 +++--- .../JsonApiDotNetCoreExample.csproj | 2 +- src/Examples/JsonApiDotNetCoreExample/Startup.cs | 6 +++--- test/OpenApiTests/OpenApiDocumentTests.cs | 4 ++-- test/OpenApiTests/OpenApiStartup.cs | 13 +++---------- test/OpenApiTests/OpenApiTests.csproj | 4 ++-- test/OpenApiTests/{openapi.json => swagger.json} | 0 7 files changed, 14 insertions(+), 21 deletions(-) rename test/OpenApiTests/{openapi.json => swagger.json} (100%) diff --git a/docs/usage/openapi.md b/docs/usage/openapi.md index 76bc78e219..092a80415a 100644 --- a/docs/usage/openapi.md +++ b/docs/usage/openapi.md @@ -36,11 +36,11 @@ public class Startup { public void ConfigureServices(IServiceCollection services) { - IMvcCoreBuilder builder = services.AddMvcCore(); - services.AddJsonApi(mvcBuilder: builder); + IMvcCoreBuilder mvcBuilder = services.AddMvcCore(); + services.AddJsonApi(mvcBuilder: mvcBuilder); // Adds the Swashbuckle integration. - services.AddOpenApi(builder); + services.AddOpenApi(mvcBuilder); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) diff --git a/src/Examples/JsonApiDotNetCoreExample/JsonApiDotNetCoreExample.csproj b/src/Examples/JsonApiDotNetCoreExample/JsonApiDotNetCoreExample.csproj index e3ef994658..8dba30b456 100644 --- a/src/Examples/JsonApiDotNetCoreExample/JsonApiDotNetCoreExample.csproj +++ b/src/Examples/JsonApiDotNetCoreExample/JsonApiDotNetCoreExample.csproj @@ -4,8 +4,8 @@ - + diff --git a/src/Examples/JsonApiDotNetCoreExample/Startup.cs b/src/Examples/JsonApiDotNetCoreExample/Startup.cs index 4128a8dc53..50094f7e6d 100644 --- a/src/Examples/JsonApiDotNetCoreExample/Startup.cs +++ b/src/Examples/JsonApiDotNetCoreExample/Startup.cs @@ -45,9 +45,9 @@ public void ConfigureServices(IServiceCollection services) #endif }); - IMvcCoreBuilder mvcCoreBuilder = services.AddMvcCore(); + IMvcCoreBuilder mvcBuilder = services.AddMvcCore(); - services.AddOpenApi(mvcCoreBuilder); + services.AddOpenApi(mvcBuilder); using (CodeTimingSessionManager.Current.Measure("Configure JSON:API (startup)")) { @@ -62,7 +62,7 @@ public void ConfigureServices(IServiceCollection services) #if DEBUG options.IncludeExceptionStackTraceInErrors = true; #endif - }, discovery => discovery.AddCurrentAssembly(), mvcBuilder: mvcCoreBuilder); + }, discovery => discovery.AddCurrentAssembly(), mvcBuilder: mvcBuilder); } } } diff --git a/test/OpenApiTests/OpenApiDocumentTests.cs b/test/OpenApiTests/OpenApiDocumentTests.cs index baa758452e..4203eb0489 100644 --- a/test/OpenApiTests/OpenApiDocumentTests.cs +++ b/test/OpenApiTests/OpenApiDocumentTests.cs @@ -21,9 +21,9 @@ public OpenApiDocumentTests() public async Task Retrieved_document_matches_expected_document() { // Arrange - string embeddedResourceName = $"{nameof(OpenApiTests)}.openapi.json"; + string embeddedResourceName = $"{nameof(OpenApiTests)}.swagger.json"; string expectedDocument = await LoadEmbeddedResourceAsync(embeddedResourceName); - string requestUrl = $"swagger/{OpenApiStartup.OpenApiDocumentName}/swagger.json"; + string requestUrl = "swagger/v1/swagger.json"; // Act string actualDocument = await GetAsync(requestUrl); diff --git a/test/OpenApiTests/OpenApiStartup.cs b/test/OpenApiTests/OpenApiStartup.cs index 4800813a52..88f956a0f6 100644 --- a/test/OpenApiTests/OpenApiStartup.cs +++ b/test/OpenApiTests/OpenApiStartup.cs @@ -5,7 +5,6 @@ using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using Microsoft.OpenApi.Models; using TestBuildingBlocks; namespace OpenApiTests @@ -13,19 +12,13 @@ namespace OpenApiTests public sealed class OpenApiStartup : TestableStartup where TDbContext : DbContext { - internal const string OpenApiDocumentName = nameof(OpenApiTests); - public override void ConfigureServices(IServiceCollection services) { - IMvcCoreBuilder mvcCoreBuilder = services.AddMvcCore(); + IMvcCoreBuilder mvcBuilder = services.AddMvcCore(); - services.AddJsonApi(SetJsonApiOptions, mvcBuilder: mvcCoreBuilder); + services.AddJsonApi(SetJsonApiOptions, mvcBuilder: mvcBuilder); - services.AddOpenApi(mvcCoreBuilder, options => options.SwaggerDoc(OpenApiDocumentName, new OpenApiInfo - { - Title = OpenApiDocumentName, - Version = "1" - })); + services.AddOpenApi(mvcBuilder); } public override void Configure(IApplicationBuilder app, IWebHostEnvironment environment, ILoggerFactory loggerFactory) diff --git a/test/OpenApiTests/OpenApiTests.csproj b/test/OpenApiTests/OpenApiTests.csproj index 00a8040eb5..e9391331ac 100644 --- a/test/OpenApiTests/OpenApiTests.csproj +++ b/test/OpenApiTests/OpenApiTests.csproj @@ -15,13 +15,13 @@ - + - + diff --git a/test/OpenApiTests/openapi.json b/test/OpenApiTests/swagger.json similarity index 100% rename from test/OpenApiTests/openapi.json rename to test/OpenApiTests/swagger.json From 5fc0afa08c77619be32ac392f1f9a20d744803ef Mon Sep 17 00:00:00 2001 From: maurei Date: Tue, 7 Sep 2021 15:52:21 +0200 Subject: [PATCH 17/23] review feedback --- docs/getting-started/install.md | 2 +- docs/usage/extensibility/middleware.md | 2 +- docs/usage/openapi.md | 10 +++++----- docs/usage/toc.md | 2 +- src/Examples/JsonApiDotNetCoreExample/Startup.cs | 10 +++++----- .../ServiceCollectionExtensions.cs | 8 ++++---- 6 files changed, 17 insertions(+), 17 deletions(-) diff --git a/docs/getting-started/install.md b/docs/getting-started/install.md index 64cc1edac9..11a5e53471 100644 --- a/docs/getting-started/install.md +++ b/docs/getting-started/install.md @@ -19,6 +19,6 @@ Install-Package JsonApiDotnetCore ```xml - + ``` diff --git a/docs/usage/extensibility/middleware.md b/docs/usage/extensibility/middleware.md index 9be350250a..c05efa2e41 100644 --- a/docs/usage/extensibility/middleware.md +++ b/docs/usage/extensibility/middleware.md @@ -27,7 +27,7 @@ public class Startup { services.AddSingleton(); - IMvcCoreBuilder builder = services.AddMvcCore(); + IMvcCoreBuilder mvcBuilder = services.AddMvcCore(); services.AddJsonApi(mvcBuilder: builder); // Ensure this call is placed after the AddJsonApi call. diff --git a/docs/usage/openapi.md b/docs/usage/openapi.md index 092a80415a..79156c5de7 100644 --- a/docs/usage/openapi.md +++ b/docs/usage/openapi.md @@ -4,18 +4,18 @@ You can describe your API with an OpenAPI specification using the [Swashbuckle]( ## Installation -Install the `JsonApiDotnetCore.OpenApi` NuGet package. +Install the `JsonApiDotNetCore.OpenApi` NuGet package. ### CLI ``` -dotnet add package JsonApiDotnetCore.OpenApi +dotnet add package JsonApiDotNetCore.OpenApi ``` ### Visual Studio ```powershell -Install-Package JsonApiDotnetCore.OpenApi +Install-Package JsonApiDotNetCore.OpenApi ``` ### *.csproj @@ -23,7 +23,7 @@ Install-Package JsonApiDotnetCore.OpenApi ```xml - + ``` @@ -58,7 +58,7 @@ public class Startup By default, the OpenAPI specification will be available at `http://localhost:/swagger/v1/swagger.json`. -Swashbuckle also ships with [SwaggerUI](https://swagger.io/tools/swagger-ui/), tooling for a generated documentation page. This can be enabled by adding the following to your `Startup` class. +Swashbuckle also ships with [SwaggerUI](https://swagger.io/tools/swagger-ui/), tooling for a generated documentation page. This can be enabled by installing the `Swashbuckle.AspNetCore.SwaggerUI` NuGet package and adding the following to your `Startup` class. ```c# // Startup.cs diff --git a/docs/usage/toc.md b/docs/usage/toc.md index f6fa0a0f88..76ea777aac 100644 --- a/docs/usage/toc.md +++ b/docs/usage/toc.md @@ -21,6 +21,7 @@ # [Errors](errors.md) # [Metadata](meta.md) # [Caching](caching.md) +# [OpenAPI](openapi.md) # Extensibility ## [Layer Overview](extensibility/layer-overview.md) @@ -31,4 +32,3 @@ ## [Middleware](extensibility/middleware.md) ## [Query Strings](extensibility/query-strings.md) -# [OpenAPI](openapi.md) diff --git a/src/Examples/JsonApiDotNetCoreExample/Startup.cs b/src/Examples/JsonApiDotNetCoreExample/Startup.cs index 50094f7e6d..570def00e4 100644 --- a/src/Examples/JsonApiDotNetCoreExample/Startup.cs +++ b/src/Examples/JsonApiDotNetCoreExample/Startup.cs @@ -47,8 +47,6 @@ public void ConfigureServices(IServiceCollection services) IMvcCoreBuilder mvcBuilder = services.AddMvcCore(); - services.AddOpenApi(mvcBuilder); - using (CodeTimingSessionManager.Current.Measure("Configure JSON:API (startup)")) { services.AddJsonApi(options => @@ -64,6 +62,8 @@ public void ConfigureServices(IServiceCollection services) #endif }, discovery => discovery.AddCurrentAssembly(), mvcBuilder: mvcBuilder); } + + services.AddOpenApi(mvcBuilder); } } @@ -82,14 +82,14 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment environment, app.UseRouting(); - app.UseSwagger(); - app.UseSwaggerUI(); - using (CodeTimingSessionManager.Current.Measure("Initialize JSON:API (startup)")) { app.UseJsonApi(); } + app.UseSwagger(); + app.UseSwaggerUI(); + app.UseEndpoints(endpoints => endpoints.MapControllers()); } diff --git a/src/JsonApiDotNetCore.OpenApi/ServiceCollectionExtensions.cs b/src/JsonApiDotNetCore.OpenApi/ServiceCollectionExtensions.cs index f9f29e87eb..ae87769e65 100644 --- a/src/JsonApiDotNetCore.OpenApi/ServiceCollectionExtensions.cs +++ b/src/JsonApiDotNetCore.OpenApi/ServiceCollectionExtensions.cs @@ -6,14 +6,14 @@ namespace JsonApiDotNetCore.OpenApi { public static class ServiceCollectionExtensions { - public static void AddOpenApi(this IServiceCollection services, IMvcCoreBuilder builder, Action setupSwaggerGenAction = null) + public static void AddOpenApi(this IServiceCollection services, IMvcCoreBuilder mvcBuilder, Action setupSwaggerGenAction = null) { ArgumentGuard.NotNull(services, nameof(services)); - ArgumentGuard.NotNull(builder, nameof(builder)); + ArgumentGuard.NotNull(mvcBuilder, nameof(mvcBuilder)); - builder.AddApiExplorer(); + mvcBuilder.AddApiExplorer(); - builder.AddMvcOptions(options => options.Conventions.Add(new OpenApiEndpointConvention())); + mvcBuilder.AddMvcOptions(options => options.Conventions.Add(new OpenApiEndpointConvention())); services.AddSwaggerGen(setupSwaggerGenAction); } From 71be36e1346dec68e384323b4401cb50977487f6 Mon Sep 17 00:00:00 2001 From: maurei Date: Tue, 7 Sep 2021 16:03:08 +0200 Subject: [PATCH 18/23] bump version --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index 5541886347..51081c9523 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -4,7 +4,7 @@ 5.0.* 5.0.* 5.0.* - 6.1.* + 6.2.* $(MSBuildThisFileDirectory)CodingGuidelines.ruleset From e715d2bcd71db185d8286b98c17260c648c59e0b Mon Sep 17 00:00:00 2001 From: maurei Date: Tue, 7 Sep 2021 16:03:45 +0200 Subject: [PATCH 19/23] updated swagger.json to pass test --- test/OpenApiTests/OpenApiDocumentTests.cs | 2 +- test/OpenApiTests/swagger.json | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/test/OpenApiTests/OpenApiDocumentTests.cs b/test/OpenApiTests/OpenApiDocumentTests.cs index 4203eb0489..898987712b 100644 --- a/test/OpenApiTests/OpenApiDocumentTests.cs +++ b/test/OpenApiTests/OpenApiDocumentTests.cs @@ -23,7 +23,7 @@ public async Task Retrieved_document_matches_expected_document() // Arrange string embeddedResourceName = $"{nameof(OpenApiTests)}.swagger.json"; string expectedDocument = await LoadEmbeddedResourceAsync(embeddedResourceName); - string requestUrl = "swagger/v1/swagger.json"; + const string requestUrl = "swagger/v1/swagger.json"; // Act string actualDocument = await GetAsync(requestUrl); diff --git a/test/OpenApiTests/swagger.json b/test/OpenApiTests/swagger.json index ba15f39946..87aa21d5bd 100644 --- a/test/OpenApiTests/swagger.json +++ b/test/OpenApiTests/swagger.json @@ -2,7 +2,7 @@ "openapi": "3.0.1", "info": { "title": "OpenApiTests", - "version": "1" + "version": "1.0" }, "paths": { "/airplanes": { @@ -366,13 +366,13 @@ "requestBody": { "content": { "application/json": { - "schema": {} + "schema": { } }, "text/json": { - "schema": {} + "schema": { } }, "application/*+json": { - "schema": {} + "schema": { } } } }, @@ -804,13 +804,13 @@ "requestBody": { "content": { "application/json": { - "schema": {} + "schema": { } }, "text/json": { - "schema": {} + "schema": { } }, "application/*+json": { - "schema": {} + "schema": { } } } }, From 79f79dc9929855ecbed1359ef70aaf4b033d701a Mon Sep 17 00:00:00 2001 From: maurei Date: Tue, 7 Sep 2021 16:20:11 +0200 Subject: [PATCH 20/23] add nuget specification in project file, add sourcelink --- .../JsonApiDotNetCore.OpenApi.csproj | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiDotNetCore.OpenApi.csproj b/src/JsonApiDotNetCore.OpenApi/JsonApiDotNetCore.OpenApi.csproj index cb9edfd066..32bcf4b46f 100644 --- a/src/JsonApiDotNetCore.OpenApi/JsonApiDotNetCore.OpenApi.csproj +++ b/src/JsonApiDotNetCore.OpenApi/JsonApiDotNetCore.OpenApi.csproj @@ -1,6 +1,19 @@ + 4.2.0 $(NetCoreAppVersion) + true + + + + jsonapidotnetcore;jsonapi;json:api;dotnet;asp.net;openapi;swagger;swaggerui;swashbuckle + A Swashbuckle integration that enables you to describe a JsonApiDotNetCore API with an OpenAPI specification. + https://www.jsonapi.net/ + MIT + false + true + true + embedded @@ -8,6 +21,10 @@ + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + From 6c61da61ca94ae5d148ae65c33daafef34ad9eb9 Mon Sep 17 00:00:00 2001 From: maurei Date: Tue, 7 Sep 2021 16:35:13 +0200 Subject: [PATCH 21/23] adjust buildscript --- Build.ps1 | 2 ++ test/OpenApiTests/swagger.json | 12 ++++++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Build.ps1 b/Build.ps1 index e099f62655..e3c05d0f89 100644 --- a/Build.ps1 +++ b/Build.ps1 @@ -85,9 +85,11 @@ function CreateNuGetPackage { if ([string]::IsNullOrWhitespace($versionSuffix)) { dotnet pack .\src\JsonApiDotNetCore -c Release -o .\artifacts + dotnet pack .\src\JsonApiDotNetCore.OpenApi -c Release -o .\artifacts } else { dotnet pack .\src\JsonApiDotNetCore -c Release -o .\artifacts --version-suffix=$versionSuffix + dotnet pack .\src\JsonApiDotNetCore.OpenApi -c Release -o .\artifacts --version-suffix=$versionSuffix } CheckLastExitCode diff --git a/test/OpenApiTests/swagger.json b/test/OpenApiTests/swagger.json index 87aa21d5bd..e90093c24d 100644 --- a/test/OpenApiTests/swagger.json +++ b/test/OpenApiTests/swagger.json @@ -366,13 +366,13 @@ "requestBody": { "content": { "application/json": { - "schema": { } + "schema": {} }, "text/json": { - "schema": { } + "schema": {} }, "application/*+json": { - "schema": { } + "schema": {} } } }, @@ -804,13 +804,13 @@ "requestBody": { "content": { "application/json": { - "schema": { } + "schema": {} }, "text/json": { - "schema": { } + "schema": {} }, "application/*+json": { - "schema": { } + "schema": {} } } }, From c6e6e3763188ea20e43e3fce4fe115a481d1424f Mon Sep 17 00:00:00 2001 From: maurei Date: Wed, 8 Sep 2021 09:40:45 +0200 Subject: [PATCH 22/23] Add comment to AddOpenApi, introduced authors tag and build property in project files --- Directory.Build.props | 1 + src/JsonApiDotNetCore.OpenApi/JsonApiDotNetCore.OpenApi.csproj | 3 ++- src/JsonApiDotNetCore.OpenApi/ServiceCollectionExtensions.cs | 3 +++ src/JsonApiDotNetCore/JsonApiDotNetCore.csproj | 3 ++- 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 51081c9523..baffceb9d2 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -5,6 +5,7 @@ 5.0.* 5.0.* 6.2.* + 4.2.0 $(MSBuildThisFileDirectory)CodingGuidelines.ruleset diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiDotNetCore.OpenApi.csproj b/src/JsonApiDotNetCore.OpenApi/JsonApiDotNetCore.OpenApi.csproj index 32bcf4b46f..251e13bd19 100644 --- a/src/JsonApiDotNetCore.OpenApi/JsonApiDotNetCore.OpenApi.csproj +++ b/src/JsonApiDotNetCore.OpenApi/JsonApiDotNetCore.OpenApi.csproj @@ -1,6 +1,6 @@ - 4.2.0 + $(JsonApiDotNetCoreVersionPrefix) $(NetCoreAppVersion) true @@ -8,6 +8,7 @@ jsonapidotnetcore;jsonapi;json:api;dotnet;asp.net;openapi;swagger;swaggerui;swashbuckle A Swashbuckle integration that enables you to describe a JsonApiDotNetCore API with an OpenAPI specification. + json-api-dotnet https://www.jsonapi.net/ MIT false diff --git a/src/JsonApiDotNetCore.OpenApi/ServiceCollectionExtensions.cs b/src/JsonApiDotNetCore.OpenApi/ServiceCollectionExtensions.cs index ae87769e65..e94d7458cf 100644 --- a/src/JsonApiDotNetCore.OpenApi/ServiceCollectionExtensions.cs +++ b/src/JsonApiDotNetCore.OpenApi/ServiceCollectionExtensions.cs @@ -6,6 +6,9 @@ namespace JsonApiDotNetCore.OpenApi { public static class ServiceCollectionExtensions { + /// + /// Adds the OpenAPI integration to JsonApiDotNetCore by configuring Swashbuckle. + /// public static void AddOpenApi(this IServiceCollection services, IMvcCoreBuilder mvcBuilder, Action setupSwaggerGenAction = null) { ArgumentGuard.NotNull(services, nameof(services)); diff --git a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj index 6192963587..5e1ae8a503 100644 --- a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj +++ b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj @@ -1,6 +1,6 @@ - 4.2.0 + $(JsonApiDotNetCoreVersionPrefix) $(NetCoreAppVersion) true @@ -8,6 +8,7 @@ jsonapidotnetcore;jsonapi;json:api;dotnet;asp.net A framework for building JSON:API compliant REST APIs using .NET Core and Entity Framework Core. Includes support for Atomic Operations. The ultimate goal of this library is to eliminate as much boilerplate as possible by offering out-of-the-box features such as sorting, filtering and pagination. You just need to focus on defining the resources and implementing your custom business logic. This library has been designed around dependency injection making extensibility incredibly easy. + json-api-dotnet https://www.jsonapi.net/ MIT false From c236cadd59d937735a71bcee62895152a9865078 Mon Sep 17 00:00:00 2001 From: Bart Koelman Date: Wed, 8 Sep 2021 09:51:48 +0200 Subject: [PATCH 23/23] Reformatted project file --- test/OpenApiTests/OpenApiTests.csproj | 42 +++++++++++++-------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/test/OpenApiTests/OpenApiTests.csproj b/test/OpenApiTests/OpenApiTests.csproj index e9391331ac..c4d01aadcf 100644 --- a/test/OpenApiTests/OpenApiTests.csproj +++ b/test/OpenApiTests/OpenApiTests.csproj @@ -1,27 +1,27 @@ - - $(NetCoreAppVersion) - + + $(NetCoreAppVersion) + - - - - + + + + - - - - - + + + + + - - - + + + - - - - - - + + + + + +