Skip to content
AnthonySteele edited this page Oct 25, 2014 · 6 revisions

#Usual usage

The usual pattern of using the 7digital Api wrapper is like this:

Release charts endpoint:

var chart = await Api<ReleaseChart>.Create.Please();

Track details endpoint:

var track = await Api<Track>.Create
   .ForTrackId(12345)
   .Please();

Release details endpoint:

var request = Api<Release>.Create
    .ForReleaseId(1685647)
    .WithParameter("country", "GB");
var release = await request.Please();

The pattern has three parts:

  1. it starts with a Create which specifies the endpoint type. We have a type for each endpoint in the API. This type and the attributes on it define the data returned, the url of the API endpoint, the http method to use and the authentication needed. The Create returns a new fluent Api object.

  2. The fluent Api is used to specify some parameters using WithParameter(string name, string value) or the extension methods that wrap it, such as ForReleaseId(int id) and ForTrackId(int id). The necessary parameters depend on the endpoint. Some such as the Release/charts endpoint have no mandatory parameters at all; release requires a release id, and so on. These methods chain, i.e. Each one alters and returns the same fluent Api object.

  3. It ends with Please() which sends the request and returns an awaitable Task for the result data.

Pitfalls

Shared state

Do not re-use requests. If you re-use requests, you may get unpredictable, timing-dependant errors when one request overwrites the other request's state.

Do this:

var track1 = await  Api<Track>.Create.ForTrackId(firstId).Please();
var track2 = await  Api<Track>.Create.ForTrackId(secondId).Please();

Do not do this:

var badlySharedRequest = Api<Track>.Create;
var track1 = await badlySharedRequest.ForTrackId(firstId).Please();
var track2 = await badlySharedRequest.ForTrackId(secondId).Please();

Styles

These two code snippets are exactly equivalent:

var request = Api<ReleaseChart>.Create;
var chart = await request.Please();

and

var chart = await Api<ReleaseChart>.Create.Please();

You should use whichever of the two you prefer.

Dependencies

Consuming applications need to provide a concrete implementation of IApiUri and IOAuthCredentials in order to authenticate with the 7digital Api. Otherwise wrapper will throw MissingDependencyException.

Handling Errors

There are a number of reasons you may experience an error when using the API wrapper. All exceptions inherit from ApiException but it is probably not a good idea to have a blanket catch all for these exceptions when calling the wrapper as it will mask potential other issues.

These conditions can be broken down into 2 categories, those which indicate an error thrown in the protocols which the API relies on (TCP, HTTP, OAuth) and those which are indicated by an error status response from the API:

API errors

These are represented as classes derived from ApiErrorException

  • The release you are requesting no longer exists or is not available in the territory
  • You supplied an incorrect value for a parameter etc etc

You should catch and inspect each of the relevant types of error at the callsite for the endpoint you are calling and take appropriate action. See the API documentation for a full list. Each range of error codes maps to a different exception type.

HTTP errors

These will be either NonXmlResponseExceptions or OAuthExceptions

  • The API is down for maintenance or failing in some way
  • The OAuth credentials you have supplied are not valid
  • The OAuth token you are using has expired
  • You have overriden a URL with something which does not exist etc etc

A generic application catchall for NonXmlResponseException is sensible as it indicates problems with the 7digital API.

OAuthExceptions will require special attention and testing as it could be either a problem with the user's access token, the user not authenticating your application or an attempt to access premium API resources without your application being granted the correct permissions.

Notes

A Schema type knows about its endpoint via the [ApiEndpoint] attribute, e.g

[ApiEndpoint("artist/details")]
public class Artist{}

Also - you can apply the following to a type to specify if the endpoint requires oauth:

[OAuthSigned]
public class OAuthRequestToken{}

See example usage console app project for some more examples.