Basic API wrapper around a Restful service I'm writing a basic wrapper around a restful service that returns a list of Stores. I'm using RestSharp which I'm injecting into the class.

Naturally, I want to make it completely testable (that's a major requirement!).

I'm also thinking that it could be more generic i.e. GetStores but I'm struggling how to do as I need to specify things like the RootElement.

public class TopManClient : ITopManClient
{
    private readonly IRestClient _restClient;
    private const string BaseUrl = "https://TopmanStores.Api.com/";
    private const string AcceptTenant = "uk";
    private const string AcceptLanguage = "en-GB";

    public TopManClient(IRestClient restClient)
    {
        _restClient = restClient;

        _restClient.BaseUrl = new Uri(BaseUrl);
        _restClient.AddDefaultHeader("Accept-Tenant", AcceptTenant);
        _restClient.AddDefaultHeader("Accept-Language", AcceptLanguage);
    }

    public IRestRequest GetRequest(string url)
    {
        return new RestRequest(url, Method.GET);
    }

    public List&lt;Store&gt; GetStores(string postCode)
    {
        var request = GetRequest("stores");
        request.RootElement = "Stores";
        request.AddQueryParameter("q", postCode);

        var response = _restClient.Execute&lt;List&lt;Store&gt;&gt;(request);

        if (response.ErrorException != null)
        {
            const string message = "Error retrieving response. Check inner details for more info.";
            throw new ApplicationException(message, response.ErrorException);
        }

        return response.Data;
    }
}
I would personally prefer to use HttpClient directly as it provides full control and perfect testability - see here.

We can define our REST API as:

// see https://jsonplaceholder.typicode.com/
// this site exposes some REST API example to automate
public interface ITypicode
{
    Task&lt;BlogPost[]&gt; GetPostsAsync();
    Task&lt;BlogPost&gt; GetPostAsync(int id);
}

public class Typicode : JsonRestApi, ITypicode
{
    public Typicode(HttpMessageHandler handler = null)
        : base("https://jsonplaceholder.typicode.com", handler)
    {
    }

    public Task&lt;BlogPost[]&gt; GetPostsAsync() =&gt; GetAsync&lt;BlogPost[]&gt;("posts");
    public Task&lt;BlogPost&gt; GetPostAsync(int id) =&gt; GetAsync&lt;BlogPost&gt;($"posts/{id}");
}

public class BlogPost
{
    public int UserId { get; set; }
    public int Id { get; set; }
    public string Title { get; set; }
    public string Body { get; set; }
}


Where base class to simplify API definition is:

public abstract class JsonRestApi
{
    static readonly JsonSerializerSettings Settings = new JsonSerializerSettings()
    {
        ContractResolver = new CamelCasePropertyNamesContractResolver(),
        Converters = new [] { new StringEnumConverter() }
    };

    protected JsonRestApi(string baseAddress, HttpMessageHandler handler = null)
    {
        Client = handler == null ? new HttpClient() : new HttpClient(handler);
        Client.BaseAddress = new Uri(baseAddress);
        Client.DefaultRequestHeaders
            .Accept
            .Add(new MediaTypeWithQualityHeaderValue("application/json"));
    }

    protected async Task&lt;T&gt; GetAsync&lt;T&gt;(string uri) =&gt;
        await ParseJson&lt;T&gt;(await Client.GetAsync(uri));

    protected async Task&lt;T&gt; PostAsync&lt;T&gt;(string uri, object data = null) =&gt;
        await ParseJson&lt;T&gt;(await Client.PostAsync(uri, JsonContent.From(data)));

    protected HttpClient Client { get; }

    async Task&lt;T&gt; ParseJson&lt;T&gt;(HttpResponseMessage response) =&gt;
        JsonConvert.DeserializeObject&lt;T&gt;(await response.Content.ReadAsStringAsync(), Settings);

    class JsonContent : StringContent
    {
        public static JsonContent From(object data) =&gt;
            data == null ? null : new JsonContent(data);

        public JsonContent(object data)
            : base(JsonConvert.SerializeObject(data), Encoding.UTF8, "application/json")
        {
        }
    }
}


This code is fully testable.