Skip to content

Commit d7309c3

Browse files
authored
Merge pull request #2101 from microsoftgraph/po/ServiceErrorCodeOnError
Surface Service Errors to Error Stream
2 parents 5d82888 + 3cffc9f commit d7309c3

File tree

3 files changed

+77
-6
lines changed

3 files changed

+77
-6
lines changed

src/readme.graph.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,27 @@ directive:
246246
}
247247
}
248248
}
249+
# Add Microsoft Graph error properties to InnerError.
250+
- from: 'openapi-document'
251+
where: $.components.schemas['microsoft.graph.ODataErrors.InnerError']
252+
transform: >-
253+
return {
254+
"type": "object",
255+
"properties": {
256+
"date" : {
257+
"type" : 'string'
258+
},
259+
"request-id" : {
260+
"type" : 'string'
261+
},
262+
"client-request-id" : {
263+
"type" : 'string'
264+
}
265+
},
266+
"additionalProperties": {
267+
"type" : "object"
268+
}
269+
}
249270
# Mark '@odata.id' as required properties for /$ref.
250271
- from: 'openapi-document'
251272
where: $.components.schemas.ReferenceCreate
@@ -399,6 +420,10 @@ directive:
399420
}
400421
}
401422
423+
// Format error details.
424+
let errorDetailsRegex = /(ErrorDetails\s*=\s*)(new.*ErrorDetails\(message\).*)/gmi
425+
$ = $.replace(errorDetailsRegex, '$1await this.GetErrorDetailsAsync((await response)?.Error, responseMessage)');
426+
402427
return $;
403428
}
404429
@@ -547,6 +572,21 @@ directive:
547572
return $;
548573
}
549574
575+
# Modify generated JsonObject class.
576+
- from: source-file-csharp
577+
where: $
578+
transform: >
579+
if (!$documentPath.match(/generated%2Fruntime%2FNodes%2FJsonObject.cs/gm))
580+
{
581+
return $;
582+
} else {
583+
// Make JsonObject's items dictionary case insensitive.
584+
let dictionaryInitRegex = /(\s*=\s*new\s*Dictionary<string,\s*JsonNode>\()(\);)/gm
585+
$ = $.replace(dictionaryInitRegex, '$1StringComparer.InvariantCultureIgnoreCase$2');
586+
587+
return $;
588+
}
589+
550590
# Modify API class.
551591
- from: source-file-csharp
552592
where: $

