DynamicRest - Getting Started
This article describes the basic conventions of the DynamicRest api. See advanced topics for mechanisms to bypass these conventions.
Conventions
- There are five Http verbs:
get
,put
,post
,patch
anddelete
, which are invoked as a normal method call - Http verb invocations are always
async
and return aTask<T>
, whereT
is a dynamic object - Named arguments passed to a verb invocation are Uri parameters
- Unnamed arguments passed to a verb invocation are request content
- Data Transfer Objects are serialized as JSON in both requests and responses
- Http status codes that do not indicate success throw a
DynamicRestClientException
Basic Usage
Using the dynamic rest client starts with instantiating an instance, accessing an endpoint path, invoking a REST verb, and await
ing the result. Always declare the DynamicRestClient
as
a dynamic
.
dynamic client = new DynamicRestClient("http://dev.virtualearth.net/REST/v1/");
dynamic result = await proxy.Locations.get(postalCode: "55116", countryRegion: "US", key: "api-key");
[Figure 1]
GET http://dev.virtualearth.net/REST/v1/Locations?postalCode=55116&countryRegion=US&key=api-key HTTP/1.1
Accept: application/json, text/json, text/x-json, text/javascript
Host: dev.virtualearth.net
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
Building the endpoint path
The endpoint path is represented by dot-separated members of the dynamic client instance. Each node in the path is another dynamic object to which additional path elements can be chained. The resulting path is relative to the base address set in the constructor of the client object.
The full endpoint Uri of the example in Figure 1 is:
http://dev.virtualearth.net/REST/v1/Locations/
dynamic google = new DynamicRestClient("https://www.googleapis.com/");
dynamic bucket = await google.storage.v1.b("uspto-pair").get();
[Figure 2]
The code in Figure 2 chains multiple elements together to build a longer path. It also uses an escape mechanism in order to specify a path element that is not a valid idenifier in C#. The resulting Uri is:
https://www.googleapis.com/storage/v1/b/uspto-pair/
note: Uri path segments are UrlEncoded
internally, so there is no need to escape them.
Passing parameters
Parameters are passed to the verb's invocation using C#'s named parameter syntax.
Any type of object can be passed as a parameter and will be serialized via the value object's ToString method. Both parameter names and values are Url encoded
The GET request for the example in Figure 1 is: http://dev.virtualearth.net/REST/v1/Locations/?postalCode=55116&countryRegion=US&key=api-key
Named parameters passed to a POST invocation will be form url encoded in the request body.
note: Both parameter names and values are UrlEncoded
internally, so there is no need to escape them.
Passing content
Request content is passed to the verb invocation as an unnamed argument. The first unnamed argument will be passed as the request content body. Subsequent unnamed arguments, with the exception of some special types, will be ignored.
- Strings and primitive types will be passed as StringContent
- Byte arrays will be passed as ByteArrayContent
- Any type of stream will be passed as StreamContent
- A
IEnumerable<object>
will be sent as multi-part content, with each constituent object being serialized by the above rules - All other types will be serialized to JSON
For example:
dynamic google = new DynamicRestClient("https://www.googleapis.com/calendar/v3/");
dynamic calendar = new ExpandoObject();
calendar.summary = "unit_testing";
var result = await google.calendars.post(calendar);
[Figure 3]
The resulting request shows the serialized content:
POST https://www.googleapis.com/calendar/v3/calendars HTTP/1.1
Authorization: OAuth xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Accept: application/json, text/json, text/x-json, text/javascript
Content-Type: application/json; charset=utf-8
Host: www.googleapis.com
Expect: 100-continue
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
Content-Length: 26
{"summary":"unit_testing"}
Invoking the Http verb
get
, put
, post
, patch
and delete
are the http verbs supported by this REST client. Invocation of the verb method
sends the appropriate http message to the endpoint, along with defaults, parameters and content. Verb methods are always
lower case and return a Task
object, so must be await
-ed. Unless using a strongly typed response
(see Advanced Topics), the return will be Task<object>
where the result type is a dynamic object.
Setting Defaults
Setting defaults to be included in every request is accomplished by passing a DynamicRestClientDefaults to the client constructor.
Api keys
Many REST apis require an api-key, often as a parameter included on all requests. Setting it as a default parameter will ensure it is added to every request.
var defaults = new DynamicRestClientDefaults();
defaults.DefaultParameters.Add("format", "json");
defaults.DefaultParameters.Add("api_key", "my-api-key");
defaults.DefaultParameters.Add("nojsoncallback", "1");
dynamic flickr = new DynamicRestClient("https://api.flickr.com/services/rest/");
dynamic user = await flickr.get(method: "flickr.people.findByUsername", username: "dkackman");
Authentication and authorization
For services that require authentication and authorization, the DynamicRestClientDefaults
type can also be used to
pass auth data.
var defaults = new DynamicRestClientDefaults()
{
AuthScheme = "OAuth",
AuthToken = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
};
dynamic google = new DynamicRestClient("https://www.googleapis.com/", defaults);
dynamic profile = await google.oauth2.v1.userinfo.get();
The auth data is added to every request.
GET https://www.googleapis.com/oauth2/v1/userinfo HTTP/1.1
Authorization: OAuth xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Accept: application/json, text/json, text/x-json, text/javascript
Host: www.googleapis.com
Accept-Encoding: gzip, deflate
Http Errors
In the event that the response message's IsSuccessStatusCode property
is false
, the invocation method will throw a
DynamicRestClientResponseException.
This exception includes the response message so that additional details of the falure can be inspected.