My team has been doing a lot of REST API consumption, and our favorite tool to use for that is the terrific RestSharp Library. Our latest project is very large and uses lots of different APIs, and so we needed a way to create many different client classes that could consume many different APIs but still use common features like caching and error logging.
And so, I present to you, the Ultimate RestSharp Client!
In this post, we'll build a RestSharp client which can serve as a base class to many other clients who need to consume RESTful APIs. Said base class will need to implement common functionality (e.g. the aforementioned caching and error logging) and be able to deserialize known objects in which the APIs return. Come along with me as I condense a week's worth of research and coding into one 1700-word blog post and build the Ultimate RestSharp Client!
Requirements
The awesome RestSharp client that we're going to build needs to support the following scenarios:
- Deserialize objects using an injected serializer.
- Store into and retrieve from a cache.
- Check for timeouts.
- Use custom injected error logging.
Before we build our ultimate RestSharp client, let's first define the three items which need to be injected into the client.
Cache Service
Here's our simple cache service interface and implementation:
using using public {
} public {
} |
Deserializer
As of recently, RestSharp no longer requires JSON.NET as its default serializer (see this readme). So, we must inject a serializer into our ultimate client, which will use JSON.NET anyway because that's what I like. I stole the following class from this fantastic blog post and it's worked pretty well for us.
using using using using public {
} |
Error Logger
This is the simplest of the three injection prerequisites. You will want to replace this implementation with one of your own design. Here's a very basic error logger interface and class:
public {
} public {
} |
With all three prerequisite items in place, we can now start to code our ultimate RestSharp client!
Class and Constructor
In order to build our ultimate RestSharp client, we'll first need a class that inherits from RestSharp's RestClient class:
We also need a constructor to inject our three prerequisite classes into this client, as well as a base URL for which each child client will be using for their APIs. Such a constructor looks like this:
using using using using public {
} |
Note that we are using JSON for this ultimate client. You can use other formats (e.g. XML), but I prefer JSON for this kind of client so that's what we'll use here.
Once we've got the constructor build, it's time to start coding the guts of our ultimate client, starting with...
Error Logging
We have two different kinds of error logging in this system: the generic error logging and the more specific Timeout checks. We implemented timeout checks in an earlier post, go check that out if you want more details. For now, here's some code to accomplish each of these.
private {
} private {
} |
Get and Execute
Once we've got the error logging in place, we can now discuss the kinds of operations we want this client to be able to perform. In our client, there are three possible actions that the client can perform against the API:
A basic EXECUTE operation, which will return an
IRestResponse
, which is the generic Response interface defined by RestSharp.
GET operation, which will call the EXECUTE operations and return a deserialized class.
GET FROM CACHE operation, which will check the cache service for a matching object, return that object if it exists, or call the EXECUTE operations if it doesn't.
EXECUTE
Because the GET operations will call the EXECUTE operations and will return deserialized objects, we need both generic and non-generic versions of the EXECUTE operations. Here's those EXECUTE operations, which override the underlying RestSharp methods and call the TimeoutCheck()
method from earlier:
public {
} public {
} |
GET
The GET operation is just a tiny bit more complex. It must check the status code of the response, and if that code is 200 OK it will deserialize an object; otherwise, it must log an error and return a default instance of the class it is trying to deserialize. We can do this via a generic method, like so:
public {
} |
GET FROM CACHE
The GET FROM CACHE methods are more complex still, though they really just add an extra step onto the GET operations:
public {
} |
The Complete Client
For posterity's sake, here's the complete code for the ultimate RestSharp client:
using using using using public {
} |
Yooo, Now Restsharp client is ready for you
Using the Awesome RestSharp Client
To use this client, we treat it as a base class for other clients. Let's imagine that we have the following object which will be returned by our API:
public {
} |
We also have APIs at the following URLs which will return this object or a collection of this object:
/users/{id}
/users/all
We can build a client for this situation very easily with our Ultimate RestSharp Client. First, we need to inherit from our BaseClient
class and implement the constructor:
public {
} |
Then we need to create two methods, one which will get the users by ID and one which will get all the users. Let's add a further requirement and say that the method which will get the users by ID will have its results be cached. The complete UsersClient
now looks like this:
public {
} |
That's all there is to it! Now if you have many client classes, they can all share the same base class and easily implement error logging and caching!
Summary
This Ultimate RestSharp client is already in use in one of our biggest projects, and it's saved us so much time and effort once we got it together. I hope it helps you all out as well, dear reader!
As always, I welcome suggestions on how to improve the code in this post. Let me know if you've got any ideas in the comments!
Happy Coding!