diff --git a/infrastructure/templates/template.json b/infrastructure/templates/template.json index 2262edd6e97..615d5ebfcca 100644 --- a/infrastructure/templates/template.json +++ b/infrastructure/templates/template.json @@ -2114,7 +2114,7 @@ "NEXT_CONFIG_MODE": "server", "NODE_ENV": "production", "PUBLIC_URL": "[concat(variables('publicAppUrl'), '/')]", - "PUBLIC_API_BASE_URL": "[concat('https://', parameters('publicApiUrl'),'/api/v1.0')]", + "PUBLIC_API_BASE_URL": "[concat('https://', parameters('publicApiUrl'), '/v1')]", "PUBLIC_API_DOCS_URL": "[concat('https://', parameters('publicApiDocsUrl'))]", "WEBSITE_NODE_DEFAULT_VERSION": "20.16.0", "WEBSITES_PORT": 3000 diff --git a/src/GovUk.Education.ExploreEducationStatistics.Admin/Services/Public.Data/PublicDataApiClient.cs b/src/GovUk.Education.ExploreEducationStatistics.Admin/Services/Public.Data/PublicDataApiClient.cs index f30928a4d95..7d98fb8687b 100644 --- a/src/GovUk.Education.ExploreEducationStatistics.Admin/Services/Public.Data/PublicDataApiClient.cs +++ b/src/GovUk.Education.ExploreEducationStatistics.Admin/Services/Public.Data/PublicDataApiClient.cs @@ -35,7 +35,7 @@ public async Task> GetDataSetVersionCh { return await SendRequest( () => httpClient.GetAsync( - $"api/v1/data-sets/{dataSetId}/versions/{dataSetVersion}/changes", + $"v1/data-sets/{dataSetId}/versions/{dataSetVersion}/changes", cancellationToken ), cancellationToken diff --git a/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Api.Tests/Controllers/DataSetVersionsControllerTests.cs b/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Api.Tests/Controllers/DataSetVersionsControllerTests.cs index 8e64f7b9d08..ba8fae60144 100644 --- a/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Api.Tests/Controllers/DataSetVersionsControllerTests.cs +++ b/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Api.Tests/Controllers/DataSetVersionsControllerTests.cs @@ -20,7 +20,7 @@ namespace GovUk.Education.ExploreEducationStatistics.Public.Data.Api.Tests.Contr public abstract class DataSetVersionsControllerTests(TestApplicationFactory testApp) : IntegrationTestFixture(testApp) { - private const string BaseUrl = "api/v1/data-sets"; + private const string BaseUrl = "v1/data-sets"; public class ListDataSetVersionsTests(TestApplicationFactory testApp) : DataSetVersionsControllerTests(testApp) { diff --git a/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Api.Tests/Controllers/DataSetsControllerGetQueryTests.cs b/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Api.Tests/Controllers/DataSetsControllerGetQueryTests.cs index 0a1287e3c12..b3f4e040f08 100644 --- a/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Api.Tests/Controllers/DataSetsControllerGetQueryTests.cs +++ b/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Api.Tests/Controllers/DataSetsControllerGetQueryTests.cs @@ -23,7 +23,7 @@ namespace GovUk.Education.ExploreEducationStatistics.Public.Data.Api.Tests.Contr public abstract class DataSetsControllerGetQueryTests(TestApplicationFactory testApp) : IntegrationTestFixture(testApp) { - private const string BaseUrl = "api/v1/data-sets"; + private const string BaseUrl = "v1/data-sets"; private readonly TestDataSetVersionPathResolver _dataSetVersionPathResolver = new() { diff --git a/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Api.Tests/Controllers/DataSetsControllerPostQueryTests.cs b/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Api.Tests/Controllers/DataSetsControllerPostQueryTests.cs index f1547e63fe4..15cc2c59ed3 100644 --- a/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Api.Tests/Controllers/DataSetsControllerPostQueryTests.cs +++ b/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Api.Tests/Controllers/DataSetsControllerPostQueryTests.cs @@ -25,7 +25,7 @@ namespace GovUk.Education.ExploreEducationStatistics.Public.Data.Api.Tests.Contr public abstract class DataSetsControllerPostQueryTests(TestApplicationFactory testApp) : IntegrationTestFixture(testApp) { - private const string BaseUrl = "api/v1/data-sets"; + private const string BaseUrl = "v1/data-sets"; private readonly TestDataSetVersionPathResolver _dataSetVersionPathResolver = new() { diff --git a/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Api.Tests/Controllers/DataSetsControllerTests.cs b/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Api.Tests/Controllers/DataSetsControllerTests.cs index 974d7a84797..4b9cb85467a 100644 --- a/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Api.Tests/Controllers/DataSetsControllerTests.cs +++ b/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Api.Tests/Controllers/DataSetsControllerTests.cs @@ -25,7 +25,7 @@ namespace GovUk.Education.ExploreEducationStatistics.Public.Data.Api.Tests.Contr public abstract class DataSetsControllerTests(TestApplicationFactory testApp) : IntegrationTestFixture(testApp) { - private const string BaseUrl = "api/v1/data-sets"; + private const string BaseUrl = "v1/data-sets"; public class GetDataSetTests(TestApplicationFactory testApp) : DataSetsControllerTests(testApp) { diff --git a/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Api.Tests/Controllers/PublicationsControllerTests.cs b/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Api.Tests/Controllers/PublicationsControllerTests.cs index bc99ad83d1a..0101cd1e8d7 100644 --- a/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Api.Tests/Controllers/PublicationsControllerTests.cs +++ b/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Api.Tests/Controllers/PublicationsControllerTests.cs @@ -21,7 +21,7 @@ namespace GovUk.Education.ExploreEducationStatistics.Public.Data.Api.Tests.Contr public abstract class PublicationsControllerTests(TestApplicationFactory testApp) : IntegrationTestFixture(testApp) { - private const string BaseUrl = "api/v1/publications"; + private const string BaseUrl = "v1/publications"; public class ListPublicationsTests(TestApplicationFactory testApp) : PublicationsControllerTests(testApp) { diff --git a/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Api.Tests/Swagger/VersionedPathsDocumentFilterTests.cs b/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Api.Tests/Swagger/VersionedPathsDocumentFilterTests.cs new file mode 100644 index 00000000000..6f8ae622251 --- /dev/null +++ b/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Api.Tests/Swagger/VersionedPathsDocumentFilterTests.cs @@ -0,0 +1,130 @@ +using System.Text.Json; +using GovUk.Education.ExploreEducationStatistics.Public.Data.Api.Swagger; +using Microsoft.OpenApi.Models; +using Swashbuckle.AspNetCore.SwaggerGen; + +namespace GovUk.Education.ExploreEducationStatistics.Public.Data.Api.Tests.Swagger; + +public class VersionedPathsDocumentFilterTests +{ + [Fact] + public void VersionsInlinedIntoPaths() + { + var document = new OpenApiDocument + { + Info = new OpenApiInfo { Version = "1" }, + Paths = new OpenApiPaths + { + {"/v{version}/endpoint-1", new OpenApiPathItem()}, + {"/v{version}/endpoint-2/{id}", new OpenApiPathItem()} + } + }; + + var filter = new VersionedPathsDocumentFilter(); + var context = CreateDocumentFilterContext(); + + filter.Apply(document, context); + + Assert.Equal(2, document.Paths.Count); + Assert.Contains("/v1/endpoint-1", document.Paths.Keys); + Assert.Contains("/v1/endpoint-2/{id}", document.Paths.Keys); + } + + [Fact] + public void VersionParametersRemoved() + { + var document = new OpenApiDocument + { + Info = new OpenApiInfo { Version = "1" }, + Paths = new OpenApiPaths + { + { + "/v{version}/endpoint-1", + new OpenApiPathItem + { + Parameters = + [ + new OpenApiParameter { Name = "version" } + ], + Operations = + { + { + OperationType.Get, + new OpenApiOperation + { + Parameters = + [ + new OpenApiParameter { Name = "version" } + ] + } + } + + } + } + }, + { + "/v{version}/endpoint-2/{id}", + new OpenApiPathItem + { + Parameters = + [ + new OpenApiParameter { Name = "version" }, + new OpenApiParameter { Name = "id" } + ], + Operations = + { + { + OperationType.Get, + new OpenApiOperation + { + Parameters = + [ + new OpenApiParameter { Name = "version" }, + new OpenApiParameter { Name = "id" } + ] + } + } + + } + } + } + } + }; + + var filter = new VersionedPathsDocumentFilter(); + var context = CreateDocumentFilterContext(); + + filter.Apply(document, context); + + Assert.Equal(2, document.Paths.Count); + + var endpoint1Paths = document.Paths["/v1/endpoint-1"]; + + Assert.Empty(endpoint1Paths.Parameters); + Assert.Empty(endpoint1Paths.Operations[OperationType.Get].Parameters); + + var endpoint2Paths = document.Paths["/v1/endpoint-2/{id}"]; + + Assert.Single(endpoint2Paths.Parameters); + Assert.Equal("id", endpoint2Paths.Parameters[0].Name); + + Assert.Single(endpoint2Paths.Operations[OperationType.Get].Parameters); + Assert.Equal("id", endpoint2Paths.Parameters[0].Name); + } + + private static DocumentFilterContext CreateDocumentFilterContext() + { + var schemaGenerator = new SchemaGenerator( + new SchemaGeneratorOptions(), + new JsonSerializerDataContractResolver( + new JsonSerializerOptions + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase + } + ) + ); + var schemaRepository = new SchemaRepository(); + + return new DocumentFilterContext([], schemaGenerator, schemaRepository); + } +} diff --git a/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Api/Controllers/DataSetVersionsController.cs b/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Api/Controllers/DataSetVersionsController.cs index dc46e2e74fb..dcd5a61e06f 100644 --- a/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Api/Controllers/DataSetVersionsController.cs +++ b/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Api/Controllers/DataSetVersionsController.cs @@ -10,9 +10,9 @@ namespace GovUk.Education.ExploreEducationStatistics.Public.Data.Api.Controllers; -[ApiVersion(1.0)] +[ApiVersion("1")] [ApiController] -[Route("api/v{version:apiVersion}/data-sets/{dataSetId:guid}/versions")] +[Route("v{version:apiVersion}/data-sets/{dataSetId:guid}/versions")] public class DataSetVersionsController( IDataSetService dataSetService, IDataSetVersionChangeService dataSetVersionChangeService) diff --git a/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Api/Controllers/DataSetsController.cs b/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Api/Controllers/DataSetsController.cs index ecd16d7cf40..de99e4dd527 100644 --- a/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Api/Controllers/DataSetsController.cs +++ b/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Api/Controllers/DataSetsController.cs @@ -11,9 +11,9 @@ namespace GovUk.Education.ExploreEducationStatistics.Public.Data.Api.Controllers; -[ApiVersion(1.0)] +[ApiVersion("1")] [ApiController] -[Route("api/v{version:apiVersion}/data-sets")] +[Route("v{version:apiVersion}/data-sets")] public class DataSetsController( IDataSetService dataSetService, IDataSetQueryService dataSetQueryService) diff --git a/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Api/Controllers/PublicationsController.cs b/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Api/Controllers/PublicationsController.cs index 8ee6cdd0eb7..74d901d6163 100644 --- a/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Api/Controllers/PublicationsController.cs +++ b/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Api/Controllers/PublicationsController.cs @@ -10,9 +10,9 @@ namespace GovUk.Education.ExploreEducationStatistics.Public.Data.Api.Controllers; -[ApiVersion(1.0)] +[ApiVersion("1")] [ApiController] -[Route("api/v{version:apiVersion}/publications")] +[Route("v{version:apiVersion}/publications")] public class PublicationsController(IPublicationService publicationService, IDataSetService dataSetService) : ControllerBase { diff --git a/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Api/Program.cs b/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Api/Program.cs index 214a54bb4fa..81854448f17 100644 --- a/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Api/Program.cs +++ b/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Api/Program.cs @@ -39,7 +39,7 @@ app.UseSwagger(options => { - options.RouteTemplate = "/swagger/{documentName}/openapi.json"; + options.RouteTemplate = "/swagger/v{documentName}/openapi.json"; }); app.UseSwaggerUI(options => { @@ -48,7 +48,7 @@ foreach (var description in app.DescribeApiVersions()) { options.SwaggerEndpoint( - url: $"/swagger/{description.GroupName}/openapi.json", + url: $"/swagger/v{description.GroupName}/openapi.json", name: $"v{description.GroupName}"); } }); diff --git a/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Api/Swagger/SwaggerConfig.cs b/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Api/Swagger/SwaggerConfig.cs index 8d00439bc1e..babd1bdec18 100644 --- a/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Api/Swagger/SwaggerConfig.cs +++ b/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Api/Swagger/SwaggerConfig.cs @@ -16,8 +16,11 @@ public class SwaggerConfig( { public void Configure(SwaggerGenOptions options) { + options.DocumentFilter(); + options.OperationFilter(); options.OperationFilter(); + options.SchemaFilter(); options.SchemaFilter(); options.SchemaFilter(); diff --git a/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Api/Swagger/VersionedPathsDocumentFilter.cs b/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Api/Swagger/VersionedPathsDocumentFilter.cs new file mode 100644 index 00000000000..3e0b85e334a --- /dev/null +++ b/src/GovUk.Education.ExploreEducationStatistics.Public.Data.Api/Swagger/VersionedPathsDocumentFilter.cs @@ -0,0 +1,32 @@ +using Microsoft.OpenApi.Models; +using Swashbuckle.AspNetCore.SwaggerGen; + +namespace GovUk.Education.ExploreEducationStatistics.Public.Data.Api.Swagger; + +public class VersionedPathsDocumentFilter : IDocumentFilter +{ + public void Apply(OpenApiDocument document, DocumentFilterContext context) + { + var newPaths = new OpenApiPaths(); + + foreach (var path in document.Paths) + { + var versionedPath = path.Key.Replace("{version}", document.Info.Version); + + newPaths[versionedPath] = path.Value; + + path.Value.Parameters = path.Value.Parameters + .Where(p => p.Name != "version") + .ToList(); + + foreach (var operation in path.Value.Operations.Values) + { + operation.Parameters = operation.Parameters + .Where(p => p.Name != "version") + .ToList(); + } + } + + document.Paths = newPaths; + } +} diff --git a/src/explore-education-statistics-frontend/.env b/src/explore-education-statistics-frontend/.env index a2390fb9898..95c495d7605 100644 --- a/src/explore-education-statistics-frontend/.env +++ b/src/explore-education-statistics-frontend/.env @@ -1,6 +1,6 @@ CONTENT_API_BASE_URL=http://localhost:5010/api DATA_API_BASE_URL=http://localhost:5000/api -PUBLIC_API_BASE_URL=http://localhost:5050/api/v1.0 +PUBLIC_API_BASE_URL=http://localhost:5050/v1 PUBLIC_API_DOCS_URL=https://dev.statistics.api.education.gov.uk/docs NOTIFICATION_API_BASE_URL=http://localhost:7073/api GA_TRACKING_ID=