Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
ec15ee8
Add openAPI package
seantleonard Apr 12, 2023
6773bdd
Initial openapi service, controller, and mapped swagger ui viewer end…
seantleonard Apr 13, 2023
33dafd3
Add runtimeconfig to openapidocumentor.
seantleonard Apr 14, 2023
55a78e1
Automate Component Schema creation for Full Entity (with primary key).
seantleonard Apr 14, 2023
8894daf
additional GET path documenting
seantleonard Apr 24, 2023
9f2c700
add openapidoc creation at startup, refine error messages 409 and 500…
seantleonard Apr 27, 2023
1488636
Consolidated code paths, reduced code verbosity/duplication. Comments.
seantleonard Apr 27, 2023
c783106
updated response codes and formatting of number in openapi doc.
seantleonard Apr 28, 2023
81ceda1
updated openapicontroller route and updated swaggerUI uri to point to…
seantleonard Apr 28, 2023
accb50e
Remove swagger package, keep swaggerui.
seantleonard Apr 28, 2023
63f0b95
added constants and new suberrorcode.
seantleonard Apr 28, 2023
ca3ca2d
Merge branch 'main' into dev/seantleonard/openapiv3_initial
seantleonard Apr 28, 2023
2c25653
updated media type set as application/json for GET endpoint. updated …
seantleonard Apr 28, 2023
93bebc8
prevent entities from being openapi documented if they explicitly dis…
seantleonard Apr 28, 2023
3489ff9
Consolidated code paths, reduced code verbosity/duplication. Comments…
seantleonard May 3, 2023
ab5d9de
Merge branch 'main' into dev/seantleonard/openapiv3_initial
seantleonard May 3, 2023
9941fb7
Moved placement of swaggerUI setup, to fix HTTP400 errors
seantleonard May 3, 2023
058c53d
Remove ability to POST on openapicontroller since creation occurs on …
seantleonard May 3, 2023
12d25fb
remove unnecessary usings
seantleonard May 3, 2023
e79f905
updated comments to correctly reflect operations and expected results.
seantleonard May 3, 2023
28b4120
updating function comments in interface, updating documentor usage of…
seantleonard May 5, 2023
dbcf3b5
Merge branch 'main' into dev/seantleonard/openapiv3_initial
seantleonard May 5, 2023
cf7fbe3
updated custom REST route handling for swagger and openapi, moved ope…
seantleonard May 5, 2023
988faaf
updated with dotnet format.
seantleonard May 5, 2023
de2026f
fixed tests and controller logic
seantleonard May 5, 2023
f1e06b9
list to hashset to track columns
seantleonard May 5, 2023
f77b304
allow building notice file in dev.
seantleonard May 5, 2023
aaaee4d
allow building notice file remove conditions.
seantleonard May 6, 2023
69c5fb0
Merge branch 'main' into dev/seantleonard/openapiv3_initial
abhishekkumams May 8, 2023
d30b776
Merge branch 'main' into dev/seantleonard/openapiv3_initial
seantleonard May 8, 2023
32da9c4
updated tests, updated restservice/controller handling of swaggerendp…
seantleonard May 9, 2023
6aee930
added back condition to notice file generation task in ci/cd pipeline
seantleonard May 9, 2023
d25b15b
updated logic and tests for RestPath retrieval to use existing functions
seantleonard May 9, 2023
dd3ead5
reuse constants for default rest path /api
seantleonard May 9, 2023
834615d
updated hashset name to nonAutoGeneratedPKColumnNames
seantleonard May 10, 2023
b05b812
Merge branch 'main' into dev/seantleonard/openapiv3_initial
seantleonard May 11, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion src/Config/DataApiBuilderException.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,19 @@ public enum SubStatusCodes
/// <summary>
/// Error encountered while doing data type conversions.
/// </summary>
ErrorProcessingData
ErrorProcessingData,
/// <summary>
/// Attempting to generate OpenAPI document when one already exists.
/// </summary>
OpenApiDocumentAlreadyExists,
/// <summary>
/// Attempt to create OpenAPI document failed.
/// </summary>
OpenApiDocumentCreationFailure,
/// <summary>
/// Global REST endpoint disabled in runtime configuration.
/// </summary>
GlobalRestEndpointDisabled
}

