Skip to content

Commit 2f4a1c8

Browse files
committed
Add an OpenApi filtering service for filtering an OpenApiDocument based on OperationId
1 parent 0ecca08 commit 2f4a1c8

File tree

1 file changed

+186
-0
lines changed

1 file changed

+186
-0
lines changed
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT license.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
using Microsoft.OpenApi.Models;
8+
9+
namespace Microsoft.OpenApi.Services
10+
{
11+
/// <summary>
12+
///
13+
/// </summary>
14+
public class OpenApiFilterService
15+
{
16+
public static readonly string GraphAuthorizationUrl = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize";
17+
public static readonly string GraphTokenUrl = "https://login.microsoftonline.com/common/oauth2/v2.0/token";
18+
public static readonly string GraphUrl = "https://graph.microsoft.com/{0}/";
19+
public const string GraphVersion_V1 = "v1.0";
20+
21+
22+
public OpenApiDocument CreateSubsetOpenApiDocument(string operationIds, OpenApiDocument source, string title)
23+
{
24+
var predicate = CreatePredicate(operationIds);
25+
26+
var subsetOpenApiDocument = CreateFilteredDocument(source, title, GraphVersion_V1, predicate);
27+
28+
return subsetOpenApiDocument;
29+
}
30+
31+
public Func<OpenApiOperation, bool> CreatePredicate(string operationIds)
32+
{
33+
string predicateSource = null;
34+
35+
Func<OpenApiOperation, bool> predicate;
36+
if (operationIds != null)
37+
{
38+
if (operationIds == "*")
39+
{
40+
predicate = (o) => true; // All operations
41+
}
42+
else
43+
{
44+
var operationIdsArray = operationIds.Split(',');
45+
predicate = (o) => operationIdsArray.Contains(o.OperationId);
46+
}
47+
48+
predicateSource = $"operationIds: {operationIds}";
49+
}
50+
51+
else
52+
{
53+
throw new InvalidOperationException("OperationId needs to be specified.");
54+
}
55+
56+
return predicate;
57+
}
58+
/// <summary>
59+
///
60+
/// </summary>
61+
/// <param name="source"></param>
62+
/// <param name="title"></param>
63+
/// <param name="graphVersion"></param>
64+
/// <param name="predicate"></param>
65+
/// <returns></returns>
66+
public OpenApiDocument CreateFilteredDocument(OpenApiDocument source, string title, string graphVersion, Func<OpenApiOperation, bool> predicate)
67+
{
68+
var subset = new OpenApiDocument
69+
{
70+
Info = new OpenApiInfo()
71+
{
72+
Title = title,
73+
Version = graphVersion
74+
},
75+
76+
Components = new OpenApiComponents()
77+
};
78+
var aadv2Scheme = new OpenApiSecurityScheme()
79+
{
80+
Type = SecuritySchemeType.OAuth2,
81+
Flows = new OpenApiOAuthFlows()
82+
{
83+
AuthorizationCode = new OpenApiOAuthFlow()
84+
{
85+
AuthorizationUrl = new Uri(GraphAuthorizationUrl),
86+
TokenUrl = new Uri(GraphTokenUrl)
87+
}
88+
},
89+
Reference = new OpenApiReference() { Id = "azureaadv2", Type = ReferenceType.SecurityScheme },
90+
UnresolvedReference = false
91+
};
92+
subset.Components.SecuritySchemes.Add("azureaadv2", aadv2Scheme);
93+
94+
subset.SecurityRequirements.Add(new OpenApiSecurityRequirement() { { aadv2Scheme, Array.Empty<string>() } });
95+
96+
subset.Servers.Add(new OpenApiServer() { Description = "Core", Url = string.Format(GraphUrl, graphVersion) });
97+
98+
var results = FindOperations(source, predicate);
99+
foreach (var result in results)
100+
{
101+
OpenApiPathItem pathItem;
102+
string pathKey = result.CurrentKeys.Path;
103+
104+
if (subset.Paths == null)
105+
{
106+
subset.Paths = new OpenApiPaths();
107+
pathItem = new OpenApiPathItem();
108+
subset.Paths.Add(pathKey, pathItem);
109+
}
110+
else
111+
{
112+
if (!subset.Paths.TryGetValue(pathKey, out pathItem))
113+
{
114+
pathItem = new OpenApiPathItem();
115+
subset.Paths.Add(pathKey, pathItem);
116+
}
117+
}
118+
119+
pathItem.Operations.Add((OperationType)result.CurrentKeys.Operation, result.Operation);
120+
}
121+
122+
if (subset.Paths == null)
123+
{
124+
throw new ArgumentException("No paths found for the supplied parameters.");
125+
}
126+
127+
CopyReferences(subset);
128+
129+
return subset;
130+
}
131+
132+
private static IList<SearchResult> FindOperations(OpenApiDocument graphOpenApi, Func<OpenApiOperation, bool> predicate)
133+
{
134+
var search = new OperationSearch(predicate);
135+
var walker = new OpenApiWalker(search);
136+
walker.Walk(graphOpenApi);
137+
return search.SearchResults;
138+
}
139+
140+
private static void CopyReferences(OpenApiDocument target)
141+
{
142+
bool morestuff;
143+
do
144+
{
145+
var copy = new CopyReferences(target);
146+
var walker = new OpenApiWalker(copy);
147+
walker.Walk(target);
148+
149+
morestuff = AddReferences(copy.Components, target.Components);
150+
151+
} while (morestuff);
152+
}
153+
154+
private static bool AddReferences(OpenApiComponents newComponents, OpenApiComponents target)
155+
{
156+
var moreStuff = false;
157+
foreach (var item in newComponents.Schemas)
158+
{
159+
if (!target.Schemas.ContainsKey(item.Key))
160+
{
161+
moreStuff = true;
162+
target.Schemas.Add(item);
163+
}
164+
}
165+
166+
foreach (var item in newComponents.Parameters)
167+
{
168+
if (!target.Parameters.ContainsKey(item.Key))
169+
{
170+
moreStuff = true;
171+
target.Parameters.Add(item);
172+
}
173+
}
174+
175+
foreach (var item in newComponents.Responses)
176+
{
177+
if (!target.Responses.ContainsKey(item.Key))
178+
{
179+
moreStuff = true;
180+
target.Responses.Add(item);
181+
}
182+
}
183+
return moreStuff;
184+
}
185+
}
186+
}

0 commit comments

Comments
 (0)