From 73b70f8f1b12250ba4d60796bdf1f725fee9cef3 Mon Sep 17 00:00:00 2001 From: jehuan Date: Wed, 22 Jun 2016 13:19:02 +0800 Subject: [PATCH 1/3] support applicable for all the operations under --- .../Swagger/OperationObject.cs | 7 - .../Swagger/PathItemObject.cs | 11 +- .../Swagger/PathsObject.cs | 7 - .../ViewModels/RestApiRootItemViewModel.cs | 143 ++++-- ...osoft.DocAsCode.Build.RestApi.Tests.csproj | 3 + .../RestApiDocumentProcessorTest.cs | 29 +- .../SwaggerJsonParserTest.cs | 37 +- .../TestData/contacts_swagger2.json | 434 +++++++++--------- .../swagger/pathParameters_swagger2.json | 70 +++ 9 files changed, 474 insertions(+), 267 deletions(-) create mode 100644 test/Microsoft.DocAsCode.Build.RestApi.Tests/TestData/swagger/pathParameters_swagger2.json diff --git a/src/Microsoft.DocAsCode.Build.RestApi/Swagger/OperationObject.cs b/src/Microsoft.DocAsCode.Build.RestApi/Swagger/OperationObject.cs index 9bb6c619188..7f0335e3185 100644 --- a/src/Microsoft.DocAsCode.Build.RestApi/Swagger/OperationObject.cs +++ b/src/Microsoft.DocAsCode.Build.RestApi/Swagger/OperationObject.cs @@ -14,13 +14,6 @@ namespace Microsoft.DocAsCode.Build.RestApi.Swagger [Serializable] public class OperationObject { - /// - /// Docfx Added: Operation name, e.g. get, put, post, delete, options, head, patch - /// - [YamlMember(Alias = "name")] - [JsonProperty("name")] - public string OperationName { get; set; } - /// /// Unique string used to identify the operation. The id MUST be unique among all operations described in the API. Tools and libraries MAY use the operationId to uniquely identify an operation, therefore, it is recommended to follow common programming naming conventions. /// diff --git a/src/Microsoft.DocAsCode.Build.RestApi/Swagger/PathItemObject.cs b/src/Microsoft.DocAsCode.Build.RestApi/Swagger/PathItemObject.cs index 2294f7149b0..0454fb2b1fa 100644 --- a/src/Microsoft.DocAsCode.Build.RestApi/Swagger/PathItemObject.cs +++ b/src/Microsoft.DocAsCode.Build.RestApi/Swagger/PathItemObject.cs @@ -7,6 +7,7 @@ namespace Microsoft.DocAsCode.Build.RestApi.Swagger using System.Collections.Generic; using Newtonsoft.Json; + using YamlDotNet.Serialization; using Microsoft.DocAsCode.YamlSerialization; @@ -14,8 +15,16 @@ namespace Microsoft.DocAsCode.Build.RestApi.Swagger /// TODO: need a converter /// [Serializable] - public class PathItemObject : Dictionary + public class PathItemObject { + /// + /// A list of parameters that are applicable for all the operations described under this path. + /// These parameters can be overridden at the operation level, but cannot be removed there. + /// + [YamlMember(Alias = "parameters")] + [JsonProperty("parameters")] + public List Parameters { get; set; } + [ExtensibleMember] [JsonExtensionData] public Dictionary Metadata { get; set; } = new Dictionary(); diff --git a/src/Microsoft.DocAsCode.Build.RestApi/Swagger/PathsObject.cs b/src/Microsoft.DocAsCode.Build.RestApi/Swagger/PathsObject.cs index 1324b32a80a..9f04e5a36b6 100644 --- a/src/Microsoft.DocAsCode.Build.RestApi/Swagger/PathsObject.cs +++ b/src/Microsoft.DocAsCode.Build.RestApi/Swagger/PathsObject.cs @@ -6,15 +6,8 @@ namespace Microsoft.DocAsCode.Build.RestApi.Swagger using System; using System.Collections.Generic; - using Newtonsoft.Json; - - using Microsoft.DocAsCode.YamlSerialization; - [Serializable] public class PathsObject : Dictionary { - [ExtensibleMember] - [JsonExtensionData] - public Dictionary Metadata { get; set; } = new Dictionary(); } } diff --git a/src/Microsoft.DocAsCode.Build.RestApi/ViewModels/RestApiRootItemViewModel.cs b/src/Microsoft.DocAsCode.Build.RestApi/ViewModels/RestApiRootItemViewModel.cs index aa9fdaca176..b80807db6ab 100644 --- a/src/Microsoft.DocAsCode.Build.RestApi/ViewModels/RestApiRootItemViewModel.cs +++ b/src/Microsoft.DocAsCode.Build.RestApi/ViewModels/RestApiRootItemViewModel.cs @@ -9,17 +9,19 @@ namespace Microsoft.DocAsCode.Build.RestApi.ViewModels using System.Text.RegularExpressions; using Newtonsoft.Json; + using Newtonsoft.Json.Linq; using YamlDotNet.Serialization; + using Microsoft.DocAsCode.Build.RestApi.Swagger; using Microsoft.DocAsCode.Common; using Microsoft.DocAsCode.DataContracts.Common; using Microsoft.DocAsCode.Utility.EntityMergers; - using Microsoft.DocAsCode.YamlSerialization; [Serializable] public class RestApiRootItemViewModel : RestApiItemViewModelBase { private const string TagText = "tag"; + private static readonly string[] OperationNames = { "get", "put", "post", "delete", "options", "head", "patch" }; /// /// The original swagger.json cpntent @@ -38,7 +40,7 @@ public class RestApiRootItemViewModel : RestApiItemViewModelBase [JsonProperty("children")] public List Children { get; set; } - public static RestApiRootItemViewModel FromSwaggerModel(Swagger.SwaggerModel swagger) + public static RestApiRootItemViewModel FromSwaggerModel(SwaggerModel swagger) { var uid = GetUid(swagger); var vm = new RestApiRootItemViewModel @@ -67,43 +69,60 @@ public static RestApiRootItemViewModel FromSwaggerModel(Swagger.SwaggerModel swa }); } } - foreach (var path in swagger.Paths) + if (swagger.Paths != null) { - foreach (var op in path.Value) + foreach (var path in swagger.Paths) { - var itemUid = GetUidForOperation(uid, op.Value); - var itemVm = new RestApiChildItemViewModel + var commonParameters = path.Value.Parameters; + foreach (var op in path.Value.Metadata) { - Path = path.Key, - OperationName = op.Key, - OperationId = op.Value.OperationId, - HtmlId = GetHtmlId(itemUid), - Uid = itemUid, - Metadata = op.Value.Metadata, - Description = op.Value.Description, - Summary = op.Value.Summary, - Parameters = op.Value.Parameters?.Select(s => new RestApiParameterViewModel + // fetch operations from metadata + if (OperationNames.Contains(op.Key, StringComparer.OrdinalIgnoreCase)) { - Description = s.Description, - Metadata = s.Metadata - }).ToList(), - Responses = op.Value.Responses?.Select(s => new RestApiResponseViewModel - { - Metadata = s.Value.Metadata, - Description = s.Value.Description, - Summary = s.Value.Summary, - HttpStatusCode = s.Key, - Examples = s.Value.Examples?.Select(example => new RestApiResponseExampleViewModel + var opJObject = op.Value as JObject; + if (opJObject == null) + { + throw new InvalidOperationException($"Value of {op.Key} should be JObject"); + } + + // convert operation from JObject to OperationObject + var operation = opJObject.ToObject(); + var parameters = GetParametersForOperation(operation.Parameters, commonParameters); + var itemUid = GetUidForOperation(uid, operation); + var itemVm = new RestApiChildItemViewModel { - MimeType = example.Key, - Content = example.Value != null ? JsonUtility.Serialize(example.Value) : null, - }).ToList(), - }).ToList(), - }; - - // TODO: line number - itemVm.Metadata[Constants.PropertyName.Source] = swagger.Metadata[Constants.PropertyName.Source]; - vm.Children.Add(itemVm); + Path = path.Key, + OperationName = op.Key, + OperationId = operation.OperationId, + HtmlId = GetHtmlId(itemUid), + Uid = itemUid, + Metadata = operation.Metadata, + Description = operation.Description, + Summary = operation.Summary, + Parameters = parameters?.Select(s => new RestApiParameterViewModel + { + Description = s.Description, + Metadata = s.Metadata + }).ToList(), + Responses = operation.Responses?.Select(s => new RestApiResponseViewModel + { + Metadata = s.Value.Metadata, + Description = s.Value.Description, + Summary = s.Value.Summary, + HttpStatusCode = s.Key, + Examples = s.Value.Examples?.Select(example => new RestApiResponseExampleViewModel + { + MimeType = example.Key, + Content = example.Value != null ? JsonUtility.Serialize(example.Value) : null, + }).ToList(), + }).ToList(), + }; + + // TODO: line number + itemVm.Metadata[Constants.PropertyName.Source] = swagger.Metadata[Constants.PropertyName.Source]; + vm.Children.Add(itemVm); + } + } } } @@ -125,17 +144,17 @@ private static string GetHtmlId(string id) return HtmlEncodeRegex.Replace(id, "_"); } - private static string GetUid(Swagger.SwaggerModel swagger) + private static string GetUid(SwaggerModel swagger) { return GenerateUid(swagger.Host, swagger.BasePath, swagger.Info.Title, swagger.Info.Version); } - private static string GetUidForOperation(string parentUid, Swagger.OperationObject item) + private static string GetUidForOperation(string parentUid, OperationObject item) { return GenerateUid(parentUid, item.OperationId); } - private static string GetUidForTag(string parentUid, Swagger.TagItemObject tag) + private static string GetUidForTag(string parentUid, TagItemObject tag) { return GenerateUid(parentUid, TagText, tag.Name); } @@ -150,6 +169,56 @@ private static string GenerateUid(params string[] segments) return string.Join("/", segments.Where(s => !string.IsNullOrEmpty(s)).Select(s => s.Trim('/'))); } + /// + /// Merge operation's parameters with path's parameters. + /// + /// Operation's parameters + /// Path's parameters + /// + private static IEnumerable GetParametersForOperation(List operationParameters, List pathParameters) + { + if (pathParameters == null || pathParameters.Count == 0) + { + return operationParameters; + } + if (operationParameters == null || operationParameters.Count == 0) + { + return pathParameters; + } + + // Path parameters can be overridden at the operation level. + var uniquePathParams = pathParameters.Where( + p => operationParameters.Any(o => IsParameterEquals(p, o)) != true).ToList(); + + return operationParameters.Union(uniquePathParams).ToList(); + } + + /// + /// Judge whether two ParameterObject equal to each other. according to value of 'name' and 'in' + /// Define 'Equals' here instead of inside ParameterObject, since ParameterObject is either self defined or referenced object which 'name' and 'in' needs to be resolved. + /// + /// Fist ParameterObject + /// Second ParameterObject + private static bool IsParameterEquals(ParameterObject left, ParameterObject right) + { + if (left == null || right == null) + { + return false; + } + return string.Equals(GetMetadataStringValue(left, "name"), GetMetadataStringValue(right, "name")) && + string.Equals(GetMetadataStringValue(left, "in"), GetMetadataStringValue(right, "in")); + } + + private static string GetMetadataStringValue(ParameterObject parameter, string metadataName) + { + object metadataValue; + if (parameter.Metadata.TryGetValue(metadataName, out metadataValue)) + { + return (string)metadataValue; + } + return null; + } + #endregion } } diff --git a/test/Microsoft.DocAsCode.Build.RestApi.Tests/Microsoft.DocAsCode.Build.RestApi.Tests.csproj b/test/Microsoft.DocAsCode.Build.RestApi.Tests/Microsoft.DocAsCode.Build.RestApi.Tests.csproj index bd92aad243b..f7036f84447 100644 --- a/test/Microsoft.DocAsCode.Build.RestApi.Tests/Microsoft.DocAsCode.Build.RestApi.Tests.csproj +++ b/test/Microsoft.DocAsCode.Build.RestApi.Tests/Microsoft.DocAsCode.Build.RestApi.Tests.csproj @@ -112,6 +112,9 @@ Always + + Always + Always diff --git a/test/Microsoft.DocAsCode.Build.RestApi.Tests/RestApiDocumentProcessorTest.cs b/test/Microsoft.DocAsCode.Build.RestApi.Tests/RestApiDocumentProcessorTest.cs index 8e26a07312b..9e228516263 100644 --- a/test/Microsoft.DocAsCode.Build.RestApi.Tests/RestApiDocumentProcessorTest.cs +++ b/test/Microsoft.DocAsCode.Build.RestApi.Tests/RestApiDocumentProcessorTest.cs @@ -53,7 +53,7 @@ public void ProcessSwaggerShouldSucceed() var model = JsonUtility.Deserialize(outputRawModelPath); Assert.Equal("graph.windows.net/myorganization/Contacts/1.0", model.Uid); Assert.Equal("graph_windows_net_myorganization_Contacts_1_0", model.HtmlId); - Assert.Equal(9, model.Children.Count); + Assert.Equal(10, model.Children.Count); Assert.Equal("Hello world!", model.Metadata["meta"]); var item1 = model.Children[0]; Assert.Equal("graph.windows.net/myorganization/Contacts/1.0/get contacts", item1.Uid); @@ -86,6 +86,33 @@ public void ProcessSwaggerShouldSucceed() Assert.Equal("http://swagger.io", externalDocs["url"]); var tag2 = model.Tags[1]; Assert.Equal("pet_store", tag2.HtmlId); + + // Verify path parameters + // Path parameter applicable for get operation + Assert.Equal(2, item2.Parameters.Count); + Assert.Equal("object_id", item2.Parameters[0].Metadata["name"]); + Assert.Equal("api-version", item2.Parameters[1].Metadata["name"]); + Assert.Equal(true, item2.Parameters[1].Metadata["required"]); + + // Override ""api-version" parameters by $ref for patch opearation + var item3 = model.Children[2]; + Assert.Equal(3, item3.Parameters.Count); + Assert.Equal("object_id", item3.Parameters[0].Metadata["name"]); + Assert.Equal("api-version", item3.Parameters[1].Metadata["name"]); + Assert.Equal(false, item3.Parameters[1].Metadata["required"]); + + // Override ""api-version" parameters by self definition for delete opearation + var item4 = model.Children[3]; + Assert.Equal(2, item4.Parameters.Count); + Assert.Equal("object_id", item4.Parameters[0].Metadata["name"]); + Assert.Equal("api-version", item4.Parameters[1].Metadata["name"]); + Assert.Equal(false, item4.Parameters[1].Metadata["required"]); + + // When operation parameters is not set, inherit from th parameters for post opearation + var item5 = model.Children[4]; + Assert.Equal(1, item5.Parameters.Count); + Assert.Equal("api-version", item5.Parameters[0].Metadata["name"]); + Assert.Equal(true, item5.Parameters[0].Metadata["required"]); } [Fact] diff --git a/test/Microsoft.DocAsCode.Build.RestApi.Tests/SwaggerJsonParserTest.cs b/test/Microsoft.DocAsCode.Build.RestApi.Tests/SwaggerJsonParserTest.cs index 6937fe70bc5..960c63ef1db 100644 --- a/test/Microsoft.DocAsCode.Build.RestApi.Tests/SwaggerJsonParserTest.cs +++ b/test/Microsoft.DocAsCode.Build.RestApi.Tests/SwaggerJsonParserTest.cs @@ -20,9 +20,10 @@ public void ParseSimpleSwaggerJsonShouldSucceed() var swaggerFile = @"TestData\swagger\simple_swagger2.json"; var swagger = SwaggerJsonParser.Parse(File.ReadAllText(swaggerFile)); - Assert.Equal(1, swagger.Paths.Count); - Assert.Equal(1, swagger.Paths["/contacts"].Count); - var action = swagger.Paths["/contacts"]["get"]; + Assert.Equal(1, swagger.Paths.Values.Count); + var actionJObject = swagger.Paths["/contacts"].Metadata["get"] as JObject; + Assert.NotNull(actionJObject); + var action = actionJObject.ToObject(); var parameters = action.Parameters; Assert.Equal(1, parameters.Count); Assert.Equal("query", parameters[0].Metadata["in"]); @@ -40,11 +41,11 @@ public void ParseSwaggerJsonWithReferenceShouldSucceed() var swagger = SwaggerJsonParser.Parse(File.ReadAllText(swaggerFile)); Assert.Equal(1, swagger.Paths.Count); - Assert.Equal(1, swagger.Paths["/contacts"].Count); - var action = swagger.Paths["/contacts"]["patch"]; + Assert.Equal(1, swagger.Paths["/contacts"].Metadata.Count); + var actionJObject = swagger.Paths["/contacts"].Metadata["patch"] as JObject; + Assert.NotNull(actionJObject); + var action = actionJObject.ToObject(); var parameters = action.Parameters; - Assert.Equal(2, parameters.Count); - Assert.Equal("body", parameters[0].Metadata["in"]); var schema = parameters[0].Metadata["schema"] as JObject; Assert.NotNull(schema); Assert.Equal("Sales", schema["example"]["department"].ToString()); @@ -89,6 +90,28 @@ public void ParseSwaggerJsonWithTagShouldSucceed() Assert.Equal("http://swagger.io", externalDocs["url"]); } + + [Fact] + public void ParseSwaggerJsonWithPathParametersShouldSucceed() + { + const string swaggerFile = @"TestData\swagger\pathParameters_swagger2.json"; + var swagger = SwaggerJsonParser.Parse(File.ReadAllText(swaggerFile)); + + Assert.Equal(1, swagger.Paths.Values.Count); + var parameters = swagger.Paths["/contacts"].Parameters; + Assert.Equal(2, parameters.Count); + + // $ref parameter + Assert.Equal("api-version", parameters[0].Metadata["name"]); + Assert.Equal(false, parameters[0].Metadata["required"]); + Assert.Equal("api version description", parameters[0].Description); + + // self defined parameter + Assert.Equal("subscriptionId", parameters[1].Metadata["name"]); + Assert.Equal(true, parameters[1].Metadata["required"]); + Assert.Equal("subscription id", parameters[1].Description); + } + [Fact] public void ParseSwaggerJsonWithLoopReferenceShouldFail() { diff --git a/test/Microsoft.DocAsCode.Build.RestApi.Tests/TestData/contacts_swagger2.json b/test/Microsoft.DocAsCode.Build.RestApi.Tests/TestData/contacts_swagger2.json index fdf2daddd04..775a83d778d 100644 --- a/test/Microsoft.DocAsCode.Build.RestApi.Tests/TestData/contacts_swagger2.json +++ b/test/Microsoft.DocAsCode.Build.RestApi.Tests/TestData/contacts_swagger2.json @@ -23,199 +23,31 @@ "description": "Operations about user" } ], + "parameters": { + "ApiVersionParameter": { + "in": "query", + "description": "api version description", + "name": "api-version", + "required": false, + "type": "string", + "default": "1.6" + } + }, "paths": { "/contacts": { - "get": { - "tags": [ "contacts" ], - "parameters": [ - { - "in": "query", - "description": "The version of the Graph API to target. Beginning with version 1.5, the api-version string is represented in major.minor format. Prior releases were represented as date strings: '2013-11-08' and '2013-04-05'. Required.", - "name": "api-version", - "required": true, - "type": "string", - "default": "1.6" - } - ], - "responses": { - "200": { - "description": "OK. Indicates success. The results are returned in the response body.", - "examples": { - "application/json": { - "odata.metadata": "https://graph.windows.net/myorganization/$metadata#directoryObjects/Microsoft.DirectoryServices.Contact", - "value": [ - { - "odata.type": "Microsoft.DirectoryServices.Contact", - "objectType": "Contact", - "objectId": "31944231-fd52-4a7f-b32e-7902a01fddf9", - "deletionTimestamp": null, - "city": null, - "companyName": null, - "country": null, - "department": null, - "dirSyncEnabled": null, - "displayName": "Marcus Breyer", - "facsimileTelephoneNumber": null, - "givenName": "Marcus", - "jobTitle": null, - "lastDirSyncTime": null, - "mail": "Marcus@contoso.com", - "mailNickname": "MarcusBreyer", - "mobile": null, - "physicalDeliveryOfficeName": null, - "postalCode": null, - "provisioningErrors": [ - - ], - "proxyAddresses": [ - "SMTP:Marcus@contoso.com" - ], - "sipProxyAddress": null, - "state": null, - "streetAddress": null, - "surname": "Breyer", - "telephoneNumber": null - }, - { - "odata.type": "Microsoft.DirectoryServices.Contact", - "objectType": "Contact", - "objectId": "35110b16-360c-4c4a-93b2-03f065fabd93", - "deletionTimestamp": null, - "city": null, - "companyName": null, - "country": null, - "department": null, - "dirSyncEnabled": null, - "displayName": "Yossi Ran", - "facsimileTelephoneNumber": null, - "givenName": "Yossi", - "jobTitle": null, - "lastDirSyncTime": null, - "mail": "Yossi@contoso.com", - "mailNickname": "YossiRan", - "mobile": null, - "physicalDeliveryOfficeName": null, - "postalCode": null, - "provisioningErrors": [ - - ], - "proxyAddresses": [ - "SMTP:Yossi@contoso.com" - ], - "sipProxyAddress": null, - "state": null, - "streetAddress": null, - "surname": "Ran", - "telephoneNumber": null - }, - { - "odata.type": "Microsoft.DirectoryServices.Contact", - "objectType": "Contact", - "objectId": "7163f3b8-70c9-43d2-b9e1-4467ddaf087a", - "deletionTimestamp": null, - "city": null, - "companyName": null, - "country": null, - "department": null, - "dirSyncEnabled": null, - "displayName": "Jeremy Nelson", - "facsimileTelephoneNumber": null, - "givenName": "Jeremy", - "jobTitle": null, - "lastDirSyncTime": null, - "mail": "Jeremy@contoso.com", - "mailNickname": "JeremyNelson", - "mobile": null, - "physicalDeliveryOfficeName": null, - "postalCode": null, - "provisioningErrors": [ - - ], - "proxyAddresses": [ - "SMTP:Jeremy@contoso.com" - ], - "sipProxyAddress": null, - "state": null, - "streetAddress": null, - "surname": "Nelson", - "telephoneNumber": null - }, - { - "odata.type": "Microsoft.DirectoryServices.Contact", - "objectType": "Contact", - "objectId": "83234b5c-3a10-4108-8f36-39b1addadfdb", - "deletionTimestamp": null, - "city": null, - "companyName": null, - "country": null, - "department": null, - "dirSyncEnabled": null, - "displayName": "David Strome", - "facsimileTelephoneNumber": null, - "givenName": "David", - "jobTitle": null, - "lastDirSyncTime": null, - "mail": "David@contoso.com", - "mailNickname": "DavidStrome", - "mobile": null, - "physicalDeliveryOfficeName": null, - "postalCode": null, - "provisioningErrors": [ - - ], - "proxyAddresses": [ - "SMTP:David@contoso.com" - ], - "sipProxyAddress": null, - "state": null, - "streetAddress": null, - "surname": "Strome", - "telephoneNumber": null - }, - { - "odata.type": "Microsoft.DirectoryServices.Contact", - "objectType": "Contact", - "objectId": "8c1315ce-bf6f-4e26-b24f-c830606ef41c", - "deletionTimestamp": null, - "city": null, - "companyName": null, - "country": null, - "department": null, - "dirSyncEnabled": null, - "displayName": "Holly Holt", - "facsimileTelephoneNumber": null, - "givenName": "Holly", - "jobTitle": null, - "lastDirSyncTime": null, - "mail": "Holly@contoso.com", - "mailNickname": "HollyHolt", - "mobile": null, - "physicalDeliveryOfficeName": null, - "postalCode": null, - "provisioningErrors": [ - - ], - "proxyAddresses": [ - "SMTP:Holly@contoso.com" - ], - "sipProxyAddress": null, - "state": null, - "streetAddress": null, - "surname": "Holt", - "telephoneNumber": null - } - ] - } - } - - } - }, - "description": "

Required scope: Contacts.Read or Contacts.Write

", - "summary": "You can get a collection of contacts from your tenant.", - "operationId": "get contacts" - } + "$ref": "#/definitions/getDefinition" }, "/contacts/{object_id}": { + "parameters": [ + { + "in": "query", + "description": "Specifies the version of the Graph API to target. Beginning with version 1.5, the api-version string is represented in major.minor format. Prior releases were represented as date strings: '2013-11-08' and '2013-04-05'. Required.", + "name": "api-version", + "required": true, + "type": "string", + "default": "1.6" + } + ], "get": { "tags": [ "contacts", "pet store" ], "parameters": [ @@ -226,14 +58,6 @@ "required": true, "type": "string", "default": "31944231-fd52-4a7f-b32e-7902a01fddf9" - }, - { - "in": "query", - "description": "Specifies the version of the Graph API to target. Beginning with version 1.5, the api-version string is represented in major.minor format. Prior releases were represented as date strings: '2013-11-08' and '2013-04-05'. Required.", - "name": "api-version", - "required": true, - "type": "string", - "default": "1.6" } ], "responses": { @@ -289,14 +113,8 @@ "default": "7163f3b8-70c9-43d2-b9e1-4467ddaf087a" }, { - "in": "query", - "description": "The version of the Graph API to target. Beginning with version 1.5, the api-version string is represented in major.minor format. Prior releases were represented as date strings: '2013-11-08' and '2013-04-05'. Required.", - "name": "api-version", - "required": true, - "type": "string", - "default": "1.6" + "$ref": "#/parameters/ApiVersionParameter" }, - { "in": "body", "description": "this is request body, not real parameter", @@ -342,7 +160,6 @@ "type": "string", "default": "1.6" } - ], "responses": { "204": { @@ -355,6 +172,21 @@ "description": "

Required scope: Contacts.Write

", "summary": "Delete a contact.", "operationId": "delete contact" + }, + "post": { + "parameters": [ + ], + "responses": { + "204": { + "description": "No Content. Indicates success.", + "examples": { + "application/json": "none" + } + } + }, + "description": "

Required scope: Contacts.Write

", + "summary": "Post a contact.", + "operationId": "post contact" } }, "/contacts/{object_id}/$links/manager": { @@ -377,7 +209,6 @@ "type": "string", "default": "1.6" } - ], "responses": { "200": { @@ -569,13 +400,202 @@ "operationId": "get contact memberOf links" } } - }, "host": "graph.windows.net", "basePath": "/myorganization", "schemes": [ "https" ], "definitions": { + "getDefinition" : { + "get": { + "tags": [ "contacts" ], + "parameters": [ + { + "in": "query", + "description": "The version of the Graph API to target. Beginning with version 1.5, the api-version string is represented in major.minor format. Prior releases were represented as date strings: '2013-11-08' and '2013-04-05'. Required.", + "name": "api-version", + "required": true, + "type": "string", + "default": "1.6" + } + ], + "responses": { + "200": { + "description": "OK. Indicates success. The results are returned in the response body.", + "examples": { + "application/json": { + "odata.metadata": "https://graph.windows.net/myorganization/$metadata#directoryObjects/Microsoft.DirectoryServices.Contact", + "value": [ + { + "odata.type": "Microsoft.DirectoryServices.Contact", + "objectType": "Contact", + "objectId": "31944231-fd52-4a7f-b32e-7902a01fddf9", + "deletionTimestamp": null, + "city": null, + "companyName": null, + "country": null, + "department": null, + "dirSyncEnabled": null, + "displayName": "Marcus Breyer", + "facsimileTelephoneNumber": null, + "givenName": "Marcus", + "jobTitle": null, + "lastDirSyncTime": null, + "mail": "Marcus@contoso.com", + "mailNickname": "MarcusBreyer", + "mobile": null, + "physicalDeliveryOfficeName": null, + "postalCode": null, + "provisioningErrors": [ + + ], + "proxyAddresses": [ + "SMTP:Marcus@contoso.com" + ], + "sipProxyAddress": null, + "state": null, + "streetAddress": null, + "surname": "Breyer", + "telephoneNumber": null + }, + { + "odata.type": "Microsoft.DirectoryServices.Contact", + "objectType": "Contact", + "objectId": "35110b16-360c-4c4a-93b2-03f065fabd93", + "deletionTimestamp": null, + "city": null, + "companyName": null, + "country": null, + "department": null, + "dirSyncEnabled": null, + "displayName": "Yossi Ran", + "facsimileTelephoneNumber": null, + "givenName": "Yossi", + "jobTitle": null, + "lastDirSyncTime": null, + "mail": "Yossi@contoso.com", + "mailNickname": "YossiRan", + "mobile": null, + "physicalDeliveryOfficeName": null, + "postalCode": null, + "provisioningErrors": [ + + ], + "proxyAddresses": [ + "SMTP:Yossi@contoso.com" + ], + "sipProxyAddress": null, + "state": null, + "streetAddress": null, + "surname": "Ran", + "telephoneNumber": null + }, + { + "odata.type": "Microsoft.DirectoryServices.Contact", + "objectType": "Contact", + "objectId": "7163f3b8-70c9-43d2-b9e1-4467ddaf087a", + "deletionTimestamp": null, + "city": null, + "companyName": null, + "country": null, + "department": null, + "dirSyncEnabled": null, + "displayName": "Jeremy Nelson", + "facsimileTelephoneNumber": null, + "givenName": "Jeremy", + "jobTitle": null, + "lastDirSyncTime": null, + "mail": "Jeremy@contoso.com", + "mailNickname": "JeremyNelson", + "mobile": null, + "physicalDeliveryOfficeName": null, + "postalCode": null, + "provisioningErrors": [ + + ], + "proxyAddresses": [ + "SMTP:Jeremy@contoso.com" + ], + "sipProxyAddress": null, + "state": null, + "streetAddress": null, + "surname": "Nelson", + "telephoneNumber": null + }, + { + "odata.type": "Microsoft.DirectoryServices.Contact", + "objectType": "Contact", + "objectId": "83234b5c-3a10-4108-8f36-39b1addadfdb", + "deletionTimestamp": null, + "city": null, + "companyName": null, + "country": null, + "department": null, + "dirSyncEnabled": null, + "displayName": "David Strome", + "facsimileTelephoneNumber": null, + "givenName": "David", + "jobTitle": null, + "lastDirSyncTime": null, + "mail": "David@contoso.com", + "mailNickname": "DavidStrome", + "mobile": null, + "physicalDeliveryOfficeName": null, + "postalCode": null, + "provisioningErrors": [ + ], + "proxyAddresses": [ + "SMTP:David@contoso.com" + ], + "sipProxyAddress": null, + "state": null, + "streetAddress": null, + "surname": "Strome", + "telephoneNumber": null + }, + { + "odata.type": "Microsoft.DirectoryServices.Contact", + "objectType": "Contact", + "objectId": "8c1315ce-bf6f-4e26-b24f-c830606ef41c", + "deletionTimestamp": null, + "city": null, + "companyName": null, + "country": null, + "department": null, + "dirSyncEnabled": null, + "displayName": "Holly Holt", + "facsimileTelephoneNumber": null, + "givenName": "Holly", + "jobTitle": null, + "lastDirSyncTime": null, + "mail": "Holly@contoso.com", + "mailNickname": "HollyHolt", + "mobile": null, + "physicalDeliveryOfficeName": null, + "postalCode": null, + "provisioningErrors": [ + + ], + "proxyAddresses": [ + "SMTP:Holly@contoso.com" + ], + "sipProxyAddress": null, + "state": null, + "streetAddress": null, + "surname": "Holt", + "telephoneNumber": null + } + ] + } + } + + } + }, + "description": "

Required scope: Contacts.Read or Contacts.Write

", + "summary": "You can get a collection of contacts from your tenant.", + "operationId": "get contacts" + } + }, "contact": { "properties": { "objectType": { diff --git a/test/Microsoft.DocAsCode.Build.RestApi.Tests/TestData/swagger/pathParameters_swagger2.json b/test/Microsoft.DocAsCode.Build.RestApi.Tests/TestData/swagger/pathParameters_swagger2.json new file mode 100644 index 00000000000..fc69984ba68 --- /dev/null +++ b/test/Microsoft.DocAsCode.Build.RestApi.Tests/TestData/swagger/pathParameters_swagger2.json @@ -0,0 +1,70 @@ +{ + "swagger": "2.0", + "info": { + "title": "Contacts", + "version": "1.0" + }, + "host": "graph.windows.net", + "basePath": "/myorganization", + "parameters": { + "ApiVersionParameter": { + "in": "query", + "description": "api version description", + "name": "api-version", + "required": false, + "type": "string", + "default": "1.6" + } + }, + "paths": { + "/contacts": { + "parameters": [ + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "name": "subscriptionId", + "in": "query", + "required": true, + "type": "string", + "description": "subscription id" + } + ], + "get": { + "parameters": [ + { + "in": "query", + "name": "api-version", + "required": true, + "type": "string", + "default": "1.6" + } + ], + "responses": { + "200": { + "description": "" + } + }, + "operationId": "get contacts" + }, + "delete": { + "parameters": [ + { + "in": "query", + "description": "The object ID (GUID) of the target contact.", + "name": "object_id", + "required": true, + "type": "string", + "default": "7163f3b8-70c9-43d2-b9e1-4467ddaf087a" + } + ], + "responses": { + "200": { + "description": "" + } + } + } + } + } +} + From ce0e3b45895352dea4f10fb4c9e47bd5bccdc972 Mon Sep 17 00:00:00 2001 From: jehuan Date: Wed, 22 Jun 2016 16:21:10 +0800 Subject: [PATCH 2/3] Some refinement --- .../ViewModels/RestApiChildItemViewModel.cs | 1 - .../ViewModels/RestApiRootItemViewModel.cs | 2 +- .../RestApiDocumentProcessorTest.cs | 2 ++ 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.DocAsCode.Build.RestApi/ViewModels/RestApiChildItemViewModel.cs b/src/Microsoft.DocAsCode.Build.RestApi/ViewModels/RestApiChildItemViewModel.cs index 9b0a176b7f6..b18573d7f21 100644 --- a/src/Microsoft.DocAsCode.Build.RestApi/ViewModels/RestApiChildItemViewModel.cs +++ b/src/Microsoft.DocAsCode.Build.RestApi/ViewModels/RestApiChildItemViewModel.cs @@ -10,7 +10,6 @@ namespace Microsoft.DocAsCode.Build.RestApi.ViewModels using YamlDotNet.Serialization; using Microsoft.DocAsCode.DataContracts.Common; - using Microsoft.DocAsCode.YamlSerialization; [Serializable] public class RestApiChildItemViewModel : RestApiItemViewModelBase diff --git a/src/Microsoft.DocAsCode.Build.RestApi/ViewModels/RestApiRootItemViewModel.cs b/src/Microsoft.DocAsCode.Build.RestApi/ViewModels/RestApiRootItemViewModel.cs index b80807db6ab..44695eff9c8 100644 --- a/src/Microsoft.DocAsCode.Build.RestApi/ViewModels/RestApiRootItemViewModel.cs +++ b/src/Microsoft.DocAsCode.Build.RestApi/ViewModels/RestApiRootItemViewModel.cs @@ -188,7 +188,7 @@ private static IEnumerable GetParametersForOperation(List operationParameters.Any(o => IsParameterEquals(p, o)) != true).ToList(); + p => operationParameters.Any(o => !IsParameterEquals(p, o))).ToList(); return operationParameters.Union(uniquePathParams).ToList(); } diff --git a/test/Microsoft.DocAsCode.Build.RestApi.Tests/RestApiDocumentProcessorTest.cs b/test/Microsoft.DocAsCode.Build.RestApi.Tests/RestApiDocumentProcessorTest.cs index 9e228516263..ea2b32a9719 100644 --- a/test/Microsoft.DocAsCode.Build.RestApi.Tests/RestApiDocumentProcessorTest.cs +++ b/test/Microsoft.DocAsCode.Build.RestApi.Tests/RestApiDocumentProcessorTest.cs @@ -55,6 +55,8 @@ public void ProcessSwaggerShouldSucceed() Assert.Equal("graph_windows_net_myorganization_Contacts_1_0", model.HtmlId); Assert.Equal(10, model.Children.Count); Assert.Equal("Hello world!", model.Metadata["meta"]); + + // Verify $ref in path var item1 = model.Children[0]; Assert.Equal("graph.windows.net/myorganization/Contacts/1.0/get contacts", item1.Uid); Assert.Equal("

You can get a collection of contacts from your tenant.

\n", item1.Summary); From e8b85daa9a9b6ce2eddb344074485f6c7f49a99c Mon Sep 17 00:00:00 2001 From: jehuan Date: Wed, 22 Jun 2016 16:44:42 +0800 Subject: [PATCH 3/3] Fix bug when compare pamameters --- .../ViewModels/RestApiRootItemViewModel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.DocAsCode.Build.RestApi/ViewModels/RestApiRootItemViewModel.cs b/src/Microsoft.DocAsCode.Build.RestApi/ViewModels/RestApiRootItemViewModel.cs index 44695eff9c8..d3796c76fdd 100644 --- a/src/Microsoft.DocAsCode.Build.RestApi/ViewModels/RestApiRootItemViewModel.cs +++ b/src/Microsoft.DocAsCode.Build.RestApi/ViewModels/RestApiRootItemViewModel.cs @@ -188,7 +188,7 @@ private static IEnumerable GetParametersForOperation(List operationParameters.Any(o => !IsParameterEquals(p, o))).ToList(); + p => !operationParameters.Any(o => IsParameterEquals(p, o))).ToList(); return operationParameters.Union(uniquePathParams).ToList(); }