-
Notifications
You must be signed in to change notification settings - Fork 15
Using the DynamicRestClient
The portable version of this code has both a client class and a proxy class that use System.Net.Http.HttpClient for communication.
The DynamicRestClient encapsulates the HttpClient instance and makes some assumptions about how to configure it to support the most common ways Rest APIs are constructed.
dynamic client = new DynamicRestClient("http://dev.virtualearth.net/REST/v1/");
var result = await client.Locations.get(postalCode: "55116", countryRegion: "US", key: CredentialStore.Key("bing"));
Assert.AreEqual(result.statusCode, 200);
Assert.IsTrue(result.resourceSets.Count > 0);
Assert.IsTrue(result.resourceSets[0].resources.Count > 0);
var r = result.resourceSets[0].resources[0].point.coordinates;
Assert.IsTrue((44.9108238220215).AboutEqual((double)r[0]));
Assert.IsTrue((-93.1702041625977).AboutEqual((double)r[1]));
The DynamicRestClient constructor has an optional parameter where calling code can supply default parameters and headers.
var defaults = new DynamicRestClientDefaults();
defaults.DefaultParameters.Add("key", CredentialStore.Key("bing"));
dynamic client = new DynamicRestClient("http://dev.virtualearth.net/REST/v1/", defaults);
var result = await client.Locations.get(postalCode: "55116", countryRegion: "US");
These defaults apply to any request made on any endpoint created from the root client object.
When invoking the http verb methods, unnamed arguments are added to the request body as content. The type of the argument is used to determine how to serialize the argument into the request body.
- Arguments of types Stream or StreamInfo are serialized as StreamContent
- Any argument of type byte[] will be serialized as ByteArrayContent
- Any argument that derives from HttpContent is passed directly to the request without modification (see below)
- A CancellationToken argument will be used so that requests can be cancelled if necessary
- All other types are serialized as json
Passing multiple unnamed arguments will result in MultiPartContent. Objects are serialized per the rules above in the order they are passed.
Named arguments are passed following the C# named arguments syntax. Named arguments are considered to be request parameters with the name being the parameter name and its value the parameter value.
dynamic client = new DynamicRestClient("http://openstates.org/api/v1/")
var result = await client.bills.get(state: "mn", chamber: "upper", status: "passed_upper");
Would result in the following endpoint url: http://openstates.org/api/v1/bills?state=mn&chamber=upper&status=passed_upper
By default POST request parameters are serialized to the request body as application/x-www-form-urlencoded. If a POST request parameter needs to be a url query parameter, wrap the value object in a PostUrlParam, which will force it to be part of the endpoint url.
var defaults = new DynamicRestClientDefaults();
defaults.OAuthToken = _token;
dynamic google = new DynamicRestClient("https://www.googleapis.com/", defaults);
using (var stream = new StreamInfo(File.OpenRead(@"D:\temp\test.png"), "image/png"))
{
dynamic result = await google.upload.storage.v1.b.unit_tests.o.post(stream, name: new PostUrlParam("test_object"), uploadType: new PostUrlParam("media"));
Assert.IsNotNull(result);
}
For all other request types named arguments result in query parameters.
Because the DynamicRestClient encapsulates the HttpClient there are a few of escape mechanisms to allow finer grained control over requests than might be implemented by convention.
The first is that the DynamicRestClient constructor can also take an optional callback method so calling code can perform any final configuration of an HttpRequest immediately before its invocation. If supplied, this callback will by called before each invocation of an http request. This allows the caller to set an additional request headers.
var oauth = new GoogleOAuth2("email profile");
// the cancellation token here is the one we passed in below
dynamic client = new DynamicRestClient("https://www.googleapis.com/oauth2/v1/userinfo", null, async (request, cancelToken) =>
{
var authToken = await oauth.Authenticate("", cancelToken);
request.Headers.Authorization = new AuthenticationHeaderValue("OAuth", authToken);
});
The second is that an HttpContent object can be passed directly as an unnamed argument. This allows the caller to configure any content headers. The HttpContent object will be passed directly to the request as is.
Lastly, if request parameter names conflict with C# keywords they cannot be passed using the named argument syntax. In this case, named arguments can also be passed as name value pairs in a dictionary.
dynamic client = new DynamicRestClient("http://openstates.org/api/v1/");
string key = CredentialStore.RetrieveObject("sunlight.key.json").Key;
var parameters = new Dictionary<string, object>()
{
{ "lat", 44.926868 },
{ "long", -93.214049 } // since long is a keyword we need to pass arguments in a Dictionary
};
var result = await client.legislators.geo.get(paramList: parameters, apikey: key);
Assert.IsNotNull(result);
Assert.IsTrue(result.Count > 0);