Http
A typed HttpClient wrapper that returns status, headers and a deserialized body in a single envelope.
Features
HttpGateway: wrapsHttpClientwith typed async methods for GET, POST, PUT, PATCH, and DELETE. Each takes aCancellationToken, buffers the response body into anHttpOutput<TBody>, and disposes the underlyingHttpResponseMessagebefore returning.HttpOutput<TBody>: typed HTTP response container carrying the status code, response and content headers, the raw body text, anIsSuccessflag, and the deserialized body. A payload that cannot be bound toTBody— malformed JSON, an array where an object was expected, an HTML error page — leavesBodyat its default rather than throwing.HttpExtensions: generic extension providingToJsonStringContent()to serialize a payload into aStringContentsuitable for request payloads. Serialization usesSystem.Text.Json; property matching on the way back in is case insensitive.HttpStatusCodes: static constants for common HTTP status codes (200, 201, 202, 204, 301, 302, 304, 307, 308, 400, 401, 403, 404, 405, 409, 422, 429, 500, 501, 502, 503, 504) plus groupedImmutableArray<int>collections (Success,Redirection,ClientError,ServerError,All). The groups are singletons, so reading one allocates nothing.
Class Diagram
classDiagram
namespace Http {
class HttpGateway {
+HttpClient Client
+Task~HttpOutput~TBody~~ GetAsync~TBody~(string route)
+Task~HttpOutput~TBody~~ PostAsync~TBody~(string route, object? payloadObject)
+Task~HttpOutput~TBody~~ PutAsync~TBody~(string route, object? payloadObject)
+Task~HttpOutput~TBody~~ PatchAsync~TBody~(string route, object? payloadObject)
+Task~HttpOutput~TBody~~ DeleteAsync~TBody~(string route)
}
class HttpOutput~TBody~ {
+HttpStatusCode StatusCode
+HttpResponseHeaders Headers
+TBody? Body
+Task ReadContentAsync(CancellationToken)
}
class HttpExtensions {
<<static>>
+StringContent ToJsonStringContent(object @object)
}
class HttpStatusCodes {
<<static>>
+const int Ok
+const int Created
+const int Accepted
+const int NoContent
+const int MovedPermanently
+const int Found
+const int NotModified
+const int TemporaryRedirect
+const int PermanentRedirect
+const int BadRequest
+const int Unauthorized
+const int Forbidden
+const int NotFound
+const int MethodNotAllowed
+const int Conflict
+const int UnprocessableEntity
+const int TooManyRequests
+const int InternalServerError
+const int NotImplemented
+const int BadGateway
+const int ServiceUnavailable
+const int GatewayTimeout
+int[] Success
+int[] Redirection
+int[] ClientError
+int[] ServerError
+int[] All
}
}
HttpGateway --> HttpOutput : returns
HttpGateway ..> HttpExtensions : usesUsage
Basic GET request
using ArturRios.Util.Http;
var client = new HttpClient { BaseAddress = new Uri("https://api.example.com") };
var gateway = new HttpGateway(client);
var output = await gateway.GetAsync<List<Product>>("/products");
if ((int)output.StatusCode == HttpStatusCodes.Ok)
{
foreach (var product in output.Body!)
Console.WriteLine(product.Name);
}
POST with a payload
var newProduct = new { Name = "Widget", Price = 9.99 };
var output = await gateway.PostAsync<Product>("/products", newProduct);
if ((int)output.StatusCode == HttpStatusCodes.Created)
Console.WriteLine($"Created: {output.Body!.Id}");
PUT and PATCH
var update = new { Name = "Updated Widget" };
await gateway.PutAsync<Product>("/products/42", update);
await gateway.PatchAsync<Product>("/products/42", update);
DELETE
var output = await gateway.DeleteAsync<object>("/products/42");
if ((int)output.StatusCode == HttpStatusCodes.NoContent)
Console.WriteLine("Deleted.");
Status code groups
int code = (int)output.StatusCode;
if (HttpStatusCodes.Success.Contains(code))
Console.WriteLine("Request succeeded.");
else if (HttpStatusCodes.ClientError.Contains(code))
Console.WriteLine("Client error — check your request.");
else if (HttpStatusCodes.ServerError.Contains(code))
Console.WriteLine("Server error — try again later.");
Serialize a payload manually
var payload = new UpdateRequest { Name = "New Name" };
StringContent content = payload.ToJsonStringContent();
// UTF-8, application/json