API TestingPublished: Updated: · 2 months ago9 min read

RestSharp C# API Automation: Complete 2026 Guide

Complete RestSharp C# API automation guide for 2026. Setup, CRUD operations, authentication, schema validation, mocking, and CI/CD integration.

Avinash K
Founder & QA Engineer at SoftwareTestPilot
Share:XLinkedInWhatsApp
RestSharp C# API automation — flat editorial illustration of a code window sending HTTP requests through a CI/CD pipeline into a server stack.
RestSharp C# API automation — flat editorial illustration of a code window sending HTTP requests through a CI/CD pipeline into a server stack.

Last updated: June 27, 2026 · 9 min read

This guide covers everything you need to automate API testing with RestSharp in C#: setup, CRUD operations, authentication, schema validation, mocking, and CI/CD integration. Pair it with our API Testing Tutorial, RestSharp C# fundamentals, and REST Assured Java guide.

What is RestSharp?

RestSharp is a simple REST and HTTP API client for .NET. It wraps HttpClient with a fluent API that handles JSON serialization, authentication, and error handling out of the box. Docs: restsharp.dev.

Step 1 — Install RestSharp

dotnet new nunit -n RestSharpDemo
cd RestSharpDemo
dotnet add package RestSharp
dotnet add package Newtonsoft.Json

Step 2 — Your First GET Request

using RestSharp;
using NUnit.Framework;

public class UserApiTests
{
    private RestClient _client;

    [SetUp]
    public void SetUp()
    {
        _client = new RestClient("https://jsonplaceholder.typicode.com");
    }

    [Test]
    public void GetUserById()
    {
        var request = new RestRequest("/users/{id}", Method.Get);
        request.AddUrlSegment("id", "1");

        var response = _client.Execute(request);

        Assert.That(response.StatusCode, Is.EqualTo(System.Net.HttpStatusCode.OK));
        Assert.That(response.Content, Does.Contain("Leanne Graham"));
    }
}

Step 3 — Deserialize JSON

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
}

[Test]
public void GetUserByIdDeserialized()
{
    var request = new RestRequest("/users/{id}", Method.Get);
    request.AddUrlSegment("id", "1");

    var response = _client.Execute<User>(request);

    Assert.That(response.StatusCode, Is.EqualTo(System.Net.HttpStatusCode.OK));
    Assert.That(response.Data.Name, Is.EqualTo("Leanne Graham"));
    Assert.That(response.Data.Email, Does.Contain("@"));
}

Step 4 — POST Requests

[Test]
public void CreateUser()
{
    var request = new RestRequest("/users", Method.Post)
        .AddJsonBody(new
        {
            name = "Alice Johnson",
            email = "alice@example.com",
            role = "admin"
        });

    var response = _client.Execute(request);

    Assert.That((int)response.StatusCode, Is.EqualTo(201));
    var json = JObject.Parse(response.Content);
    Assert.That(json["email"]?.ToString(), Is.EqualTo("alice@example.com"));
}

Step 5 — PUT and DELETE

[Test]
public void UpdateUser()
{
    var request = new RestRequest("/users/{id}", Method.Put)
        .AddUrlSegment("id", "1")
        .AddJsonBody(new { name = "Alice Updated" });

    var response = _client.Execute(request);

    Assert.That((int)response.StatusCode, Is.EqualTo(200));
}

[Test]
public void DeleteUser()
{
    var request = new RestRequest("/users/{id}", Method.Delete)
        .AddUrlSegment("id", "1");

    var response = _client.Execute(request);

    Assert.That((int)response.StatusCode, Is.EqualTo(200).Or.EqualTo(204));
}

Step 6 — Authentication

Bearer Token

[Test]
public void AuthenticatedRequest()
{
    var token = GetAuthToken();
    _client.AddDefaultHeader("Authorization", $"Bearer {token}");

    var request = new RestRequest("/admin/users", Method.Get);
    var response = _client.Execute(request);

    Assert.That((int)response.StatusCode, Is.EqualTo(200));
}

private string GetAuthToken()
{
    var authRequest = new RestRequest("/auth/login", Method.Post)
        .AddJsonBody(new { email = "admin@example.com", password = "Sup3rSecret!" });

    return _client.Execute<TokenResponse>(authRequest).Data.Token;
}

public class TokenResponse
{
    public string Token { get; set; }
}

Basic Auth

_client.Authenticator = new HttpBasicAuthenticator("admin", "Sup3rSecret!");

Step 7 — Query Parameters

var request = new RestRequest("/users", Method.Get)
    .AddQueryParameter("page", "1")
    .AddQueryParameter("limit", "10");

Step 8 — Schema Validation

Use Newtonsoft.Json.Schema:

dotnet add package Newtonsoft.Json.Schema
[Test]
public void ValidateResponseSchema()
{
    var schemaJson = File.ReadAllText("schemas/user.json");
    var schema = JSchema.Parse(schemaJson);

    var request = new RestRequest("/users/{id}", Method.Get)
        .AddUrlSegment("id", "1");

    var response = _client.Execute(request);
    var json = JObject.Parse(response.Content);

    var isValid = json.IsValid(schema, out var errors);
    Assert.That(isValid, Is.True, $"Schema validation failed: {string.Join(", ", errors)}");
}

