Getting Started with RestClient.Net
RestClient.Net is a type-safe REST client for C# that brings functional programming patterns to HTTP communication. Instead of throwing exceptions, every call returns a Result type that you must explicitly handle.
Why RestClient.Net?
Traditional HTTP clients throw exceptions, which have problems:
- Invisible errors - Method signatures don't show what can go wrong
- Easy to forget - Miss a catch block and your app crashes
- Inconsistent handling - Try-catch scattered throughout the codebase
RestClient.Net solves this with discriminated unions:
// The return type tells you everything that can happen
Result<User, HttpError<ApiError>> result = await httpClient.GetUserAsync(...);
Quick Start
1. Install the Package
dotnet add package RestClient.Net
This includes:
HttpClientextension methodsResult<TSuccess, HttpError<TError>>types- The Exhaustion analyzer for compile-time checking
2. Define Your Models
// Success response
record Post(int UserId, int Id, string Title, string Body);
// Error response
record ApiError(string Message, string? Code = null);
3. Make a Request
using System.Net.Http.Json;
using RestClient.Net;
using Urls;
using var httpClient = new HttpClient();
var result = await httpClient.GetAsync(
url: "https://jsonplaceholder.typicode.com/posts/1".ToAbsoluteUrl(),
deserializeSuccess: async (content, ct) =>
await content.ReadFromJsonAsync<Post>(ct)
?? throw new InvalidOperationException("Null response"),
deserializeError: async (content, ct) =>
await content.ReadFromJsonAsync<ApiError>(ct)
?? new ApiError("Unknown error")
);
4. Handle the Result
Pattern match on the result to handle all cases:
var message = result switch
{
Outcome.Result<Post, Outcome.HttpError<ApiError>>.Ok(var post) =>
$"Success: {post.Title}",
Outcome.Result<Post, Outcome.HttpError<ApiError>>.Error(
Outcome.HttpError<ApiError>.ResponseError(var err, var status, _)) =>
$"API Error {status}: {err.Message}",
Outcome.Result<Post, Outcome.HttpError<ApiError>>.Error(
Outcome.HttpError<ApiError>.ExceptionError(var ex)) =>
$"Exception: {ex.Message}",
};
Console.WriteLine(message);
5. Add Type Aliases (Recommended)
The full type names are verbose. Add type aliases to GlobalUsings.cs:
global using OkPost = Outcome.Result<Post, Outcome.HttpError<ApiError>>
.Ok<Post, Outcome.HttpError<ApiError>>;
global using ErrorPost = Outcome.Result<Post, Outcome.HttpError<ApiError>>
.Error<Post, Outcome.HttpError<ApiError>>;
global using ResponseErrorPost = Outcome.HttpError<ApiError>.ErrorResponseError;
global using ExceptionErrorPost = Outcome.HttpError<ApiError>.ExceptionError;
Now pattern matching is cleaner:
var message = result switch
{
OkPost(var post) => $"Success: {post.Title}",
ErrorPost(ResponseErrorPost(var err, var status, _)) => $"API Error {status}: {err.Message}",
ErrorPost(ExceptionErrorPost(var ex)) => $"Exception: {ex.Message}",
};
Exhaustiveness Checking
The Exhaustion analyzer ensures you don't miss any cases:
// This won't compile!
var message = result switch
{
OkPost(var post) => "Success",
ErrorPost(ResponseErrorPost(...)) => "API Error",
// COMPILE ERROR: Missing ExceptionErrorPost case!
};
error EXHAUSTION001: Switch on Result is not exhaustive;
Missing: Error<Post, HttpError<ApiError>> with ExceptionError
Runtime crashes become compile-time errors.
What's in the Box
| Package | Description |
|---|---|
RestClient.Net |
Core library with HttpClient extensions and Result types |
RestClient.Net.OpenApiGenerator |
Generate type-safe clients from OpenAPI 3.x specs |
RestClient.Net.McpGenerator |
Generate MCP servers for Claude Code integration |
Exhaustion |
Roslyn analyzer for switch exhaustiveness (included) |
Next Steps
- Installation - Detailed setup instructions
- Basic Usage - GET, POST, PUT, DELETE examples
- Error Handling - Deep dive into Result types
- Advanced Usage - Retry policies, authentication, caching
- OpenAPI Generator - Generate clients from specs
- Code Examples - Complete working examples