1

We are creating an office application in C#.

Originally, the persistent data like customer details, orders, agenda, statistics, etc. were stored in a local SqlServer database on a server. The application runs on a single computer and acts as a client. The app grew and became bigger but still maintainable until some decisions were made to move all data to a hosted server. On the server side we created an API and the intention is that the client application uses the API endpoint to save/load the data to/from the client application. For the data layer in the client application we use the repository design pattern (to summarize it in one term).

Now I'm looking for a good class design to make API calls clear and consistent. My plans were to organize it like the repositories in our repository design. So a Customer repository would internally make a call to the API endpoint, and return the data to the user code. But we would like to create an extra layer for the whole API tasks. How we wanted to approach it is as follows: One class that represents the API endpoint, which stores the endpoint base URL, API token, etc. And for each kind of business things like customers, orders, agenda we create a class for the api calls that load customer data, order data, and so on. By this we mean classes like:

APIEndpoint

APICall (base class), with sub classes:
    - CustomerCall
    - OrderCall 
    - AgendaCall
    - ...

In the API call base class we can define some defaults, like automatically adding the authentication headers/parameters to the call.

APIEndpoint gets an API call and cares about actually sending it over the network. What we want to avoid is spreading literal strings of API call URL's all over the code with ugly string building for filling in GET parameters or POST data.

I would greatly appreciate any help or push in the right direction. What would you change about our current approach. What could possibly be pitfalls?

  • Is the point of this API to support low-level CRUD operations (create, read, update, delete) or higher-level business operations? – John Wu Dec 9 '19 at 22:28
  • 1
    Mainly low-level CRUD operations. – user2190492 Dec 9 '19 at 22:44
2

How about having several EndPoint Interfaces. They just describe the connection string to a given end-point including http method (get/put/post/...).

something like:

class EndPoint
{
    URL path { get; }
    HTTPMethod method { get; }
    //other salient points of information
    List<Permissions> requiredPermissions { get; }
    bool authorisationTokenRequired { get; }
}
interface ICustomerEndPoints
{
    EndPoint create { get; }
    EndPoint update(guid customerId);
    EndPoint find(string searchText);
    EndPoint retrieve(guid customerId);
    EndPoint delete(guid customerId);
}
interface IProductEndPoints
{
    EndPoint create { get; }
    EndPoint update(guid customerId);
    EndPoint find(Region region);
    EndPoint find(MajorCategory category, string freeText);
    EndPoint retrieve(guid customerId);
    EndPoint delete(guid customerId);
}
class EndPoints
   : ICustomerEndPoints
   , IProductEndPoints
{
    EndPoint IProductEndPoints::create { get; } //<implemented in terms of below.
    ...

    private string baseURL;
    //or
    private EndPoint ProductCreateEndPoint = new EndPoint(....);
    //or whatever backing method
}

This allows flexibility in how you construct the end point information.

That information is then passed into Agents. These implement and hide the actuall activity of calling through to the api, and can even be wrapped with caches/buffers to speed things up/permit offline usage.

class CustomerAgent
{
    Customer operator[](guid customerId) {... calls endpoint etc... }
    List<Customer> find(string searchText) { ... }
    ...

    private ICustomerEndPoints _endPoints;
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.