Step 9 — Reusable Client Setup

public class ApiClient
{
    public RestClient Client { get; }

    public ApiClient(string baseUrl)
    {
        Client = new RestClient(baseUrl);
    }

    public async Task<RestResponse<T>> GetAsync<T>(string resource)
    {
        return await Client.ExecuteAsync<T>(new RestRequest(resource, Method.Get));
    }

    public async Task<RestResponse<T>> PostAsync<T>(string resource, object body)
    {
        var request = new RestRequest(resource, Method.Post).AddJsonBody(body);
        return await Client.ExecuteAsync<T>(request);
    }

    public async Task<RestResponse> DeleteAsync(string resource)
    {
        return await Client.ExecuteAsync(new RestRequest(resource, Method.Delete));
    }
}

Step 10 — Mocking with WireMock

dotnet add package WireMock.Net
public class MockedApiTests
{
    private WireMockServer _server;
    private RestClient _client;

    [SetUp]
    public void SetUp()
    {
        _server = WireMockServer.Start(8080);
        _server.Given(Request.Create().WithPath("/api/users/1").UsingGet())
              .RespondWith(Response.Create()
                  .WithStatusCode(200)
                  .WithBody("{ \"id\": 1, \"name\": \"Mock User\" }"));

        _client = new RestClient("http://localhost:8080");
    }

    [TearDown]
    public void TearDown() { _server.Stop(); }

    [Test]
    public void TestAgainstMock()
    {
        var request = new RestRequest("/api/users/1", Method.Get);
        var response = _client.Execute(request);

        Assert.That((int)response.StatusCode, Is.EqualTo(200));
    }
}

See more options in our free API mocking tools roundup.

Step 11 — CI/CD Integration

GitHub Actions

name: RestSharp Tests
on: [push, pull_request]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-dotnet@v4
        with: { dotnet-version: '8.0.x' }
      - run: dotnet restore
      - run: dotnet test --logger "trx;LogFileName=results.trx"
      - uses: actions/upload-artifact@v4
        if: ${{ !cancelled() }}
        with:
          name: test-results
          path: TestResults/

For deeper pipeline patterns, see our CI/CD pipeline testing tutorial and GitHub Actions for automation testing guide.

Best Practices

Do

  • Use async/await for scalability
  • Validate response schemas on every test
  • Use mocks for external dependencies
  • Store credentials in secrets, not source
  • Track metrics (response time, error rate)

Don't

  • Don't hardcode URLs or credentials
  • Don't chain tests that depend on each other
  • Don't ignore HTTP error codes
  • Don't skip schema validation

Common RestSharp Mistakes and Fixes

Mistake 1 — Not using async

// BAD
var response = client.Execute(request);

// GOOD
var response = await client.ExecuteAsync(request);

Mistake 2 — Hardcoded URLs

// BAD
var client = new RestClient("https://api.example.com");

// GOOD
var baseUrl = Environment.GetEnvironmentVariable("API_BASE_URL") ?? "https://staging.example.com";
var client = new RestClient(baseUrl);

Mistake 3 — Ignoring HTTP status codes

if (!response.IsSuccessful) {
    Assert.Fail($"Request failed: {response.StatusCode} - {response.ErrorMessage}");
}

Mistake 4 — Not validating response schema

var schema = JSchema.Parse(File.ReadAllText("schemas/user.json"));
var body = JObject.Parse(response.Content);
Assert.That(body.IsValid(schema), Is.True);

Mistake 5 — Sharing state across tests

Use fresh client instances per test. Don't share state via static fields.

Mistake 6 — Not handling rate limits

public async Task<RestResponse> ExecuteWithRetry(RestRequest request)
{
    for (int i = 0; i < 3; i++)
    {
        var response = await client.ExecuteAsync(request);
        if (response.StatusCode != HttpStatusCode.TooManyRequests)
            return response;
        await Task.Delay(1000 * (i + 1));
    }
    throw new Exception("Rate limit exceeded");
}

Mistake 7 — Not logging failures

if (!response.IsSuccessful) {
    Log.Error($"Request: {request.Method} {request.Resource}");
    Log.Error($"Response: {response.StatusCode} {response.Content}");
}

Frequently asked questions

1.Is RestSharp still relevant in 2026?
Yes — RestSharp v110+ is actively maintained. It's the most popular HTTP client for .NET API testing.
2.RestSharp vs HttpClient — which should I use?
Use RestSharp for API testing (less boilerplate). Use HttpClient for production code (more control).
3.Can RestSharp deserialize JSON automatically?
Yes — pass a type to ExecuteAsync<T>() and RestSharp handles JSON deserialization.
4.How do I mock APIs in RestSharp tests?
Use WireMock.Net for full mocking, or stub responses with a local test server.
5.How do I handle rate limiting in tests?
Implement retry logic with exponential backoff, or use a sandbox API that doesn't rate-limit.
6.Is RestSharp free?
Yes — RestSharp is free and open source under the Apache 2.0 license.