diff --git a/tools/code/common/Api.cs b/tools/code/common/Api.cs index a1642ec0..797fdc77 100644 --- a/tools/code/common/Api.cs +++ b/tools/code/common/Api.cs @@ -456,7 +456,7 @@ public static async ValueTask> TryGetSpecificationContents(th catch (HttpRequestException exception) when (exception.StatusCode == HttpStatusCode.InternalServerError) { // Don't export XML specifications, as the non-link exports cannot be reimported. - if (specification is ApiSpecification.Wsdl or ApiSpecification.Wadl) + if (specification is ApiSpecification.Wsdl or ApiSpecification.Wadl or ApiSpecification.OData) { return Option.None; } @@ -498,6 +498,7 @@ private static string GetExportFormat(ApiSpecification specification, bool inclu { ApiSpecification.Wadl => "wadl", ApiSpecification.Wsdl => "wsdl", + ApiSpecification.OData => "odata", ApiSpecification.OpenApi openApiSpecification => (openApiSpecification.Version, openApiSpecification.Format) switch { @@ -541,6 +542,10 @@ public static async ValueTask PutDto(this ApiUri uri, ApiDto dto, HttpPipeline p { await PutSoapApi(uri, dto, pipeline, cancellationToken); } + else if (dto.Properties.ApiType is "odata") + { + await PutODataApi(uri, dto, pipeline, cancellationToken); + } else { await PutNonSoapApi(uri, dto, pipeline, cancellationToken); @@ -603,6 +608,32 @@ await soapApiResiliencePipeline.Value }) .Build()); + private static async ValueTask PutODataApi(ApiUri uri, ApiDto dto, HttpPipeline pipeline, CancellationToken cancellationToken) + { + // Import API with specification + var odataUri = uri.ToUri().SetQueryParam("import", "true").ToUri(); + var odataDto = new ApiDto + { + Properties = new ApiDto.ApiCreateOrUpdateProperties + { + Format = "odata", + Value = dto.Properties.Value, + ApiType = "odata", + DisplayName = dto.Properties.DisplayName, + Path = dto.Properties.Path, + Protocols = dto.Properties.Protocols, + ApiVersion = dto.Properties.ApiVersion, + ApiVersionDescription = dto.Properties.ApiVersionDescription, + ApiVersionSetId = dto.Properties.ApiVersionSetId + } + }; + await pipeline.PutContent(odataUri, BinaryData.FromObjectAsJson(odataDto), cancellationToken); + + // Put API again without specification + var updatedDto = dto with { Properties = dto.Properties with { Format = null, Value = null } }; + await pipeline.PutContent(uri.ToUri(), BinaryData.FromObjectAsJson(updatedDto), cancellationToken); + } + private static async ValueTask PutNonSoapApi(ApiUri uri, ApiDto dto, HttpPipeline pipeline, CancellationToken cancellationToken) { // Put API without the specification. diff --git a/tools/code/common/ApiSpecification.cs b/tools/code/common/ApiSpecification.cs index b573a5e8..fbd48634 100644 --- a/tools/code/common/ApiSpecification.cs +++ b/tools/code/common/ApiSpecification.cs @@ -14,6 +14,7 @@ public abstract record ApiSpecification public sealed record GraphQl : ApiSpecification; public sealed record Wadl : ApiSpecification; public sealed record Wsdl : ApiSpecification; + public sealed record OData : ApiSpecification; public sealed record OpenApi : ApiSpecification { public required OpenApiVersion Version { get; init; } @@ -67,6 +68,7 @@ public static ApiSpecificationFile From(ApiSpecification specification, ApiName ApiSpecification.GraphQl => GraphQlSpecificationFile.From(apiName, serviceDirectory), ApiSpecification.Wadl => WadlSpecificationFile.From(apiName, serviceDirectory), ApiSpecification.Wsdl => WsdlSpecificationFile.From(apiName, serviceDirectory), + ApiSpecification.OData => ODataSpecificationFile.From(apiName, serviceDirectory), ApiSpecification.OpenApi openApi => OpenApiSpecificationFile.From(openApi, apiName, serviceDirectory), _ => throw new NotImplementedException() }; @@ -88,10 +90,13 @@ public static async ValueTask> TryParse(FileInfo? f var tryParseWsdl = () => (from specificationFile in WsdlSpecificationFile.TryParse(file, serviceDirectory) select specificationFile as ApiSpecificationFile).AsTask(); + var tryParseOData = () => (from specificationFile in ODataSpecificationFile.TryParse(file, serviceDirectory) + select specificationFile as ApiSpecificationFile).AsTask(); + var tryParseOpenApi = async () => from specificationFile in await OpenApiSpecificationFile.TryParse(file, getFileContents, serviceDirectory, cancellationToken) select specificationFile as ApiSpecificationFile; - return await ImmutableArray.Create(tryParseGraphQl, tryParseWadl, tryParseWsdl, tryParseOpenApi) + return await ImmutableArray.Create(tryParseGraphQl, tryParseWadl, tryParseWsdl, tryParseOData, tryParseOpenApi) .Pick(async (f, cancellationToken) => await f(), cancellationToken); } } @@ -150,6 +155,24 @@ public static Option TryParse(FileInfo? file, ManagementS : Option.None; } +public sealed record ODataSpecificationFile : ApiSpecificationFile +{ + public override ApiSpecification Specification { get; } = new ApiSpecification.OData(); + + public static string Name => "specification.xml"; + + protected override FileInfo Value => new(Path.Combine(Parent.ToDirectoryInfo().FullName, Name)); + + public static ODataSpecificationFile From(ApiName apiName, ManagementServiceDirectory serviceDirectory) => + new() { Parent = ApiDirectory.From(apiName, serviceDirectory) }; + + public static Option TryParse(FileInfo? file, ManagementServiceDirectory serviceDirectory) => + file is not null && file.Name == Name + ? from parent in ApiDirectory.TryParse(file.Directory, serviceDirectory) + select new ODataSpecificationFile { Parent = parent } + : Option.None; +} + public abstract record OpenApiSpecificationFile : ApiSpecificationFile { public abstract OpenApiFormat Format { get; } diff --git a/tools/code/extractor/Api.cs b/tools/code/extractor/Api.cs index 584c27fe..7eea729c 100644 --- a/tools/code/extractor/Api.cs +++ b/tools/code/extractor/Api.cs @@ -179,6 +179,7 @@ Option tryGetSpecification(ApiDto dto) => { "graphql" => new ApiSpecification.GraphQl(), "soap" => new ApiSpecification.Wsdl(), + "odata" => new ApiSpecification.OData(), "http" => defaultApiSpecification.Value, null => defaultApiSpecification.Value, _ => Option.None diff --git a/tools/code/publisher/Api.cs b/tools/code/publisher/Api.cs index 683ba240..872a724c 100644 --- a/tools/code/publisher/Api.cs +++ b/tools/code/publisher/Api.cs @@ -697,6 +697,7 @@ file static class Common { WadlSpecificationFile.Name, WsdlSpecificationFile.Name, + ODataSpecificationFile.Name, GraphQlSpecificationFile.Name, JsonOpenApiSpecificationFile.Name, YamlOpenApiSpecificationFile.Name diff --git a/tools/code/publisher/WorkspaceApi.cs b/tools/code/publisher/WorkspaceApi.cs index 44a6d98c..d4f2a447 100644 --- a/tools/code/publisher/WorkspaceApi.cs +++ b/tools/code/publisher/WorkspaceApi.cs @@ -683,6 +683,7 @@ file static class Common { WadlSpecificationFile.Name, WsdlSpecificationFile.Name, + ODataSpecificationFile.Name, GraphQlSpecificationFile.Name, JsonOpenApiSpecificationFile.Name, YamlOpenApiSpecificationFile.Name