tools/Custom/HttpMessageLogFormatter.cs

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace NamespacePrefixPlaceholder.PowerShell
66
{
7+
using NamespacePrefixPlaceholder.PowerShell.Models;
78
using Newtonsoft.Json;
89
using System;
910
using System.Collections.Generic;
@@ -63,9 +64,9 @@ public static async Task<string> GetHttpRequestLogAsync(HttpRequestMessage reque
6364

6465
StringBuilder stringBuilder = new StringBuilder();
6566
stringBuilder.AppendLine($"============================ HTTP REQUEST ============================{Environment.NewLine}");
66-
stringBuilder.AppendLine($"HTTP Method:{Environment.NewLine}{requestClone.Method.ToString()}{Environment.NewLine}");
67-
stringBuilder.AppendLine($"Absolute Uri:{Environment.NewLine}{requestClone.RequestUri.ToString()}{Environment.NewLine}");
68-
stringBuilder.AppendLine($"Headers:{Environment.NewLine}{HeadersToString(ConvertHttpHeadersToCollection(requestClone.Headers))}{Environment.NewLine}");
67+
stringBuilder.AppendLine($"HTTP Method:{Environment.NewLine}{requestClone.Method}{Environment.NewLine}");
68+
stringBuilder.AppendLine($"Absolute Uri:{Environment.NewLine}{requestClone.RequestUri}{Environment.NewLine}");
69+
stringBuilder.AppendLine($"Headers:{Environment.NewLine}{HeadersToString(requestClone.Headers)}{Environment.NewLine}");
6970
stringBuilder.AppendLine($"Body:{Environment.NewLine}{SanitizeBody(body)}{Environment.NewLine}");
7071
return stringBuilder.ToString();
7172
}
@@ -84,12 +85,30 @@ public static async Task<string> GetHttpResponseLogAsync(HttpResponseMessage res
8485
StringBuilder stringBuilder = new StringBuilder();
8586
stringBuilder.AppendLine($"============================ HTTP RESPONSE ============================{Environment.NewLine}");
8687
stringBuilder.AppendLine($"Status Code:{Environment.NewLine}{response.StatusCode}{Environment.NewLine}");
87-
stringBuilder.AppendLine($"Headers:{Environment.NewLine}{HeadersToString(ConvertHttpHeadersToCollection(response.Headers))}{Environment.NewLine}");
88+
stringBuilder.AppendLine($"Headers:{Environment.NewLine}{HeadersToString(response.Headers)}{Environment.NewLine}");
8889
stringBuilder.AppendLine($"Body:{Environment.NewLine}{SanitizeBody(body)}{Environment.NewLine}");
8990
return stringBuilder.ToString();
9091
}
9192

92-
private static Regex regexPattern = new Regex("(\\s*\"access_token\"\\s*:\\s*)\"[^\"]+\"", RegexOptions.Compiled);
93+
public static async Task<string> GetErrorLogAsync(HttpResponseMessage response, IMicrosoftGraphODataErrorsMainError odataError)
94+
{
95+
if (response == null) return string.Empty;
96+
97+
StringBuilder stringBuilder = new StringBuilder();
98+
stringBuilder.AppendLine($"{odataError?.Message}{Environment.NewLine}");
99+
stringBuilder.AppendLine($"Status: {((int)response.StatusCode)} ({response.StatusCode})");
100+
stringBuilder.AppendLine($"ErrorCode: {odataError?.Code}");
101+
stringBuilder.AppendLine($"Date: {odataError?.Innererror?.Date}{Environment.NewLine}");
102+
stringBuilder.AppendLine($"Headers:{Environment.NewLine}{HeadersToString(response.Headers)}{Environment.NewLine}");
103+
return stringBuilder.ToString();
104+
}
105+
106+
internal static string HeadersToString(HttpHeaders headers)
107+
{
108+
return HeadersToString(ConvertHttpHeadersToCollection(headers));
109+
}
110+
111+
private static readonly Regex regexPattern = new Regex("(\\s*\"access_token\"\\s*:\\s*)\"[^\"]+\"", RegexOptions.Compiled);
93112
private static object SanitizeBody(string body)
94113
{
95114
IList<Regex> regexList = new List<Regex>();
@@ -110,7 +129,7 @@ private static IDictionary<string, IEnumerable<string>> ConvertHttpHeadersToColl
110129
return headers.ToDictionary(a => a.Key, a => a.Value);
111130
}
112131

113-
private static object HeadersToString(IDictionary<string, IEnumerable<string>> headers)
132+
private static string HeadersToString(IDictionary<string, IEnumerable<string>> headers)
114133
{
115134
StringBuilder stringBuilder = headers.Aggregate(new StringBuilder(),
116135
(sb, kvp) => sb.AppendLine(string.Format("{0,-30}: {1}", kvp.Key, String.Join(",", kvp.Value.ToArray()))));

tools/Custom/PSCmdletExtensions.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ namespace NamespacePrefixPlaceholder.PowerShell
55
{
66
using Microsoft.Graph.PowerShell.Authentication;
77
using Microsoft.Graph.PowerShell.Authentication.Common;
8+
using NamespacePrefixPlaceholder.PowerShell.Models;
89
using System;
910
using System.Collections.ObjectModel;
1011
using System.IO;
@@ -104,6 +105,17 @@ internal static void WriteToFile(this PSCmdlet cmdlet, HttpResponseMessage respo
104105
cmdlet.WriteToStream(inputStream, fileProvider.Stream, downloadUrl, cancellationToken);
105106
}
106107
}
108+
109+
internal static async Task<ErrorDetails> GetErrorDetailsAsync(this PSCmdlet cmdlet, IMicrosoftGraphODataErrorsMainError odataError, HttpResponseMessage response)
110+
{
111+
var serviceErrorDoc = "https://learn.microsoft.com/graph/errors";
112+
var recommendedAction = $"See service error codes: {serviceErrorDoc}";
113+
var errorDetailsMessage = await HttpMessageLogFormatter.GetErrorLogAsync(response, odataError);
114+
return new ErrorDetails(errorDetailsMessage)
115+
{
116+
RecommendedAction = recommendedAction
117+
};
118+
}
107119

108120
/// <summary>
109121
/// Writes an input stream to an output stream.

0 commit comments

Comments
 (0)