Skip to content

Commit 1576a26

Browse files
feat(client): add helper functions for raw messages
1 parent 63b0e6c commit 1576a26

File tree

3 files changed

+40
-15
lines changed

3 files changed

+40
-15
lines changed

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,10 +111,12 @@ To access this data, prefix any HTTP method call on a client or service with `Wi
111111

112112
```csharp
113113
var response = await client.WithRawResponse.Customers.Create(parameters);
114-
var statusCode = response.Message.StatusCode;
115-
var headers = response.Message.Headers;
114+
var statusCode = response.StatusCode;
115+
var headers = response.Headers;
116116
```
117117

118+
The raw `HttpResponseMessage` can also be accessed through the `RawMessage` property.
119+
118120
For non-streaming responses, you can deserialize the response into an instance of a C# class if needed:
119121

120122
```csharp

src/Orb/Core/HttpResponse.cs

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.Generic;
33
using System.Diagnostics.CodeAnalysis;
44
using System.IO;
5+
using System.Net;
56
using System.Net.Http;
67
using System.Text.Json;
78
using System.Threading.Tasks;
@@ -12,10 +13,32 @@ namespace Orb.Core;
1213

1314
public class HttpResponse : IDisposable
1415
{
15-
public required HttpResponseMessage Message { get; init; }
16+
public required HttpResponseMessage RawMessage { get; init; }
17+
18+
public IEnumerable<KeyValuePair<string, IEnumerable<string>>> Headers
19+
{
20+
get { return RawMessage.Headers; }
21+
}
22+
23+
public bool IsSuccessStatusCode
24+
{
25+
get { return RawMessage.IsSuccessStatusCode; }
26+
}
27+
28+
public HttpStatusCode StatusCode
29+
{
30+
get { return RawMessage.StatusCode; }
31+
}
1632

1733
public Threading::CancellationToken CancellationToken { get; init; } = default;
1834

35+
public IEnumerable<string> GetHeaderValues(string name) => RawMessage.Headers.GetValues(name);
36+
37+
public bool TryGetHeaderValues(
38+
string name,
39+
[NotNullWhen(true)] out IEnumerable<string>? values
40+
) => RawMessage.Headers.TryGetValues(name, out values);
41+
1942
public async Task<T> Deserialize<T>(Threading::CancellationToken cancellationToken = default)
2043
{
2144
using var cts = Threading::CancellationTokenSource.CreateLinkedTokenSource(
@@ -45,7 +68,7 @@ public async Task<Stream> ReadAsStream(Threading::CancellationToken cancellation
4568
this.CancellationToken,
4669
cancellationToken
4770
);
48-
return await Message.Content.ReadAsStreamAsync(
71+
return await RawMessage.Content.ReadAsStreamAsync(
4972
#if NET
5073
cts.Token
5174
#endif
@@ -58,7 +81,7 @@ public async Task<string> ReadAsString(Threading::CancellationToken cancellation
5881
this.CancellationToken,
5982
cancellationToken
6083
);
61-
return await Message.Content.ReadAsStringAsync(
84+
return await RawMessage.Content.ReadAsStringAsync(
6285
#if NET
6386
cts.Token
6487
#endif
@@ -67,7 +90,7 @@ public async Task<string> ReadAsString(Threading::CancellationToken cancellation
6790

6891
public void Dispose()
6992
{
70-
this.Message.Dispose();
93+
this.RawMessage.Dispose();
7194
GC.SuppressFinalize(this);
7295
}
7396
}
@@ -88,7 +111,7 @@ internal HttpResponse(
88111
)
89112
: this(deserialize)
90113
{
91-
this.Message = response.Message;
114+
this.RawMessage = response.RawMessage;
92115
this.CancellationToken = response.CancellationToken;
93116
}
94117

@@ -120,7 +143,7 @@ internal StreamingHttpResponse(
120143
)
121144
: this(enumerate)
122145
{
123-
this.Message = response.Message;
146+
this.RawMessage = response.RawMessage;
124147
this.CancellationToken = response.CancellationToken;
125148
}
126149

src/Orb/OrbClient.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -420,15 +420,15 @@ public async Task<HttpResponse> Execute<T>(
420420

421421
if (response != null && (++retries > maxRetries || !ShouldRetry(response)))
422422
{
423-
if (response.Message.IsSuccessStatusCode)
423+
if (response.IsSuccessStatusCode)
424424
{
425425
return response;
426426
}
427427

428428
try
429429
{
430430
throw OrbExceptionFactory.CreateApiException(
431-
response.Message.StatusCode,
431+
response.StatusCode,
432432
await response.ReadAsString(cancellationToken).ConfigureAwait(false)
433433
);
434434
}
@@ -494,7 +494,7 @@ async Task<HttpResponse> ExecuteOnce<T>(
494494
{
495495
throw new OrbIOException("I/O exception", e);
496496
}
497-
return new() { Message = responseMessage, CancellationToken = cts.Token };
497+
return new() { RawMessage = responseMessage, CancellationToken = cts.Token };
498498
}
499499

500500
static TimeSpan ComputeRetryBackoff(int retries, HttpResponse? response)
@@ -516,7 +516,7 @@ static TimeSpan ComputeRetryBackoff(int retries, HttpResponse? response)
516516
static TimeSpan? ParseRetryAfterMsHeader(HttpResponse? response)
517517
{
518518
IEnumerable<string>? headerValues = null;
519-
response?.Message.Headers.TryGetValues("Retry-After-Ms", out headerValues);
519+
response?.TryGetHeaderValues("Retry-After-Ms", out headerValues);
520520
var headerValue = headerValues == null ? null : Enumerable.FirstOrDefault(headerValues);
521521
if (headerValue == null)
522522
{
@@ -534,7 +534,7 @@ static TimeSpan ComputeRetryBackoff(int retries, HttpResponse? response)
534534
static TimeSpan? ParseRetryAfterHeader(HttpResponse? response)
535535
{
536536
IEnumerable<string>? headerValues = null;
537-
response?.Message.Headers.TryGetValues("Retry-After", out headerValues);
537+
response?.TryGetHeaderValues("Retry-After", out headerValues);
538538
var headerValue = headerValues == null ? null : Enumerable.FirstOrDefault(headerValues);
539539
if (headerValue == null)
540540
{
@@ -556,15 +556,15 @@ static TimeSpan ComputeRetryBackoff(int retries, HttpResponse? response)
556556
static bool ShouldRetry(HttpResponse response)
557557
{
558558
if (
559-
response.Message.Headers.TryGetValues("X-Should-Retry", out var headerValues)
559+
response.TryGetHeaderValues("X-Should-Retry", out var headerValues)
560560
&& bool.TryParse(Enumerable.FirstOrDefault(headerValues), out var shouldRetry)
561561
)
562562
{
563563
// If the server explicitly says whether to retry, then we obey.
564564
return shouldRetry;
565565
}
566566

567-
return (int)response.Message.StatusCode switch
567+
return (int)response.StatusCode switch
568568
{
569569
// Retry on request timeouts
570570
408

0 commit comments

Comments
 (0)