RESTCLIENT.NET
Menu
EN
↗ GitHub

RESTCLIENT.NET / FROM SOURCE TO REQUEST

Code you can run.

One example, compiled against RestClient.Net 7.3.1. The code below is the same source our checks exercise with local HTTP responses: success, HTTP errors, connection failures, JSON requests, and cancellation.

Start with a GET

The entry point fetches a post from JSONPlaceholder and prints an explicit result. Clone the repository, install the .NET 9 SDK, then run:

dotnet run --project Website/examples/Examples.csproj

This command makes a real request to JSONPlaceholder. The automated checks use a local message handler and make no HTTP requests.

Send JSON. Keep the result.

CreatePostAsync passes JsonContent.Create(request) as requestBody. Deserializers receive an HttpResponseMessage, so they read response.Content. The successful response becomes a Post; an HTTP failure preserves the response body as text.

Use your existing client factory

GetUsingFactoryAsync uses the named client posts. Register it with services.AddHttpClient("posts") in your application. Each call passes an absolute URL, and your registered handlers, authentication, and resilience configuration still apply.

Handle every outcome

Result.Match separates success from failure. HttpError.Match then handles HTTP responses and exceptions explicitly. The cancellation token is passed through every request and deserialization operation; a cancelled request is returned as an exception error.

Complete source

Both language versions render this single source file. The included Main runs the GET example; the POST and factory methods are ready to call from your application.

using System.Net.Http.Json;
using Outcome;
using RestClient.Net;
using Urls;

namespace WebsiteExamples;

public static class RestClientExamples
{
    // This runnable entry point calls JSONPlaceholder. Tests use a local handler instead.
    public static async Task Main()
    {
        using var client = new HttpClient();
        using var cancellation = new CancellationTokenSource(TimeSpan.FromSeconds(15));
        var result = await GetPostAsync(client, 1, cancellation.Token);
        Console.WriteLine(Describe(result));
    }

    public static Task<Result<Post, HttpError<string>>> GetPostAsync(
        HttpClient client,
        int id,
        CancellationToken cancellationToken = default
    ) =>
        client.GetAsync(
            url: $"https://jsonplaceholder.typicode.com/posts/{id}".ToAbsoluteUrl(),
            deserializeSuccess: ReadPostAsync,
            deserializeError: ReadErrorAsync,
            headers: new Dictionary<string, string> { ["Accept"] = "application/json" },
            cancellationToken: cancellationToken
        );

    public static Task<Result<Post, HttpError<string>>> CreatePostAsync(
        HttpClient client,
        CreatePost request,
        CancellationToken cancellationToken = default
    ) =>
        client.PostAsync(
            url: "https://jsonplaceholder.typicode.com/posts".ToAbsoluteUrl(),
            requestBody: JsonContent.Create(request),
            deserializeSuccess: ReadPostAsync,
            deserializeError: ReadErrorAsync,
            cancellationToken: cancellationToken
        );

    // Register a named client with services.AddHttpClient("posts") in your application.
    public static Task<Result<Post, HttpError<string>>> GetUsingFactoryAsync(
        IHttpClientFactory factory,
        int id,
        CancellationToken cancellationToken = default
    ) =>
        factory.GetAsync(
            clientName: "posts",
            url: $"https://jsonplaceholder.typicode.com/posts/{id}".ToAbsoluteUrl(),
            deserializeSuccess: ReadPostAsync,
            deserializeError: ReadErrorAsync,
            cancellationToken: cancellationToken
        );

    // Both success and failure are explicit. HTTP failures retain the response body.
    public static string Describe(Result<Post, HttpError<string>> result) =>
        result.Match(
            onSuccess: post => $"Post {post.Id}: {post.Title}",
            onError: error =>
                error.Match(
                    onException: exception => $"Connection failed: {exception.Message}",
                    onErrorResponse: (body, status, headers) => $"HTTP {(int)status}: {body}"
                )
        );

    // Deserialize<T> receives HttpResponseMessage: read its Content property.
    private static async Task<Post> ReadPostAsync(
        HttpResponseMessage response,
        CancellationToken cancellationToken
    ) =>
        await response.Content.ReadFromJsonAsync<Post>(cancellationToken)
        ?? throw new InvalidDataException("The response contained no post.");

    private static Task<string> ReadErrorAsync(
        HttpResponseMessage response,
        CancellationToken cancellationToken
    ) => response.Content.ReadAsStringAsync(cancellationToken);
}

public sealed record Post(int UserId, int Id, string Title, string Body);

public sealed record CreatePost(int UserId, string Title, string Body);

Keep exploring

HTTP methods and signatures · Client factory reference · Error-handling guide · Generate clients from OpenAPI