Since starting the project in Jan 2015, one of the most asked for features has been full static support (you have always been able to cast responses via duck typing). Inspired by libraries written in dynamic languages like JavaScript and Python - the idea behind RestClient was to reduce the fiction and ceremony when working with Rest API's, and later on HTTP in general.

I've always wanted to add static typing to be more inline with what is expected from a C# library, but wanted to do it in a way that the original concept remained, and that all code is backwards compatible. I've now spent the time required to change the package, and this is the result:

DalSoft Rest Client https://github.com/DalSoft/DalSoft.RestClient

Getting Started with static types in Rest Client 4.0

There is one fundamental change you need to make in your code to take the static typing Blue pill: you need to declare the Rest Client as RestClient or var, rather than dynamic.

// Red pill dynamic rest client dynamic restClient = new RestClient("https://jsonplaceholder.typicode.com"); // Blue pill static rest client var restClient = new RestClient("https://jsonplaceholder.typicode.com"); // Or restClient restClient = new RestClient("https://jsonplaceholder.typicode.com");

So far, nothing looks radically different, but check out the fully chained intellisense in Visual Studio.



Resources

The only limitation with the statically typed client is you can't use dynamic chaining to create the url, instead you use the Resource method. The Resource method works exactly the same way as it does, when using the dynamic Rest Client, it takes a string representing the resource. When using the statically typed client, it also takes an expression more on this later.

var restClient = new RestClient("https://jsonplaceholder.typicode.com"); await restClient.Resource("users/1").Get(); // You can also chain Resource methods to make code more readable await restClient.Resource("users").Resource("1").Get();

Headers

Headers work exactly the same way as the dynamic Rest Client, you either pass an anonymous object or a Header dictionary to the Headers method.

var restClient = new RestClient("https://jsonplaceholder.typicode.com"); // Header dictionary await restClient .Headers(new Headers { { "Content-Type", "text/html" } }) .Resource("users/1").Get(); // Or anonymous object await restClient .Headers(new { ContentType = "text/html" } ) .Resource("users/1").Get();

Query String

Again, Query Strings work exactly the same way as the dynamic Rest Client, you pass an anonymous object to the Query method. Like the dynamic Rest Client arrays are supported.

var restClient = new RestClient("https://jsonplaceholder.typicode.com"); // Header dictionary await restClient .Query(new { id = 1 }) .Resource("users/1").Get();

Casting Request body / Responses

The cool thing with the static Rest Client is you can take advantage of the dynamic Rest Client's duck typing which gives you the best of both worlds.

var restClient = new RestClient("https://jsonplaceholder.typicode.com"); // Posting and casting using duck typing User user = await restClient .Resource("users") .Post(new { id = 1, name = "William Windsor" });

You can also use more traditional generics.

var restClient = new RestClient("https://jsonplaceholder.typicode.com"); // Posting and casting using generics var user = await restClient .Resource("users") .Post<User, User>(new { id = 1, name = "William Windsor" }); // For completeness http Get using generics var user = await restClient .Resource("users/1") .Get<User>();

Or mix generics and duck typing

var restClient = new RestClient("https://jsonplaceholder.typicode.com"); // Post using generics and cast the response using duck typing User user = await restClient .Resource("users") .Post(new User { Id = 1, Name = "William Windsor" }); // Cast the response to HttpResponseMessage using duck typing HttpResponseMessage response = await restClient .Resource("users") .Post(new User { Id = 1, Name = "William Windsor" });

Extensions

You have always been able to add extensions using the dynamic Rest Client like so:

public static class RestClientExtensions { // Dynamic Rest Client extension public static async Task<User> GetUserByIdDynamic(this RestClient restClient, int id) => await ((dynamic)restClient).users(id).Get(); }

This isn't exactly obvious as you have to cast back to a dynamic. Using the static version of the Rest Client creating extensions has been formalized and simplified. This is done using Resource classes...

Extending Using Resource Classes

A resource class is just a POCO class that has methods and properties returning strings. The string represents a resource appended to base url. You pass the Resource class as a generic to the Resource method, and then pass expression returning the Resource you want to act on.

public class UsersResources { public string Departments => $"users/{nameof(Departments)}"; public string GetUser(int id) { return $"users/{id}"; } } var restClient = new RestClient("https://jsonplaceholder.typicode.com"); // GET /users/departments var user = await restClient.Resource<UsersResources> ( resource => resource.Departments ) .Get(); // GET /users/1 var user = await restClient.Resource<UsersResources> ( resource => resource.GetUser(1) ) .Get();

As you can see, it's trivial to create a maintainable and readable REST SDK's, so you don't have to resort to code generation generating horrible code. Any expression that returns a string should work, and nesting is supported.

Bonus Items

In version 4.0, I added a couple of bonus items:

HttpClient

Using either a dynamic or static Rest Client you can cast back to an HttpClient.

var restClient = new RestClient(BaseUri); HttpClient httpClient = restClient; var httpClientResponseString = await restClient.HttpClient.GetStringAsync(client.BaseUri + "/users/1");

Or access using the HttpClient property

var restClient = new RestClient(BaseUri); var httpClientResponseString = await restClient.HttpClient.GetStringAsync(client.BaseUri + "/users/1");
Authorization method

I also added an Authorization method that adds the Authorization header for Basic or Bearer Authorization Schemes. This works with dynamic or static clients.

var restClient = new RestClient(BaseUri); // Bearer Token await restClient.Authorization(AuthenticationSchemes.Bearer, "MyBearerToken").Get(); // Basic Authorization await client.Authorization(AuthenticationSchemes.Basic, "MyUserName", "MyPassword").Get();