Skip to content
This repository was archived by the owner on Feb 23, 2024. It is now read-only.

Commit 94033f2

Browse files
Supports alternate API display name (#388)
* - #387 Supports alternate display name for OpenAPI definition. * Added `displayName` property. Co-authored-by: RupengLiu <rliu1211@terpmail.umd.edu>
1 parent cc0e595 commit 94033f2

File tree

6 files changed

+361
-26
lines changed

6 files changed

+361
-26
lines changed

src/APIM_ARMTemplate/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ The utility requires one argument, --configFile, which points to a yaml file tha
4343
| Property | Type | Required | Value |
4444
|-----------------------|-----------------------|-----------------------|--------------------------------------------------|
4545
| name | string | Yes | API identifier. Must be unique in the current API Management service instance. |
46+
| displayName | string | No | User-friendly name for the API. |
4647
| description | string | No | Description of the API. |
4748
| serviceUrl | string | No | Absolute URL of the backend service implementing this API. |
4849
| type | enum | No | Type of API. - http or soap |
@@ -156,6 +157,7 @@ apiVersionSets:
156157
apis:
157158
- name: myAPI
158159
type: http
160+
displayName: My API
159161
description: myFirstAPI
160162
serviceUrl: http://myApiBackendUrl.com
161163
openApiSpec: C:\Users\myUsername\Projects\azure-api-management-devops-example\src\APIM_ARMTemplate\apimtemplate\Creator\ExampleFile\OpenApiSpecs\swaggerPetstore.json

src/APIM_ARMTemplate/apimtemplate.test/Creator/TemplateCreatorTests/APITemplateCreatorTests.cs

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using Microsoft.Azure.Management.ApiManagement.ArmTemplates.Create;
44
using System.Collections.Generic;
55
using System.Linq;
6+
using System.IO;
67

78
namespace Microsoft.Azure.Management.ApiManagement.ArmTemplates.Test
89
{
@@ -91,6 +92,119 @@ public async void ShouldCreateSubsequentlAPITemplateResourceFromCreatorConfigWit
9192
Assert.Equal(api.openApiSpec, apiTemplateResource.properties.value);
9293
}
9394

95+
[Fact]
96+
public async void ShouldCreateSubsequentlAPITemplateResourceFromCreatorConfigWithAlternateTitle()
97+
{
98+
// arrange
99+
APITemplateCreator apiTemplateCreator = APITemplateCreatorFactory.GenerateAPITemplateCreator();
100+
CreatorConfig creatorConfig = new CreatorConfig() { apis = new List<APIConfig>() };
101+
APIConfig api = new APIConfig()
102+
{
103+
name = "name",
104+
displayName = "Swagger Petstore (alternate title)",
105+
openApiSpec = "https://petstore.swagger.io/v2/swagger.json",
106+
};
107+
creatorConfig.apis.Add(api);
108+
109+
// act
110+
APITemplateResource apiTemplateResource = await apiTemplateCreator.CreateAPITemplateResourceAsync(api, true, true);
111+
112+
// assert
113+
Assert.Equal($"[concat(parameters('ApimServiceName'), '/{api.name}')]", apiTemplateResource.name);
114+
Assert.Equal("swagger-json", apiTemplateResource.properties.format);
115+
116+
// check alternate title has been specified in the embedded YAML or JSON definition
117+
118+
var yaml = apiTemplateResource.properties.value;
119+
var deserializer = new YamlDotNet.Serialization.Deserializer();
120+
var definition = deserializer.Deserialize<Dictionary<string, object>>(yaml);
121+
var info = (Dictionary<object, object>) definition["info"];
122+
123+
Assert.Equal("Swagger Petstore (alternate title)", info["title"]);
124+
}
125+
126+
[Fact]
127+
public async void ShouldCreateSubsequentlAPITemplateResourceFromCreatorConfigWithAlternateTitleInSwagger()
128+
{
129+
// arrange
130+
APITemplateCreator apiTemplateCreator = APITemplateCreatorFactory.GenerateAPITemplateCreator();
131+
CreatorConfig creatorConfig = new CreatorConfig() { apis = new List<APIConfig>() };
132+
133+
// extract swagger as a local file
134+
135+
var swaggerPath = Path.GetTempFileName();
136+
using (var stream = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream("apimtemplate.test.Resources.swaggerPetstorev3.json"))
137+
using (var reader = new StreamReader(stream))
138+
File.WriteAllText(swaggerPath, reader.ReadToEnd());
139+
140+
// create API config with local swagger definition
141+
142+
APIConfig api = new APIConfig()
143+
{
144+
name = "name",
145+
displayName = "Swagger Petstore (alternate title)",
146+
openApiSpec = swaggerPath,
147+
};
148+
creatorConfig.apis.Add(api);
149+
150+
// act
151+
APITemplateResource apiTemplateResource = await apiTemplateCreator.CreateAPITemplateResourceAsync(api, true, true);
152+
153+
// assert
154+
Assert.Equal($"[concat(parameters('ApimServiceName'), '/{api.name}')]", apiTemplateResource.name);
155+
Assert.Equal("openapi+json", apiTemplateResource.properties.format);
156+
157+
// check alternate title has been specified in the embedded YAML or JSON definition
158+
159+
var yaml = apiTemplateResource.properties.value;
160+
var deserializer = new YamlDotNet.Serialization.Deserializer();
161+
var definition = deserializer.Deserialize<Dictionary<string, object>>(yaml);
162+
var info = (Dictionary<object, object>) definition["info"];
163+
164+
Assert.Equal("Swagger Petstore (alternate title)", info["title"]);
165+
}
166+
167+
[Fact]
168+
public async void ShouldCreateSubsequentlAPITemplateResourceFromCreatorConfigWithAlternateTitleInOpenApi()
169+
{
170+
// arrange
171+
APITemplateCreator apiTemplateCreator = APITemplateCreatorFactory.GenerateAPITemplateCreator();
172+
CreatorConfig creatorConfig = new CreatorConfig() { apis = new List<APIConfig>() };
173+
174+
// extract swagger as a local file
175+
176+
var openapiPath = Path.GetTempFileName();
177+
using (var stream = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream("apimtemplate.test.Resources.swaggerPetstore.yml"))
178+
using (var reader = new StreamReader(stream))
179+
File.WriteAllText(openapiPath, reader.ReadToEnd());
180+
181+
// create API config with local swagger definition
182+
183+
APIConfig api = new APIConfig()
184+
{
185+
name = "name",
186+
displayName = "Swagger Petstore (alternate title)",
187+
openApiSpec = openapiPath,
188+
};
189+
creatorConfig.apis.Add(api);
190+
191+
// act
192+
APITemplateResource apiTemplateResource = await apiTemplateCreator.CreateAPITemplateResourceAsync(api, true, true);
193+
194+
// assert
195+
Assert.Equal($"[concat(parameters('ApimServiceName'), '/{api.name}')]", apiTemplateResource.name);
196+
Assert.Equal("openapi", apiTemplateResource.properties.format);
197+
198+
// check alternate title has been specified in the embedded YAML or JSON definition
199+
200+
var yaml = apiTemplateResource.properties.value;
201+
var deserializer = new YamlDotNet.Serialization.Deserializer();
202+
var definition = deserializer.Deserialize<Dictionary<string, object>>(yaml);
203+
var info = (Dictionary<object, object>) definition["info"];
204+
205+
Assert.Equal("Swagger Petstore (alternate title)", info["title"]);
206+
}
207+
94208
[Fact]
95209
public async void ShouldCreateUnifiedAPITemplateResourceFromCreatorConfig()
96210
{

src/APIM_ARMTemplate/apimtemplate.test/apimtemplate.test.csproj

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,13 @@
88
<ProjectGuid>{7D0C17F8-C0F5-4678-A75F-EB1BE94E3A46}</ProjectGuid>
99
</PropertyGroup>
1010

11+
<ItemGroup>
12+
<EmbeddedResource Include="..\apimtemplate\Creator\ExampleFiles\OpenAPISpecs\swaggerPetstorev3.json" Link="Resources\swaggerPetstorev3.json" />
13+
</ItemGroup>
14+
1115
<ItemGroup>
1216
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
17+
<PackageReference Include="YamlDotNet" Version="8.1.1" />
1318
</ItemGroup>
1419

1520
<ItemGroup>
@@ -26,4 +31,12 @@
2631
<ProjectReference Include="..\apimtemplate\apimtemplate.csproj" />
2732
</ItemGroup>
2833

34+
<ItemGroup>
35+
<Folder Include="Resources\" />
36+
</ItemGroup>
37+
38+
<ItemGroup>
39+
<EmbeddedResource Include="..\apimtemplate\Creator\ExampleFiles\OpenAPISpecs\swaggerPetstore.yml" Link="Resources\swaggerPetstore.yml" />
40+
</ItemGroup>
41+
2942
</Project>

src/APIM_ARMTemplate/apimtemplate/Creator/Models/CreatorConfiguration.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ public class APIConfig
3838
{
3939
// used to build displayName and resource name from APITemplateResource schema
4040
public string name { get; set; }
41+
// optional : overrides title from OpenAPI definition
42+
public string displayName { get; set; }
4143
public string description { get; set; }
4244
public string serviceUrl { get; set; }
4345
// used to build type and apiType from APITemplateResource schema

src/APIM_ARMTemplate/apimtemplate/Creator/TemplateCreators/APITemplateCreator.cs

Lines changed: 38 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
using System.Threading.Tasks;
33
using System;
44
using Microsoft.Azure.Management.ApiManagement.ArmTemplates.Common;
5+
using apimtemplate.Creator.Utilities;
6+
using System.Net;
57

68
namespace Microsoft.Azure.Management.ApiManagement.ArmTemplates.Create
79
{
@@ -173,37 +175,47 @@ public async Task<APITemplateResource> CreateAPITemplateResourceAsync(APIConfig
173175
bool isJSON = this.fileReader.isJSON(fileContents);
174176
bool isUrl = Uri.TryCreate(api.openApiSpec, UriKind.Absolute, out uriResult) && (uriResult.Scheme == Uri.UriSchemeHttp || uriResult.Scheme == Uri.UriSchemeHttps);
175177

176-
if (isUrl == true)
178+
value = isUrl
179+
? api.openApiSpec
180+
: fileContents
181+
;
182+
183+
bool isVersionThree = false;
184+
if (isJSON == true)
177185
{
178-
value = api.openApiSpec;
179-
if (isJSON == true)
180-
{
181-
// open api spec is remote json file, use swagger-link-json for v2 and openapi-link for v3
182-
OpenAPISpecReader openAPISpecReader = new OpenAPISpecReader();
183-
bool isVersionThree = await openAPISpecReader.isJSONOpenAPISpecVersionThreeAsync(api.openApiSpec);
184-
format = isVersionThree == false ? "swagger-link-json" : "openapi-link";
185-
}
186-
else
187-
{
188-
// open api spec is remote yaml file
189-
format = "openapi-link";
190-
}
191-
} else
186+
// open api spec is remote json file, use swagger-link-json for v2 and openapi-link for v3
187+
OpenAPISpecReader openAPISpecReader = new OpenAPISpecReader();
188+
isVersionThree = await openAPISpecReader.isJSONOpenAPISpecVersionThreeAsync(api.openApiSpec);
189+
}
190+
191+
format = isUrl
192+
? (isJSON ? (isVersionThree ? "openapi-link" : "swagger-link-json") : "openapi-link")
193+
: (isJSON ? (isVersionThree ? "openapi+json" : "swagger-json") : "openapi")
194+
;
195+
196+
// if the title needs to be modified
197+
// we need to embed the OpenAPI definition
198+
199+
if (!string.IsNullOrEmpty(api.displayName))
192200
{
193-
value = fileContents;
194-
if (isJSON == true)
195-
{
196-
// open api spec is local json file, use swagger-json for v2 and openapi+json for v3
197-
OpenAPISpecReader openAPISpecReader = new OpenAPISpecReader();
198-
bool isVersionThree = await openAPISpecReader.isJSONOpenAPISpecVersionThreeAsync(api.openApiSpec);
199-
format = isVersionThree == false ? "swagger-json" : "openapi+json";
200-
} else
201+
format = (isJSON ? (isVersionThree ? "openapi+json" : "swagger-json") : "openapi");
202+
203+
// download definition
204+
205+
if (isUrl)
201206
{
202-
// open api spec is local yaml file
203-
format = "openapi";
207+
using (var client = new WebClient())
208+
value = client.DownloadString(value);
204209
}
210+
211+
// update title
212+
213+
value = new OpenApi(value, format)
214+
.SetTitle(api.displayName)
215+
.GetDefinition()
216+
;
205217
}
206-
// set the version set id
218+
// set the version set id
207219
if (api.apiVersionSetId != null)
208220
{
209221
// point to the supplied version set if the apiVersionSetId is provided

0 commit comments

Comments
 (0)