public HttpStatusCode StatusCode { get; }
Expand Down
4 changes: 3 additions & 1 deletion src/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,14 @@
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.14" />
<PackageVersion Include="Microsoft.AspNetCore.TestHost" Version="6.0.14" />
<PackageVersion Include="Microsoft.Azure.Cosmos" Version="3.20.0" />
<!--When updating Microsoft.Data.SqlClient, update license URL in scripts/notice-generation.ps1-->
<!--When updating Microsoft.Data.SqlClient, update license URL in scripts/notice-generation.ps1-->
<PackageVersion Include="Microsoft.Data.SqlClient" Version="5.0.1" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Binder" Version="6.0.0" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Json" Version="6.0.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.3.2" />
<PackageVersion Include="Microsoft.OData.Edm" Version="7.12.5" />
<PackageVersion Include="Microsoft.OData.Core" Version="7.12.5" />
<PackageVersion Include="Microsoft.OpenApi" Version="1.6.3" />
<PackageVersion Include="Moq" Version="4.18.2" />
<PackageVersion Include="MSTest.TestAdapter" Version="2.2.10" />
<PackageVersion Include="MSTest.TestFramework" Version="2.2.10" />
Expand All @@ -32,6 +33,7 @@
<PackageVersion Include="Npgsql" Version="7.0.1" />
<PackageVersion Include="Polly" Version="7.2.3" />
<PackageVersion Include="StyleCop.Analyzers" Version="1.1.118" />
<PackageVersion Include="Swashbuckle.AspNetCore.SwaggerUI" Version="6.5.0" />
<PackageVersion Include="System.CommandLine" Version="2.0.0-beta4.22272.1" />
<PackageVersion Include="System.Drawing.Common" Version="6.0.0" />
<PackageVersion Include="System.IO.Abstractions" Version="17.2.3" />
Expand Down
338 changes: 319 additions & 19 deletions src/Service.Tests/Configuration/ConfigurationTests.cs

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

namespace Azure.DataApiBuilder.Service.Tests
{
public class OpenApiDocumentorConstants
{
public const string TOPLEVELPROPERTY_OPENAPI = "openapi";
public const string TOPLEVELPROPERTY_INFO = "info";
public const string TOPLEVELPROPERTY_SERVERS = "servers";
public const string TOPLEVELPROPERTY_PATHS = "paths";
public const string TOPLEVELPROPERTY_COMPONENTS = "components";
public const string PROPERTY_SCHEMAS = "schemas";
}
}
21 changes: 11 additions & 10 deletions src/Service.Tests/Unittests/RestServiceUnitTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ public class RestServiceUnitTests
#region Positive Cases

