Skip to content

Commit c0381c7

Browse files
Adds GraphConnectorGuidancePlugin. Closes #603 (#604)
* WIP: Adds GraphConnectorGuidancePlugin * Adds GraphConnectorGuidancePlugin. Closes #603 * Updates message
1 parent d750294 commit c0381c7

File tree

6 files changed

+178
-32
lines changed

6 files changed

+178
-32
lines changed
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
using Microsoft.Extensions.Configuration;
5+
using Microsoft.DevProxy.Abstractions;
6+
using System.Text.Json;
7+
using Microsoft.Extensions.Logging;
8+
9+
namespace Microsoft.DevProxy.Plugins.Guidance;
10+
11+
class ExternalConnectionSchema
12+
{
13+
public string? BaseType { get; set; }
14+
public ExternalConnectionSchemaProperty[]? Properties { get; set; }
15+
}
16+
17+
class ExternalConnectionSchemaProperty
18+
{
19+
public string[]? Aliases { get; set; }
20+
public bool? IsQueryable { get; set; }
21+
public bool? IsRefinable { get; set; }
22+
public bool? IsRetrievable { get; set; }
23+
public bool? IsSearchable { get; set; }
24+
public string[]? Labels { get; set; }
25+
public string? Name { get; set; }
26+
public string? Type { get; set; }
27+
}
28+
29+
public class GraphConnectorGuidancePlugin : BaseProxyPlugin
30+
{
31+
public override string Name => nameof(GraphConnectorGuidancePlugin);
32+
33+
public override void Register(IPluginEvents pluginEvents,
34+
IProxyContext context,
35+
ISet<UrlToWatch> urlsToWatch,
36+
IConfigurationSection? configSection = null)
37+
{
38+
base.Register(pluginEvents, context, urlsToWatch, configSection);
39+
40+
pluginEvents.BeforeRequest += BeforeRequest;
41+
}
42+
43+
private Task BeforeRequest(object sender, ProxyRequestArgs e)
44+
{
45+
if (_urlsToWatch is null ||
46+
!e.HasRequestUrlMatch(_urlsToWatch) ||
47+
e.Session.HttpClient.Request.Method.ToUpper() != "PATCH")
48+
{
49+
return Task.CompletedTask;
50+
}
51+
52+
try
53+
{
54+
var schemaString = e.Session.HttpClient.Request.BodyString;
55+
if (string.IsNullOrEmpty(schemaString))
56+
{
57+
_logger?.LogRequest([ "No schema found in the request body." ], MessageType.Failed, new LoggingContext(e.Session));
58+
return Task.CompletedTask;
59+
}
60+
61+
var schema = JsonSerializer.Deserialize<ExternalConnectionSchema>(schemaString, ProxyUtils.JsonSerializerOptions);
62+
if (schema is null || schema.Properties is null)
63+
{
64+
_logger?.LogRequest([ "Invalid schema found in the request body." ], MessageType.Failed, new LoggingContext(e.Session));
65+
return Task.CompletedTask;
66+
}
67+
68+
bool hasTitle = false, hasIconUrl = false, hasUrl = false;
69+
foreach (var property in schema.Properties)
70+
{
71+
if (property.Labels is null)
72+
{
73+
continue;
74+
}
75+
76+
if (property.Labels.Contains("title", StringComparer.OrdinalIgnoreCase))
77+
{
78+
hasTitle = true;
79+
}
80+
if (property.Labels.Contains("iconUrl", StringComparer.OrdinalIgnoreCase))
81+
{
82+
hasIconUrl = true;
83+
}
84+
if (property.Labels.Contains("url", StringComparer.OrdinalIgnoreCase))
85+
{
86+
hasUrl = true;
87+
}
88+
}
89+
90+
if (!hasTitle || !hasIconUrl || !hasUrl)
91+
{
92+
string[] missingLabels = [
93+
!hasTitle ? "title" : "",
94+
!hasIconUrl ? "iconUrl" : "",
95+
!hasUrl ? "url" : ""
96+
];
97+
98+
_logger?.LogRequest(
99+
[
100+
$"The schema is missing the following semantic labels: {string.Join(", ", missingLabels.Where(s => s != ""))}.",
101+
"Ingested content might not show up in Microsoft Copilot for Microsoft 365.",
102+
"More information: https://aka.ms/devproxy/guidance/gc/ux"
103+
],
104+
MessageType.Failed, new LoggingContext(e.Session)
105+
);
106+
}
107+
}
108+
catch (Exception ex)
109+
{
110+
_logger?.LogError(ex, "An error has occurred while deserializing the request body");
111+
}
112+
113+
return Task.CompletedTask;
114+
}
115+
}

