Using C# to Implement a Fluent Interface to Any REST API


May 26, 2016
Written by
Elmer Thomas
Contributor
Opinions expressed by Twilio contributors are their own

 

All 7 SendGrid API client libraries have been updated to contain as few dependencies as possible. Part of this effort entailed creating brand new, lean HTTP clients to drive communication with our APIs. The last HTTP client I wrote about was PHP, and in this post we will explore our new C# HTTP client that drives our new v7 SendGrid C# library, using a working prototype.

The remainder of this post will reference the following code:

Fluent Interfaces

A fluent interface allows us to create API calls dynamically, without the need to pre-define every endpoint. For example, we can use `client.path.to.the.endpoint.get()` for a call to: `GET /path/to/the/endpoint` without having to define methods for `path`, `to`, `the`, and `endpoint`.

Method Chaining

To chain our method calls together, in general, we simply return `this`. However, in this case we are returning a new version of the `Client` object, because we want to preserve fragments of the URL for later reuse see line 29.

Reflection

To capture the method calls dynamically, we need to use C#’s dynamic `TryGetMember` C# docs method, which is called whenever the object can't find the method you are calling see line 20. We end the chain by trying to invoke the method, using C#’s dynamic `TryInvokeMember` C# docs method See line 43.

Handling Special Cases

To handle special cases or allow users to specify a complete path as a string, we use the `_()` method see line 32. You pass in a string and receive a new object with the name of your string added to the URL path variable.

References & Acknowledgements

The following references helped me understand the concepts described in this post: Thank you for dropping by, and if you decide to build something with this library or have some contributions, please open an issue.

What’s next? Stay tuned as we continue to release similar blog posts for all the other languages we support Python, PHP, Ruby, Node.js, Go, and Java.

Send With Confidence

Partner with the email service trusted by developers and marketers for time-savings, scalability, and delivery expertise.

using System;
using System.Dynamic;
namespace Fluent
{
class Client : DynamicObject
{
public string UrlPath;
public Client(string urlPath = null)
{
UrlPath = (urlPath != null) ? urlPath : null;
}
private Client BuildClient(string name = null)
{
string endpoint;
if (name != null)
{
endpoint = UrlPath + "/" + name;
}
else
{
endpoint = UrlPath;
}
UrlPath = null; // Reset the current object's state before we return a new one
return new Client(endpoint);
}
public Client _(string name)
{
return BuildClient(name);
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = BuildClient(binder.Name);
return true;
}
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
result = UrlPath;
return true;
}
}
class Program
{
static void Main(string[] args)
{
dynamic client = new Client();
dynamic chain = client.hello.world;
Console.WriteLine(chain.UrlPath);
Console.ReadLine();
dynamic new_chain = chain.thanks._("for").all.the.fish;
Console.WriteLine(new_chain.method());
Console.ReadLine();
}
}
}
view raw Fluent.cs hosted with ❤ by GitHub