/// <summary>
/// Test the REST Service for parsing entity name
/// and primary key route from the route, given a
/// particular path.
/// Validates that the RestService helper function GetEntityNameAndPrimaryKeyRouteFromRoute
/// properly parses the entity name and primary key route from the route,
/// given the input path (which does not include the path base).
/// </summary>
/// <param name="route">The route to parse.</param>
/// <param name="path">The path that the route starts with.</param>
Expand All @@ -42,14 +42,16 @@ public class RestServiceUnitTests
[DataRow("rest api/Book/id/1", "/rest api", "Book", "id/1")]
[DataRow(" rest_api/commodities/categoryid/1/pieceid/1", "/ rest_api", "commodities", "categoryid/1/pieceid/1")]
[DataRow("rest-api/Book/id/1", "/rest-api", "Book", "id/1")]
public void ParseEntityNameAndPrimaryKeyTest(string route,
string path,
string expectedEntityName,
string expectedPrimaryKeyRoute)
public void ParseEntityNameAndPrimaryKeyTest(
string route,
string path,
string expectedEntityName,
string expectedPrimaryKeyRoute)
{
InitializeTest(path, expectedEntityName);
string routeAfterPathBase = _restService.GetRouteAfterPathBase(route);
(string actualEntityName, string actualPrimaryKeyRoute) =
_restService.GetEntityNameAndPrimaryKeyRouteFromRoute(route);
_restService.GetEntityNameAndPrimaryKeyRouteFromRoute(routeAfterPathBase);
Assert.AreEqual(expectedEntityName, actualEntityName);
Assert.AreEqual(expectedPrimaryKeyRoute, actualPrimaryKeyRoute);
}
Expand All @@ -76,8 +78,7 @@ public void ErrorForInvalidRouteAndPathToParseTest(string route,
InitializeTest(path, route);
try
{
(string actualEntityName, string actualPrimaryKeyRoute) =
_restService.GetEntityNameAndPrimaryKeyRouteFromRoute(route);
string routeAfterPathBase = _restService.GetRouteAfterPathBase(route);
}
catch (DataApiBuilderException e)
{
Expand Down
2 changes: 2 additions & 0 deletions src/Service/Azure.DataApiBuilder.Service.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
<PackageReference Include="Microsoft.Extensions.Configuration.Json" />
<PackageReference Include="Microsoft.OData.Edm" />
<PackageReference Include="Microsoft.OData.Core" />
<PackageReference Include="Microsoft.OpenApi" />
<PackageReference Include="MSTest.TestFramework" />
<PackageReference Include="MySqlConnector" />
<PackageReference Include="Newtonsoft.Json" />
Expand All @@ -67,6 +68,7 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" />
<PackageReference Include="System.CommandLine" />
<PackageReference Include="System.IO.Abstractions" />
<PackageReference Include="Microsoft.SourceLink.GitHub" PrivateAssets="All"/>
Expand Down
30 changes: 26 additions & 4 deletions src/Service/Controllers/RestController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@

using System;
using System.Net;
using System.Net.Mime;
using System.Threading.Tasks;
using Azure.DataApiBuilder.Service.Exceptions;
using Azure.DataApiBuilder.Service.Models;
using Azure.DataApiBuilder.Service.Services;
using Azure.DataApiBuilder.Service.Services.OpenAPI;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.Mvc;
Expand All @@ -27,6 +29,11 @@ public class RestController : ControllerBase
/// Service providing REST Api executions.
/// </summary>
private readonly RestService _restService;

/// <summary>
/// OpenAPI description document creation service.
/// </summary>
private readonly IOpenApiDocumentor _openApiDocumentor;
/// <summary>
/// String representing the value associated with "code" for a server error
/// </summary>
Expand All @@ -44,9 +51,10 @@ public class RestController : ControllerBase
/// <summary>
/// Constructor.
/// </summary>
public RestController(RestService restService, ILogger<RestController> logger)
public RestController(RestService restService, IOpenApiDocumentor openApiDocumentor, ILogger<RestController> logger)
{
_restService = restService;
_openApiDocumentor = openApiDocumentor;
_logger = logger;
}

Expand Down Expand Up @@ -87,8 +95,8 @@ public async Task<IActionResult> Find(
string route)
{
return await HandleOperation(
route,
Config.Operation.Read);
route,
Config.Operation.Read);
}

/// <summary>
Expand Down Expand Up @@ -188,7 +196,21 @@ private async Task<IActionResult> HandleOperation(
subStatusCode: DataApiBuilderException.SubStatusCodes.BadRequest);
}

(string entityName, string primaryKeyRoute) = _restService.GetEntityNameAndPrimaryKeyRouteFromRoute(route);
// Validate the PathBase matches the configured REST path.
string routeAfterPathBase = _restService.GetRouteAfterPathBase(route);

