The Canopy API is very bare and requires the consumer to understand how to encode the account ID and key and to understand a hand-full of undocumented nuance in order to successfully make API calls. This library wraps around the API and provides the consumer with a more streamlined and fluent experience.
- Canopy Api Documentation the US hostname is usapi.canopyapp.net
INTERFACE | IMPLEMENTATION | Description |
---|---|---|
ICanopySearchService | CanopySearchService | Get a list of business objects of type T. Supports sorting, filtering, and paging. |
ICanopyRetrieveService | CanopyRetrieveService | Get a specific business object of type T. Supports selecting by UUID, Code, and Gtin. |
Note: each service must be restricted to a specific business object using the "...Service" notation.
Supported business objects defined by class models:
- Media
- Product
Note: the dependency injection approach is recommended due to the configuration required. Alternatively, code a static class that handles the configuration and is used throughout the application.
The DI framework should provide a mechanism for registering services. This DLL provides a succinct way to register all implemented Canopy services in an ASP.NET Core application by following these steps.
- Find the ConfigureServices method in the startup.cs file.
- Add the following code:
services.AddCanopyServices(
new Uri("<Canopy base URI>"),
new Account()
{
UUID = "<Account UUID>",
HMACSHA256_APIKey = "<HMACSHA256_APIKey>"
},
<optinal-webproxy>);
- Inject an implemented Canopy service's interface using one of the following approaches; note that the ICanopySearchService is used as an example:
In a .razor file, inject the service directly using the following code; note that the using statement can optionally be included in central "_Imports" file:
@using Canopy.Provider.Interfaces
//@inject INTERFACE PropertyName
@inject ICanopySearchService<Media> ProviderMediaService
In a .razor.cs file, inject as a property using the following notation
[Inject]
//private INTERFACE PropertyName { get; set; }
private ICanopySearchService<Media> ProviderMediaService { get; set; }
in a plain old csharp object (POCO), inject the property in the constructor. Note that the POCO should, itself, be injected or should be retrieved from the DI framework:
public class POCO{
//private readonly INTERFACE FieldName;
private readonly ICanopySearchService<Media> ProviderMediaService;
//public POCO(INTERFACE parameterName)
public POCO(ICanopySearchService<Media> ProviderMediaService)
{
this.ProviderMediaService = ProviderMediaService;
}
}
The Canopy.Provider.CanopyServiceProvider class has a static method for retrieving the configured http client in the following way.
var uri = new Uri("<Canopy base URI>");
var acct = new Account()
{
UUID = "<Account UUID>",
HMACSHA256_APIKey = "<HMACSHA256_APIKey>"
};
//var service = Canopy.Provider.CanopyServiceProvider.GetService<INTERFACE, IMPLEMENTATION>(uri, acct, <optinal-webproxy>);
var service = Canopy.Provider.CanopyServiceProvider.GetSearchService<ICanopySearchService<Media>, CanopySearchService<Media>>(uri, acct);
The services in this library abide by a fluent programming style which basically means that the developer attempted to create an experience that flows logically and intuitively
by stacking small, specialized interfaces that expose only those methods that are appropriate.
See the following documentation for further reading on this topic:
Fluent Code in C#
Tips:
- A service is lazy and will only perform an action when the ".Get()" method is executed.
- The services return Task rather than T. It is recommended that these services be consumed using the "await" keyword.
Example of getting the first "qty" Media business objects
async Task GetMedia(int qty)
{
try
{
List<Media> media = await SearchMediaService
.WithBatchsize(qty)
.GetBatchNumber(0)
.Get();
}
catch (Exception ex)
{
Logger.LogError(ex.Message);
throw;
}
}
Supports T values:
- Media
- Product
Defaults to 25
Limits the number of returned business objects to be at most "qty".
where n >= 0
Defaults to 0
Used for paging, this is required when WithBatchSize is used; returns page n. Alternatively, this can be thought of as returning items in the range
[nq + 1, nq + q] where n is the batchNumber or page and q is the batchSize
While this looks complicated, the usage is simple. The Expression is a means to prompt the IDE to allow the developer to select a strongly typed property.
- Select the property (strongly typed generated from the business object).
- Select the comparator (strongly typed generated from the enum Comparator).
- Define the filter criteria.
Note that Like also serves as Equals when the wildcard symbol (%) is omitted.
Comparators | Comments |
---|---|
Like | serves as Equals when the wildcard symbol (%) is omitted |
GreaterThan | Only works on numerical properties |
GreaterThanOrEqualTo | Only works on numerical properties |
LessThan | Only works on numerical properties |
LessThanOrEqualTo | Only works on numerical properties |
List<Product> product = await SearchProductService
.Where(x => x.Description, Comparator.Like, "%Corned Beef%")
.Get();
OrderBy(Expression<Func<T, TKey>> keySelector) and OrderByDescending(Expression<Func<T, TKey>> keySelector)
Similar to the Where method, while this looks complicated, the usage is simple. The Expression is a means to prompt the IDE to allow the developer to select a strongly typed property.
If we wanted to reverse order the Where method's request by the Product object's Code property, we would add a single line:
product = await SearchProductService
.WithBatchsize(6)
.GetBatchNumber(0)
.Where(x => x.Description, Comparator.Like, "%Corned Beef%")
.OrderByDescending(x => x.Code)
.Get();