From b3301af86b960d9a114c113d573cee75e4b29ad8 Mon Sep 17 00:00:00 2001 From: "Chidozie Ononiwu (His Righteousness)" <31145988+chidozieononiwu@users.noreply.github.com> Date: Wed, 26 Apr 2023 10:14:32 -0700 Subject: [PATCH] Make Swagger Parser Pull in Properties referenced in other files (#6009) --- .../SwaggerApiParser/Program.cs | 2 +- .../SwaggerAPIViewGenerator.cs | 19 +- .../SwaggerApiView/SwaggerApiViewRoot.cs | 5 +- .../SwaggerSpec/SchemaCache.cs | 30 +- .../SwaggerSpec/SwaggerTypes.cs | 7 +- .../SwaggerApiParser/Utils.cs | 22 ++ .../SwaggerAPIViewGeneratorTest.cs | 2 +- .../SwaggerAPIViewTest.cs | 36 +- .../fixtures/devcenter.json | 330 ++++++++++++++++++ 9 files changed, 397 insertions(+), 56 deletions(-) create mode 100644 tools/apiview/parsers/swagger-api-parser/SwaggerApiParserTest/fixtures/devcenter.json diff --git a/tools/apiview/parsers/swagger-api-parser/SwaggerApiParser/Program.cs b/tools/apiview/parsers/swagger-api-parser/SwaggerApiParser/Program.cs index f4a0f945147..194413774ca 100644 --- a/tools/apiview/parsers/swagger-api-parser/SwaggerApiParser/Program.cs +++ b/tools/apiview/parsers/swagger-api-parser/SwaggerApiParser/Program.cs @@ -108,7 +108,7 @@ static async Task HandleGenerateCodeFile(IEnumerable swaggers, string ou foreach (var swaggerSpec in swaggerSpecs) { - root.AddSwaggerSpec(swaggerSpec, swaggerSpec.swaggerFilePath, packageName, swaggerSpec.swaggerLink); + await root.AddSwaggerSpec(swaggerSpec, swaggerSpec.swaggerFilePath, packageName, swaggerSpec.swaggerLink); } var codeFile = root.GenerateCodeFile(); diff --git a/tools/apiview/parsers/swagger-api-parser/SwaggerApiParser/SwaggerAPIViewGenerator.cs b/tools/apiview/parsers/swagger-api-parser/SwaggerApiParser/SwaggerAPIViewGenerator.cs index 43ce5f2e340..134037737b8 100644 --- a/tools/apiview/parsers/swagger-api-parser/SwaggerApiParser/SwaggerAPIViewGenerator.cs +++ b/tools/apiview/parsers/swagger-api-parser/SwaggerApiParser/SwaggerAPIViewGenerator.cs @@ -1,12 +1,13 @@ using System; using System.Collections.Generic; using System.IO; +using System.Threading.Tasks; namespace SwaggerApiParser; public class SwaggerApiViewGenerator { - public static SwaggerApiViewSpec GenerateSwaggerApiView(SwaggerSpec swaggerSpec, string swaggerFilePath, SchemaCache schemaCache, string packageName = "", string swaggerLink = "") + public static async Task GenerateSwaggerApiView(SwaggerSpec swaggerSpec, string swaggerFilePath, SchemaCache schemaCache, string packageName = "", string swaggerLink = "") { SwaggerApiViewSpec ret = new SwaggerApiViewSpec { @@ -70,6 +71,7 @@ public static SwaggerApiViewSpec GenerateSwaggerApiView(SwaggerSpec swaggerSpec, }; if (value.parameters != null) + { foreach (var parameter in value.parameters) { var param = parameter; @@ -82,7 +84,18 @@ public static SwaggerApiViewSpec GenerateSwaggerApiView(SwaggerSpec swaggerSpec, if (param == null) { - continue; + if (!Path.IsPathFullyQualified(parameter.Ref)) + { + var referenceSwaggerFilePath = Utils.GetReferencedSwaggerFile(parameter.Ref, currentSwaggerFilePath); + var referenceSwaggerSpec = await SwaggerDeserializer.Deserialize(referenceSwaggerFilePath); + referenceSwaggerSpec.swaggerFilePath = Path.GetFullPath(referenceSwaggerFilePath); + AddDefinitionsToCache(referenceSwaggerSpec, referenceSwaggerFilePath, schemaCache); + param = schemaCache.GetParameterFromCache(parameter.Ref, referenceSwaggerFilePath); + } + else + { + continue; + } } var swaggerApiViewOperationParameter = new SwaggerApiViewParameter @@ -114,8 +127,6 @@ public static SwaggerApiViewSpec GenerateSwaggerApiView(SwaggerSpec swaggerSpec, break; } } - - { } diff --git a/tools/apiview/parsers/swagger-api-parser/SwaggerApiParser/SwaggerApiView/SwaggerApiViewRoot.cs b/tools/apiview/parsers/swagger-api-parser/SwaggerApiParser/SwaggerApiView/SwaggerApiViewRoot.cs index ecbe1be1517..2644159e864 100644 --- a/tools/apiview/parsers/swagger-api-parser/SwaggerApiParser/SwaggerApiView/SwaggerApiViewRoot.cs +++ b/tools/apiview/parsers/swagger-api-parser/SwaggerApiParser/SwaggerApiView/SwaggerApiViewRoot.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Threading.Tasks; namespace SwaggerApiParser; @@ -19,9 +20,9 @@ public SwaggerApiViewRoot(string resourceProvider, string packageName) this.schemaCache = new SchemaCache(); } - public void AddSwaggerSpec(SwaggerSpec swaggerSpec, string swaggerFilePath, string resourceProvider = "", string swaggerLink="") + public async Task AddSwaggerSpec(SwaggerSpec swaggerSpec, string swaggerFilePath, string resourceProvider = "", string swaggerLink="") { - var swaggerApiViewSpec = SwaggerApiViewGenerator.GenerateSwaggerApiView(swaggerSpec, swaggerFilePath, this.schemaCache, resourceProvider, swaggerLink); + var swaggerApiViewSpec = await SwaggerApiViewGenerator.GenerateSwaggerApiView(swaggerSpec, swaggerFilePath, this.schemaCache, resourceProvider, swaggerLink); if (swaggerApiViewSpec != null) { diff --git a/tools/apiview/parsers/swagger-api-parser/SwaggerApiParser/SwaggerSpec/SchemaCache.cs b/tools/apiview/parsers/swagger-api-parser/SwaggerApiParser/SwaggerSpec/SchemaCache.cs index c8cac72cf87..f93d41619b7 100644 --- a/tools/apiview/parsers/swagger-api-parser/SwaggerApiParser/SwaggerSpec/SchemaCache.cs +++ b/tools/apiview/parsers/swagger-api-parser/SwaggerApiParser/SwaggerSpec/SchemaCache.cs @@ -42,28 +42,6 @@ public void AddParameter(string swaggerFilePath, string key, Parameter parameter parameterCache.TryAdd(key, parameter); } - private static string GetReferencedSwaggerFile(string Ref, string currentSwaggerFilePath) - { - if (string.IsNullOrEmpty(Ref)) - { - return currentSwaggerFilePath; - } - - var idx = Ref.IndexOf("#", StringComparison.Ordinal); - var relativePath = Ref[..idx]; - if (relativePath == "") - { - relativePath = "."; - } - else - { - currentSwaggerFilePath = Path.GetDirectoryName(currentSwaggerFilePath); - } - - var referenceSwaggerFilePath = Path.GetFullPath(relativePath, currentSwaggerFilePath!); - return referenceSwaggerFilePath; - } - public static string GetRefKey(string Ref) { var key = Ref.Split("/").Last(); @@ -79,7 +57,7 @@ public static string RemoveCrossFileReferenceFromRef(string Ref) public static string GetResolvedCacheRefKey(string Ref, string currentSwaggerFilePath) { - return RemoveCrossFileReferenceFromRef(Ref) + GetReferencedSwaggerFile(Ref, currentSwaggerFilePath); + return RemoveCrossFileReferenceFromRef(Ref) + Utils.GetReferencedSwaggerFile(Ref, currentSwaggerFilePath); } private BaseSchema GetSchemaFromResolvedCache(string Ref, string currentSwaggerFilePath) @@ -94,7 +72,7 @@ private BaseSchema GetSchemaFromCache(string Ref, string currentSwaggerFilePath) // try get from resolved cache. - var referenceSwaggerFilePath = GetReferencedSwaggerFile(Ref, currentSwaggerFilePath); + var referenceSwaggerFilePath = Utils.GetReferencedSwaggerFile(Ref, currentSwaggerFilePath); this.Cache.TryGetValue(referenceSwaggerFilePath, out var swaggerSchema); @@ -119,7 +97,7 @@ public Parameter GetParameterFromCache(string Ref, string currentSwaggerFilePath // try get from resolved cache. - var referenceSwaggerFilePath = GetReferencedSwaggerFile(Ref, currentSwaggerFilePath); + var referenceSwaggerFilePath = Utils.GetReferencedSwaggerFile(Ref, currentSwaggerFilePath); this.ParametersCache.TryGetValue(referenceSwaggerFilePath, out var parameterCache); @@ -184,7 +162,7 @@ public BaseSchema GetResolvedSchema(BaseSchema root, string currentSwaggerFilePa // get from original schema cache. refChain.AddLast(GetResolvedCacheRefKey(root.Ref, currentSwaggerFilePath)); var schema = this.GetSchemaFromCache(root.Ref, currentSwaggerFilePath); - var ret = this.GetResolvedSchema(schema, GetReferencedSwaggerFile(root.Ref, currentSwaggerFilePath), refChain); + var ret = this.GetResolvedSchema(schema, Utils.GetReferencedSwaggerFile(root.Ref, currentSwaggerFilePath), refChain); // write back resolved cache this.ResolvedCache.TryAdd(GetResolvedCacheRefKey(root.Ref, currentSwaggerFilePath), schema); refChain.RemoveLast(); diff --git a/tools/apiview/parsers/swagger-api-parser/SwaggerApiParser/SwaggerSpec/SwaggerTypes.cs b/tools/apiview/parsers/swagger-api-parser/SwaggerApiParser/SwaggerSpec/SwaggerTypes.cs index e950973d884..a966f9908bb 100644 --- a/tools/apiview/parsers/swagger-api-parser/SwaggerApiParser/SwaggerSpec/SwaggerTypes.cs +++ b/tools/apiview/parsers/swagger-api-parser/SwaggerApiParser/SwaggerSpec/SwaggerTypes.cs @@ -130,7 +130,7 @@ public string GetTypeFormat() var typeFormat = this.format != null ? $"/{this.format}" : ""; - if (this.type is "array") + if (this.type is "array" && this.items is not null) { var reference = this.items.originalRef ?? this.items.Ref; var arrayType = Utils.GetDefinitionType(reference) ?? this.items.type; @@ -180,11 +180,10 @@ private CodeFileToken[] TokenSerializeInternal(SerializeContext context, BaseSch TokenSerializeProperties(new SerializeContext(context.intent + 2, context.IteratorPath), schema, schema.allOfProperities, ret, ref flattenedTableItems, serializeRef); } - if (schema.type == "array") + if (schema.type == "array" && schema.items is not null) { SchemaTableItem arrayItem = new SchemaTableItem {Description = schema.description}; - var arrayType = schema.items.type != null ? $"array<{schema.items.type}>" : $"array<{Utils.GetDefinitionType(schema.items.originalRef)}>"; - arrayItem.TypeFormat = arrayType; + arrayItem.TypeFormat = schema.items.type != null ? $"array<{schema.items.type}>" : $"array<{Utils.GetDefinitionType(schema.items.originalRef)}>"; flattenedTableItems.Add(arrayItem); TokenSerializeArray(context, ret, schema, ref flattenedTableItems, serializeRef); } diff --git a/tools/apiview/parsers/swagger-api-parser/SwaggerApiParser/Utils.cs b/tools/apiview/parsers/swagger-api-parser/SwaggerApiParser/Utils.cs index 7f445da086c..106c2136b63 100644 --- a/tools/apiview/parsers/swagger-api-parser/SwaggerApiParser/Utils.cs +++ b/tools/apiview/parsers/swagger-api-parser/SwaggerApiParser/Utils.cs @@ -189,4 +189,26 @@ public static string GetRefDefinitionIdPath(string Ref) return ""; } + + public static string GetReferencedSwaggerFile(string Ref, string currentSwaggerFilePath) + { + if (string.IsNullOrEmpty(Ref)) + { + return currentSwaggerFilePath; + } + + var idx = Ref.IndexOf("#", StringComparison.Ordinal); + var relativePath = Ref[..idx]; + if (relativePath == "") + { + relativePath = "."; + } + else + { + currentSwaggerFilePath = Path.GetDirectoryName(currentSwaggerFilePath); + } + + var referenceSwaggerFilePath = Path.GetFullPath(relativePath, currentSwaggerFilePath!); + return referenceSwaggerFilePath; + } } \ No newline at end of file diff --git a/tools/apiview/parsers/swagger-api-parser/SwaggerApiParserTest/SwaggerAPIViewGeneratorTest.cs b/tools/apiview/parsers/swagger-api-parser/SwaggerApiParserTest/SwaggerAPIViewGeneratorTest.cs index 89f67ec191c..2d7d188775f 100644 --- a/tools/apiview/parsers/swagger-api-parser/SwaggerApiParserTest/SwaggerAPIViewGeneratorTest.cs +++ b/tools/apiview/parsers/swagger-api-parser/SwaggerApiParserTest/SwaggerAPIViewGeneratorTest.cs @@ -64,7 +64,7 @@ public async Task TestGenerateSwaggerApiViewGroupedModelProperties() { var runCommandsFilePath = Path.GetFullPath("./fixtures/communicationserviceschat.json"); var swaggerSpec = await SwaggerDeserializer.Deserialize(runCommandsFilePath); - var apiView = SwaggerApiViewGenerator.GenerateSwaggerApiView(swaggerSpec, runCommandsFilePath, new SchemaCache()); + var apiView = await SwaggerApiViewGenerator.GenerateSwaggerApiView(swaggerSpec, runCommandsFilePath, new SchemaCache()); var codeFile = apiView.GenerateCodeFile(); //var outputFilePath = Path.GetFullPath("./communicationserviceschat_output.json"); diff --git a/tools/apiview/parsers/swagger-api-parser/SwaggerApiParserTest/SwaggerAPIViewTest.cs b/tools/apiview/parsers/swagger-api-parser/SwaggerApiParserTest/SwaggerAPIViewTest.cs index 865f4114124..bb77992cd09 100644 --- a/tools/apiview/parsers/swagger-api-parser/SwaggerApiParserTest/SwaggerAPIViewTest.cs +++ b/tools/apiview/parsers/swagger-api-parser/SwaggerApiParserTest/SwaggerAPIViewTest.cs @@ -23,7 +23,7 @@ public async Task TestComputeOneFile() var swaggerSpec = await SwaggerDeserializer.Deserialize(runCommandFilePath); SwaggerApiViewRoot root = new SwaggerApiViewRoot("Microsoft.Compute", "Microsoft.Compute"); - root.AddSwaggerSpec(swaggerSpec, Path.GetFullPath(runCommandFilePath), "Microsoft.Compute"); + await root.AddSwaggerSpec(swaggerSpec, Path.GetFullPath(runCommandFilePath), "Microsoft.Compute"); var codeFile = root.GenerateCodeFile(); var outputFilePath = Path.GetFullPath("./compute_root_one_file_codefile.json"); @@ -40,7 +40,7 @@ public async Task TestMediaComposition() var swaggerSpec = await SwaggerDeserializer.Deserialize(runCommandFilePath); SwaggerApiViewRoot root = new SwaggerApiViewRoot("Microsoft.Media", "Microsoft.Media"); - root.AddSwaggerSpec(swaggerSpec, Path.GetFullPath(runCommandFilePath), "Microsoft.Media"); + await root.AddSwaggerSpec(swaggerSpec, Path.GetFullPath(runCommandFilePath), "Microsoft.Media"); var codeFile = root.GenerateCodeFile(); var outputFilePath = Path.GetFullPath("./media_codefile.json"); @@ -60,8 +60,8 @@ public async Task TestComputeTwoFiles() var computeSwaggerSpec = await SwaggerDeserializer.Deserialize(computeFilePath); SwaggerApiViewRoot root = new SwaggerApiViewRoot("Microsoft.Compute", "Microsoft.Compute"); - root.AddSwaggerSpec(runCommandsSwaggerSpec, Path.GetFullPath(runCommandFilePath), "Microsoft.Compute"); - root.AddSwaggerSpec(computeSwaggerSpec, Path.GetFullPath(computeFilePath), "Microsoft.Compute"); + await root.AddSwaggerSpec(runCommandsSwaggerSpec, Path.GetFullPath(runCommandFilePath), "Microsoft.Compute"); + await root.AddSwaggerSpec(computeSwaggerSpec, Path.GetFullPath(computeFilePath), "Microsoft.Compute"); var codeFile = root.GenerateCodeFile(); @@ -79,7 +79,7 @@ public async Task TestPetStore() var petStoreSwaggerSpec = await SwaggerDeserializer.Deserialize(petStoreFilePath); SwaggerApiViewRoot root = new SwaggerApiViewRoot("Microsoft.PetStore", "Microsoft.PetStore"); - root.AddSwaggerSpec(petStoreSwaggerSpec, Path.GetFullPath(petStoreFilePath), "Microsoft.PetStore"); + await root.AddSwaggerSpec(petStoreSwaggerSpec, Path.GetFullPath(petStoreFilePath), "Microsoft.PetStore"); var codeFile = root.GenerateCodeFile(); var outputFilePath = Path.GetFullPath("./petstore_codefile.json"); @@ -95,7 +95,7 @@ public async Task TestDeviceUpdate() var deviceUpdateSwagger = await SwaggerDeserializer.Deserialize(deviceUpdatePath); SwaggerApiViewRoot root = new SwaggerApiViewRoot("Microsoft.DeviceUpdate", "Microsoft.DeviceUpdate"); - root.AddSwaggerSpec(deviceUpdateSwagger, Path.GetFullPath(deviceUpdatePath), "Microsoft.DeviceUpdate"); + await root.AddSwaggerSpec(deviceUpdateSwagger, Path.GetFullPath(deviceUpdatePath), "Microsoft.DeviceUpdate"); var codeFile = root.GenerateCodeFile(); var outputFilePath = Path.GetFullPath("./deviceupdate_codefile.json"); @@ -111,7 +111,7 @@ public async Task TestService() var serviceSwagger = await SwaggerDeserializer.Deserialize(deviceUpdatePath); SwaggerApiViewRoot root = new SwaggerApiViewRoot("Microsoft.Service", "Microsoft.Service"); - root.AddSwaggerSpec(serviceSwagger, Path.GetFullPath(deviceUpdatePath), "Microsoft.Service"); + await root.AddSwaggerSpec(serviceSwagger, Path.GetFullPath(deviceUpdatePath), "Microsoft.Service"); var codeFile = root.GenerateCodeFile(); var outputFilePath = Path.GetFullPath("./service_codefile.json"); @@ -127,7 +127,7 @@ public async Task TestDeviceUpdateSmall() var deviceUpdateSwagger = await SwaggerDeserializer.Deserialize(deviceUpdatePath); SwaggerApiViewRoot root = new SwaggerApiViewRoot("Microsoft.DeviceUpdate", "Microsoft.DeviceUpdate"); - root.AddSwaggerSpec(deviceUpdateSwagger, Path.GetFullPath(deviceUpdatePath), "Microsoft.DeviceUpdate"); + await root.AddSwaggerSpec(deviceUpdateSwagger, Path.GetFullPath(deviceUpdatePath), "Microsoft.DeviceUpdate"); var codeFile = root.GenerateCodeFile(); var outputFilePath = Path.GetFullPath("./deviceupdatesmall_codefile.json"); @@ -143,7 +143,7 @@ public async Task TestContentModerator() var contentModeratorSwagger = await SwaggerDeserializer.Deserialize(contentModerator); SwaggerApiViewRoot root = new SwaggerApiViewRoot("Microsoft.ContentModerator", "Microsoft.ContentModerator"); - root.AddSwaggerSpec(contentModeratorSwagger, Path.GetFullPath(contentModerator), "Microsoft.ContentModerator"); + await root.AddSwaggerSpec(contentModeratorSwagger, Path.GetFullPath(contentModerator), "Microsoft.ContentModerator"); var codeFile = root.GenerateCodeFile(); var outputFilePath = Path.GetFullPath("./contentModerator_codefile.json"); @@ -159,7 +159,7 @@ public async Task TestAzureOpenai() var openaiSwagger = await SwaggerDeserializer.Deserialize(openai); SwaggerApiViewRoot root = new SwaggerApiViewRoot("Microsoft.OpenAI", "Microsoft.OpenAI"); - root.AddSwaggerSpec(openaiSwagger, Path.GetFullPath(openai), "Microsoft.OpenAI"); + await root.AddSwaggerSpec(openaiSwagger, Path.GetFullPath(openai), "Microsoft.OpenAI"); var codeFile = root.GenerateCodeFile(); var outputFilePath = Path.GetFullPath("./openai_codefile.json"); @@ -175,7 +175,7 @@ public async Task TestPersonalize() var personalizeSwagger = await SwaggerDeserializer.Deserialize(personal); SwaggerApiViewRoot root = new SwaggerApiViewRoot("Microsoft.Personalize", "Microsoft.Personalize"); - root.AddSwaggerSpec(personalizeSwagger, Path.GetFullPath(personal), "Microsoft.Personalize"); + await root.AddSwaggerSpec(personalizeSwagger, Path.GetFullPath(personal), "Microsoft.Personalize"); var codeFile = root.GenerateCodeFile(); var outputFilePath = Path.GetFullPath("./personal_codefile.json"); @@ -191,7 +191,7 @@ public async Task TestMultivariate() var multiVariateSwagger = await SwaggerDeserializer.Deserialize(multiVariateSwaggerFile); SwaggerApiViewRoot root = new SwaggerApiViewRoot("Microsoft.CognitiveService", "Microsoft.CognitiveService"); - root.AddSwaggerSpec(multiVariateSwagger, Path.GetFullPath(multiVariateSwaggerFile), "Microsoft.CognitiveService"); + await root.AddSwaggerSpec(multiVariateSwagger, Path.GetFullPath(multiVariateSwaggerFile), "Microsoft.CognitiveService"); var codeFile = root.GenerateCodeFile(); var outputFilePath = Path.GetFullPath("./multivariate_codefile.json"); @@ -207,7 +207,7 @@ public async Task TestCommunicate() var multiVariateSwagger = await SwaggerDeserializer.Deserialize(multiVariateSwaggerFile); SwaggerApiViewRoot root = new SwaggerApiViewRoot("Microsoft.Communicate", "Microsoft.Communicate"); - root.AddSwaggerSpec(multiVariateSwagger, Path.GetFullPath(multiVariateSwaggerFile), "Microsoft.Communicate"); + await root.AddSwaggerSpec(multiVariateSwagger, Path.GetFullPath(multiVariateSwaggerFile), "Microsoft.Communicate"); var codeFile = root.GenerateCodeFile(); var outputFilePath = Path.GetFullPath("./communicate_codefile.json"); @@ -223,7 +223,7 @@ public async Task TestDevCenterEnvironment() var devCenter = await SwaggerDeserializer.Deserialize(devCenterSwaggerFile); SwaggerApiViewRoot root = new SwaggerApiViewRoot("Microsoft.DevCenter", "Microsoft.DevCenter"); - root.AddSwaggerSpec(devCenter, Path.GetFullPath(devCenterSwaggerFile), "Microsoft.DevCenter"); + await root.AddSwaggerSpec(devCenter, Path.GetFullPath(devCenterSwaggerFile), "Microsoft.DevCenter"); var codeFile = root.GenerateCodeFile(); var outputFilePath = Path.GetFullPath("./devCenter_codefile.json"); @@ -243,8 +243,8 @@ public async Task TestSignalRCrossFileReferenceCommonTypes() var commonTypeSwagger = await SwaggerDeserializer.Deserialize(commonTypeFilePath); SwaggerApiViewRoot root = new SwaggerApiViewRoot("Microsoft.SignalR", "Microsoft.SignalR"); - root.AddSwaggerSpec(commonTypeSwagger, Path.GetFullPath(commonTypeFilePath), "Microsoft.SignalR"); - root.AddSwaggerSpec(signalRSwagger, Path.GetFullPath(signalRFilePath), "Microsoft.SignalR"); + await root.AddSwaggerSpec(commonTypeSwagger, Path.GetFullPath(commonTypeFilePath), "Microsoft.SignalR"); + await root.AddSwaggerSpec(signalRSwagger, Path.GetFullPath(signalRFilePath), "Microsoft.SignalR"); var codeFile = root.GenerateCodeFile(); @@ -267,8 +267,8 @@ public async Task TestCommunicationEmailWithHeaderParameters() SwaggerApiViewRoot root = new SwaggerApiViewRoot("Microsoft.Communication", "Microsoft.Communication"); root.AddDefinitionToCache(commonSpec, commonTypeFilePath); - root.AddSwaggerSpec(commonSpec, commonTypeFilePath); - root.AddSwaggerSpec(swaggerSpec, Path.GetFullPath(swaggerFilePath), "Microsoft.Communication"); + await root.AddSwaggerSpec(commonSpec, commonTypeFilePath); + await root.AddSwaggerSpec(swaggerSpec, Path.GetFullPath(swaggerFilePath), "Microsoft.Communication"); var codeFile = root.GenerateCodeFile(); var outputFilePath = Path.GetFullPath("./communication_codefile.json"); diff --git a/tools/apiview/parsers/swagger-api-parser/SwaggerApiParserTest/fixtures/devcenter.json b/tools/apiview/parsers/swagger-api-parser/SwaggerApiParserTest/fixtures/devcenter.json new file mode 100644 index 00000000000..8c4401eac01 --- /dev/null +++ b/tools/apiview/parsers/swagger-api-parser/SwaggerApiParserTest/fixtures/devcenter.json @@ -0,0 +1,330 @@ +{ + "swagger": "2.0", + "info": { + "version": "2022-03-01-preview", + "title": "DevCenter" + }, + "x-ms-parameterized-host": { + "hostTemplate": "{tenantId}-{devCenter}.{devCenterDnsSuffix}", + "parameters": [ + { + "$ref": "devcenter.json#/parameters/TenantIdParameterName" + }, + { + "$ref": "devcenter.json#/parameters/DevCenterParameterName" + }, + { + "$ref": "devcenter.json#/parameters/DevCenterDnsSuffixParameterName" + } + ] + }, + "schemes": [ + "https" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "security": [ + { + "AADToken": [ + "user_impersonation" + ] + } + ], + "securityDefinitions": { + "AADToken": { + "type": "oauth2", + "authorizationUrl": "https://login.microsoftonline.com/common/oauth2/authorize", + "flow": "implicit", + "description": "Azure Active Directory OAuth2 Flow", + "scopes": { + "user_impersonation": "impersonate your user account" + } + } + }, + "paths": { + "/projects": { + "get": { + "tags": [ + "Projects" + ], + "description": "Lists all projects.", + "parameters": [ + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/FilterParameter" + }, + { + "$ref": "#/parameters/TopParameter" + } + ], + "operationId": "DevCenter_ListProjects", + "responses": { + "200": { + "description": "OK. The request has succeeded.", + "schema": { + "$ref": "#/definitions/ProjectListResult" + } + }, + "default": { + "description": "Error response describing why the operation failed.", + "schema": { + "$ref": "#/definitions/CloudError" + } + } + }, + "x-ms-examples": { + "DevCenter_ListProjects": { + "$ref": "./examples/Projects_ListByDevCenter.json" + } + }, + "x-ms-pageable": { + "nextLinkName": "nextLink" + } + } + }, + "/projects/{projectName}": { + "get": { + "tags": [ + "Projects" + ], + "description": "Gets a project.", + "parameters": [ + { + "$ref": "#/parameters/ProjectNameMethodParameter" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + } + ], + "operationId": "DevCenter_GetProject", + "responses": { + "200": { + "description": "OK. The request has succeeded.", + "schema": { + "$ref": "#/definitions/Project" + } + }, + "default": { + "description": "Error response describing why the operation failed.", + "schema": { + "$ref": "#/definitions/CloudError" + } + } + }, + "x-ms-examples": { + "DevCenter_GetProject": { + "$ref": "./examples/Projects_Get.json" + } + } + } + } + }, + "definitions": { + "ProjectListResult": { + "description": "Results of the project list operation.", + "type": "object", + "properties": { + "value": { + "description": "Current page of results.", + "type": "array", + "items": { + "$ref": "#/definitions/Project" + } + }, + "nextLink": { + "description": "URL to get the next set of results if there are any.", + "type": "string" + } + }, + "required": [ + "value" + ] + }, + "Project": { + "description": "Project details.", + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Name of the project", + "readOnly": true + }, + "description": { + "type": "string", + "description": "Description of the project.", + "readOnly": true + } + } + }, + "CloudError": { + "x-ms-external": true, + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "description": "Error body", + "$ref": "#/definitions/CloudErrorBody" + } + }, + "description": "An error response from the service." + }, + "CloudErrorBody": { + "x-ms-external": true, + "description": "An error response from the service.", + "type": "object", + "required": [ + "code", + "message" + ], + "properties": { + "code": { + "type": "string", + "description": "An identifier for the error. Codes are invariant and are intended to be consumed programmatically." + }, + "message": { + "type": "string", + "description": "A message describing the error, intended to be suitable for display in a user interface." + }, + "target": { + "type": "string", + "description": "The target of the particular error. For example, the name of the property in error." + }, + "details": { + "type": "array", + "items": { + "$ref": "#/definitions/CloudErrorBody" + }, + "description": "A list of additional details about the error." + } + } + }, + "ProvisioningError": { + "description": "Error details", + "type": "object", + "properties": { + "code": { + "type": "string", + "description": "The error code." + }, + "message": { + "type": "string", + "description": "The error message." + } + } + }, + "EnableStatus": { + "description": "Enable or disable status. Indicates whether the property applied to is either enabled or disabled.", + "enum": [ + "Enabled", + "Disabled" + ], + "type": "string", + "x-ms-enum": { + "name": "EnableStatus", + "modelAsString": true + } + } + }, + "parameters": { + "ProjectNameParameter": { + "name": "projectName", + "description": "The DevCenter Project upon which to execute operations.", + "required": true, + "type": "string", + "pattern": "^[a-zA-Z0-9][a-zA-Z0-9-]{2,62}$", + "minLength": 3, + "maxLength": 63, + "in": "path", + "x-ms-parameter-location": "client" + }, + "ProjectNameMethodParameter": { + "name": "projectName", + "description": "The DevCenter Project upon which to execute operations.", + "required": true, + "type": "string", + "pattern": "^[a-zA-Z0-9][a-zA-Z0-9-]{2,62}$", + "minLength": 3, + "maxLength": 63, + "in": "path", + "x-ms-parameter-location": "method" + }, + "ApiVersionParameter": { + "name": "api-version", + "in": "query", + "required": true, + "type": "string", + "description": "The API version to be used with the HTTP request." + }, + "FilterParameter": { + "name": "filter", + "in": "query", + "description": "An OData filter clause to apply to the operation.", + "type": "string", + "required": false, + "x-ms-parameter-location": "method" + }, + "TopParameter": { + "name": "top", + "in": "query", + "description": "The maximum number of resources to return from the operation. Example: 'top=10'.", + "type": "integer", + "format": "int32", + "required": false, + "x-ms-parameter-location": "method" + }, + "UserIdParameterName": { + "name": "userId", + "in": "path", + "required": true, + "x-ms-client-default": "me", + "type": "string", + "pattern": "^[a-zA-Z0-9]{8}-([a-zA-Z0-9]{4}-){3}[a-zA-Z0-9]{12}$|^me$", + "minLength": 2, + "maxLength": 36, + "description": "The AAD object id of the user. If value is 'me', the identity is taken from the authentication context", + "x-ms-parameter-location": "method" + }, + "TenantIdParameterName": { + "name": "tenantId", + "description": "The tenant to operate on.", + "required": true, + "type": "string", + "pattern": "^[a-zA-Z0-9]{8}-([a-zA-Z0-9]{4}-){3}[a-zA-Z0-9]{12}$", + "minLength": 36, + "maxLength": 36, + "in": "path", + "x-ms-skip-url-encoding": true, + "x-ms-parameter-location": "client" + }, + "DevCenterParameterName": { + "name": "devCenter", + "description": "The DevCenter to operate on.", + "required": true, + "type": "string", + "pattern": "^[a-zA-Z0-9][a-zA-Z0-9-]{2,62}$", + "minLength": 3, + "maxLength": 63, + "in": "path", + "x-ms-skip-url-encoding": true, + "x-ms-parameter-location": "client" + }, + "DevCenterDnsSuffixParameterName": { + "name": "devCenterDnsSuffix", + "in": "path", + "required": true, + "type": "string", + "default": "devcenter.azure.com", + "x-ms-skip-url-encoding": true, + "description": "The DNS suffix used as the base for all devcenter requests.", + "x-ms-parameter-location": "client" + } + } +}