// Explicitly handle OpenAPI description document retrieval requests.
if (string.Equals(routeAfterPathBase, OpenApiDocumentor.OPENAPI_ROUTE, StringComparison.OrdinalIgnoreCase))
{
if (_openApiDocumentor.TryGetDocument(out string? document))
{
return Content(document, MediaTypeNames.Application.Json);
}

return NotFound();
}

(string entityName, string primaryKeyRoute) = _restService.GetEntityNameAndPrimaryKeyRouteFromRoute(routeAfterPathBase);

IActionResult? result = await _restService.ExecuteAsync(entityName, operationType, primaryKeyRoute);

Expand Down
65 changes: 0 additions & 65 deletions src/Service/Services/DbTypeHelper.cs

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ private async Task FillSchemaForStoredProcedureAsync(
new()
{
SystemType = systemType,
DbType = DbTypeHelper.GetDbTypeFromSystemType(systemType)
DbType = TypeHelper.GetDbTypeFromSystemType(systemType)
}
);
}
Expand Down Expand Up @@ -1016,7 +1016,7 @@ private async Task PopulateSourceDefinitionAsync(
IsNullable = (bool)columnInfoFromAdapter["AllowDBNull"],
IsAutoGenerated = (bool)columnInfoFromAdapter["IsAutoIncrement"],
SystemType = systemTypeOfColumn,
DbType = DbTypeHelper.GetDbTypeFromSystemType(systemTypeOfColumn)
DbType = TypeHelper.GetDbTypeFromSystemType(systemTypeOfColumn)
};

// Tests may try to add the same column simultaneously
Expand Down
31 changes: 31 additions & 0 deletions src/Service/Services/OpenAPI/IOpenApiDocumentor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System.Diagnostics.CodeAnalysis;

namespace Azure.DataApiBuilder.Service.Services.OpenAPI
{
/// <summary>
/// Interface for the service which generates and provides the OpenAPI description document
/// describing the DAB engine's entity REST endpoint paths.
/// </summary>
public interface IOpenApiDocumentor
{
/// <summary>
/// Attempts to return the OpenAPI description document, if generated.
/// </summary>
/// <param name="document">String representation of JSON OpenAPI description document.</param>
/// <returns>True (plus string representation of document), when document exists. False, otherwise.</returns>
public bool TryGetDocument([NotNullWhen(true)] out string? document);

/// <summary>
/// Creates an OpenAPI description document using OpenAPI.NET.
/// Document compliant with patches of OpenAPI V3.0 spec 3.0.0 and 3.0.1,
/// aligned with specification support provided by Microsoft.OpenApi.
/// </summary>
/// <exception cref="DataApiBuilderException">Raised when document is already generated
/// or a failure occurs during generation.</exception>
/// <seealso cref="https://github.com/microsoft/OpenAPI.NET/blob/1.6.3/src/Microsoft.OpenApi/OpenApiSpecVersion.cs"/>
public void CreateDocument();
}
}
42 changes: 42 additions & 0 deletions src/Service/Services/OpenAPI/JsonDataType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

namespace Azure.DataApiBuilder.Service.Services.OpenAPI
{
/// <summary>
/// Specifies the data type of a JSON value.
/// Distinguished from System.Text.Json enum JsonValueKind because there are no separate
/// values for JsonValueKind.True or JsonValueKind.False, only a single value JsonDataType.Boolean.
/// This distinction is necessary to facilitate OpenAPI schema creation which requires generic
/// JSON types to be defined for parameters. Because no values are present, JsonValueKind.True/False
/// can't be used.
/// </summary>
public enum JsonDataType
{
Undefined = 0,
/// <summary>
/// A JSON Object
/// </summary>
Object = 1,
/// <summary>
/// A JSON array
/// </summary>
Array = 2,
/// <summary>
/// A JSON string
/// </summary>
String = 3,
/// <summary>
/// A JSON number
/// </summary>
Number = 4,
/// <summary>
/// A JSON Boolean
/// </summary>
Boolean = 5,
/// <summary>
/// The JSON value null
/// </summary>
Null = 6
}
}
Loading