dev-proxy/ConsoleLogger.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,14 @@ public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Except
346346
return;
347347
}
348348

349-
var message = formatter(state, exception).ReplaceLineEndings();
349+
var message = formatter(state, exception);
350+
// temporary fix to log exceptions
351+
// long term we should move this to the formatter
352+
if (exception is not null)
353+
{
354+
message += Environment.NewLine + exception;
355+
}
356+
message = message.ReplaceLineEndings();
350357
switch (logLevel)
351358
{
352359
case LogLevel.Debug:

dev-proxy/presets/m365-mocks.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"$schema": "https://raw.githubusercontent.com/microsoft/dev-proxy/main/schemas/v0.15.0/mockresponseplugin.schema.json",
2+
"$schema": "https://raw.githubusercontent.com/microsoft/dev-proxy/main/schemas/v0.16.0/mockresponseplugin.schema.json",
33
"mocks": [
44
{
55
"request": {

dev-proxy/presets/m365.json

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,27 @@
11
{
2-
"$schema": "https://raw.githubusercontent.com/microsoft/dev-proxy/main/schemas/v0.15.0/rc.schema.json",
2+
"$schema": "https://raw.githubusercontent.com/microsoft/dev-proxy/main/schemas/v0.16.0/rc.schema.json",
33
"plugins": [
44
{
55
"name": "DevToolsPlugin",
66
"enabled": false,
7-
"pluginPath": "~appFolder\\plugins\\dev-proxy-plugins.dll",
7+
"pluginPath": "~appFolder/plugins/dev-proxy-plugins.dll",
88
"configSection": "devTools"
99
},
1010
{
1111
"name": "LatencyPlugin",
1212
"enabled": false,
13-
"pluginPath": "~appFolder\\plugins\\dev-proxy-plugins.dll",
13+
"pluginPath": "~appFolder/plugins/dev-proxy-plugins.dll",
1414
"configSection": "latencyPlugin"
1515
},
1616
{
1717
"name": "RetryAfterPlugin",
1818
"enabled": true,
19-
"pluginPath": "~appFolder\\plugins\\dev-proxy-plugins.dll"
19+
"pluginPath": "~appFolder/plugins/dev-proxy-plugins.dll"
2020
},
2121
{
2222
"name": "GraphSelectGuidancePlugin",
2323
"enabled": true,
24-
"pluginPath": "~appFolder\\plugins\\dev-proxy-plugins.dll",
24+
"pluginPath": "~appFolder/plugins/dev-proxy-plugins.dll",
2525
"urlsToWatch": [
2626
"https://graph.microsoft.com/v1.0/*",
2727
"https://graph.microsoft.com/beta/*",
@@ -36,7 +36,7 @@
3636
{
3737
"name": "ODSPSearchGuidancePlugin",
3838
"enabled": true,
39-
"pluginPath": "~appFolder\\plugins\\dev-proxy-plugins.dll",
39+
"pluginPath": "~appFolder/plugins/dev-proxy-plugins.dll",
4040
"urlsToWatch": [
4141
"https://graph.microsoft.com/v1.0/*",
4242
"https://graph.microsoft.com/beta/*",
@@ -51,18 +51,29 @@
5151
{
5252
"name": "GraphBetaSupportGuidancePlugin",
5353
"enabled": true,
54-
"pluginPath": "~appFolder\\plugins\\dev-proxy-plugins.dll",
54+
"pluginPath": "~appFolder/plugins/dev-proxy-plugins.dll",
5555
"urlsToWatch": [
5656
"https://graph.microsoft.com/beta/*",
5757
"https://graph.microsoft.us/beta/*",
5858
"https://dod-graph.microsoft.us/beta/*",
5959
"https://microsoftgraph.chinacloudapi.cn/beta/*"
6060
]
6161
},
62+
{
63+
"name": "GraphConnectorGuidancePlugin",
64+
"enabled": true,
65+
"pluginPath": "~appFolder/plugins/dev-proxy-plugins.dll",
66+
"urlsToWatch": [
67+
"https://graph.microsoft.com/*/external/connections/*/schema",
68+
"https://graph.microsoft.us/*/external/connections/*/schema",
69+
"https://dod-graph.microsoft.us/*/external/connections/*/schema",
70+
"https://microsoftgraph.chinacloudapi.cn/*/external/connections/*/schema"
71+
]
72+
},
6273
{
6374
"name": "GraphSdkGuidancePlugin",
6475
"enabled": true,
65-
"pluginPath": "~appFolder\\plugins\\dev-proxy-plugins.dll",
76+
"pluginPath": "~appFolder/plugins/dev-proxy-plugins.dll",
6677
"urlsToWatch": [
6778
"https://graph.microsoft.com/v1.0/*",
6879
"https://graph.microsoft.com/beta/*",
@@ -77,12 +88,12 @@
7788
{
7889
"name": "ODataPagingGuidancePlugin",
7990
"enabled": true,
80-
"pluginPath": "~appFolder\\plugins\\dev-proxy-plugins.dll"
91+
"pluginPath": "~appFolder/plugins/dev-proxy-plugins.dll"
8192
},
8293
{
8394
"name": "GraphClientRequestIdGuidancePlugin",
8495
"enabled": true,
85-
"pluginPath": "~appFolder\\plugins\\dev-proxy-plugins.dll",
96+
"pluginPath": "~appFolder/plugins/dev-proxy-plugins.dll",
8697
"urlsToWatch": [
8798
"https://graph.microsoft.com/v1.0/*",
8899
"https://graph.microsoft.com/beta/*",
@@ -97,54 +108,54 @@
97108
{
98109
"name": "CachingGuidancePlugin",
99110
"enabled": true,
100-
"pluginPath": "~appFolder\\plugins\\dev-proxy-plugins.dll",
111+
"pluginPath": "~appFolder/plugins/dev-proxy-plugins.dll",
101112
"configSection": "cachingGuidance"
102113
},
103114
{
104115
"name": "RateLimitingPlugin",
105116
"enabled": false,
106-
"pluginPath": "~appFolder\\plugins\\dev-proxy-plugins.dll",
117+
"pluginPath": "~appFolder/plugins/dev-proxy-plugins.dll",
107118
"configSection": "rateLimiting"
108119
},
109120
{
110121
"name": "MockResponsePlugin",
111122
"enabled": false,
112-
"pluginPath": "~appFolder\\plugins\\dev-proxy-plugins.dll",
123+
"pluginPath": "~appFolder/plugins/dev-proxy-plugins.dll",
113124
"configSection": "mocksPlugin"
114125
},
115126
{
116127
"name": "GraphMockResponsePlugin",
117128
"enabled": true,
118-
"pluginPath": "~appFolder\\plugins\\dev-proxy-plugins.dll",
129+
"pluginPath": "~appFolder/plugins/dev-proxy-plugins.dll",
119130
"configSection": "mocksPlugin"
120131
},
121132
{
122133
"name": "GraphRandomErrorPlugin",
123134
"enabled": true,
124-
"pluginPath": "~appFolder\\plugins\\dev-proxy-plugins.dll",
135+
"pluginPath": "~appFolder/plugins/dev-proxy-plugins.dll",
125136
"configSection": "graphRandomErrorsPlugin"
126137
},
127138
{
128139
"name": "ExecutionSummaryPlugin",
129140
"enabled": false,
130-
"pluginPath": "~appFolder\\plugins\\dev-proxy-plugins.dll",
141+
"pluginPath": "~appFolder/plugins/dev-proxy-plugins.dll",
131142
"configSection": "executionSummaryPlugin"
132143
},
133144
{
134145
"name": "MinimalPermissionsPlugin",
135146
"enabled": true,
136-
"pluginPath": "~appFolder\\plugins\\dev-proxy-plugins.dll",
147+
"pluginPath": "~appFolder/plugins/dev-proxy-plugins.dll",
137148
"configSection": "minimalPermissionsPlugin"
138149
},
139150
{
140151
"name": "MinimalPermissionsGuidancePlugin",
141152
"enabled": false,
142-
"pluginPath": "~appFolder\\plugins\\dev-proxy-plugins.dll"
153+
"pluginPath": "~appFolder/plugins/dev-proxy-plugins.dll"
143154
},
144155
{
145156
"name": "MockGeneratorPlugin",
146157
"enabled": false,
147-
"pluginPath": "~appFolder\\plugins\\dev-proxy-plugins.dll"
158+
"pluginPath": "~appFolder/plugins/dev-proxy-plugins.dll"
148159
}
149160
],
150161
"urlsToWatch": [
@@ -190,6 +201,6 @@
190201
},
191202
"rate": 50,
192203
"labelMode": "text",
193-
"logLevel": "info"
204+
"logLevel": "information"
194205
}
195206

dev-proxy/presets/microsoft-graph-rate-limiting.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
{
2+
"$schema": "https://raw.githubusercontent.com/microsoft/dev-proxy/main/schemas/v0.16.0/rc.schema.json",
23
"plugins": [
34
{
45
"name": "RateLimitingPlugin",
56
"enabled": true,
6-
"pluginPath": "~appFolder\\plugins\\dev-proxy-plugins.dll"
7+
"pluginPath": "~appFolder/plugins/dev-proxy-plugins.dll"
78
}
89
],
910
"urlsToWatch": [
@@ -21,5 +22,5 @@
2122
"https://microsoftgraph.chinacloudapi.cn/*/sites/*"
2223
],
2324
"labelMode": "text",
24-
"logLevel": "info"
25+
"logLevel": "information"
2526
}

dev-proxy/presets/microsoft-graph.json

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,58 @@
11
{
2+
"$schema": "https://raw.githubusercontent.com/microsoft/dev-proxy/main/schemas/v0.16.0/rc.schema.json",
23
"plugins": [
34
{
45
"name": "GraphSelectGuidancePlugin",
56
"enabled": true,
6-
"pluginPath": "~appFolder\\plugins\\dev-proxy-plugins.dll"
7+
"pluginPath": "~appFolder/plugins/dev-proxy-plugins.dll"
78
},
89
{
910
"name": "GraphBetaSupportGuidancePlugin",
1011
"enabled": true,
11-
"pluginPath": "~appFolder\\plugins\\dev-proxy-plugins.dll",
12+
"pluginPath": "~appFolder/plugins/dev-proxy-plugins.dll",
1213
"urlsToWatch": [
1314
"https://graph.microsoft.com/beta/*",
1415
"https://graph.microsoft.us/beta/*",
1516
"https://dod-graph.microsoft.us/beta/*",
1617
"https://microsoftgraph.chinacloudapi.cn/beta/*"
1718
]
1819
},
20+
{
21+
"name": "GraphConnectorGuidancePlugin",
22+
"enabled": true,
23+
"pluginPath": "~appFolder/plugins/dev-proxy-plugins.dll",
24+
"urlsToWatch": [
25+
"https://graph.microsoft.com/*/external/connections/*/schema",
26+
"https://graph.microsoft.us/*/external/connections/*/schema",
27+
"https://dod-graph.microsoft.us/*/external/connections/*/schema",
28+
"https://microsoftgraph.chinacloudapi.cn/*/external/connections/*/schema"
29+
]
30+
},
1931
{
2032
"name": "GraphSdkGuidancePlugin",
2133
"enabled": true,
22-
"pluginPath": "~appFolder\\plugins\\dev-proxy-plugins.dll"
34+
"pluginPath": "~appFolder/plugins/dev-proxy-plugins.dll"
2335
},
2436
{
2537
"name": "ODataPagingGuidancePlugin",
2638
"enabled": true,
27-
"pluginPath": "~appFolder\\plugins\\dev-proxy-plugins.dll"
39+
"pluginPath": "~appFolder/plugins/dev-proxy-plugins.dll"
2840
},
2941
{
3042
"name": "GraphClientRequestIdGuidancePlugin",
3143
"enabled": true,
32-
"pluginPath": "~appFolder\\plugins\\dev-proxy-plugins.dll"
44+
"pluginPath": "~appFolder/plugins/dev-proxy-plugins.dll"
3345
},
3446
{
3547
"name": "GraphRandomErrorPlugin",
3648
"enabled": true,
37-
"pluginPath": "~appFolder\\plugins\\dev-proxy-plugins.dll",
49+
"pluginPath": "~appFolder/plugins/dev-proxy-plugins.dll",
3850
"configSection": "graphRandomErrorsPlugin"
3951
},
4052
{
4153
"name": "ExecutionSummaryPlugin",
4254
"enabled": true,
43-
"pluginPath": "~appFolder\\plugins\\dev-proxy-plugins.dll",
55+
"pluginPath": "~appFolder/plugins/dev-proxy-plugins.dll",
4456
"configSection": "executionSummaryPlugin"
4557
}
4658
],
@@ -62,5 +74,5 @@
6274
},
6375
"rate": 50,
6476
"labelMode": "text",
65-
"logLevel": "info"
77+
"logLevel": "information"
6678
}

0 commit comments

Comments
 (0)