简体   繁体   中英

Asana API C# Project Design

I am designing an API wrapper in C# for Asana , a project management solution. During the design process, I ran into a few roadblocks. I am wondering what a good way to design the API wrapper would be.

The Asana API I am integrating with works with REST. The requests return JSON.

There will be 6 data classes (User, Task, Project, etc), each containing a bunch of strings to hold the data returned from the REST requests. My first idea with these classes is to give them each factory Parse() constructors so I can easily pass in json and get a data object in return. I realize I can't extract the static factory methods into an interface.

I will have a REST request class that will manage sending and receiving data from the REST server. It will always return a JSON string.

Finally, I would like a AsanaAPI class that will contain methods to wrap those exposed on the REST server (ie GetUser, GetAllUsers, GetTask). Every method either returns a specific data class or an array of data classes. Here are the two cases:

    public User GetSingleUser(string userID = "me")
    {
        if(userID == "") throw new ArgumentException("UserID cannot be blank");

        string url = string.Format("{0}/{1}{2}", userUrl, userID, "?opt_fields=id,name,email,workspaces,workspaces.id,workspaces.name");
        JSONNode root = JSON.Parse(GetResponse(url))["data"];
        return User.Parse(root);
    }

    public List<User> GetAllUsers()
    {
        List<User> users = new List<User>();

        string url = string.Format("{0}{1}", userUrl, "?opt_fields=id,name,email,workspaces,workspaces.id,workspaces.name");
        JSONArray root = JSON.Parse(GetResponse(url))["data"].AsArray;
        foreach(JSONNode userRoot in root)
        {
            users.Add(User.Parse(userRoot));
        }

        return users;
    }

Each method will have that same format, but the User type will be replaced with Project, Task, etc. I want to extract the logic in these two methods because there will be many more methods with almost the exact same format.

In summary, the roadblocks I ran into were the fact that

  1. I can't extract the factory constructor method from the data class.
  2. I can't extract the parsing logic from the request methods

Is there something I can do with generics or is there just a better way of designing this project?

So I created a Parsable interface containing only a Parse method. Each data type implements Parsable. I was able to extract the parsing logic using generic types. It isn't the prettiest solution, but it does work.

    public User GetSingleUser(string userID = "me")
    {
        if(userID == "") throw new ArgumentException("UserID cannot be blank");

        string url = "{baseUrl}/users/{userID}?{opt_fields}".FormatWith(
            new { baseUrl = BASE_URL, userID = userID, opt_fields = "opt_fields=id,name,email,workspaces,workspaces.id,workspaces.name" });

        return (User)ParseJson<User>(AsanaRequest.GetResponse(url));
    }

    public User[] GetAllUsers()
    {
        string url = "{baseUrl}/users?{opt_fields}".FormatWith(
            new { baseUrl = BASE_URL, opt_fields = "opt_fields=id,name,email,workspaces,workspaces.id,workspaces.name" });

        return (User[])ParseJsonArray<User>(AsanaRequest.GetResponse(url));
    }

    public T ParseJson<T>(string json) where T : Parsable, new()
    {
        JSONNode root = JSON.Parse(json)["data"];
        T ret = new T();
        ret.Parse(root);
        return ret;
    }

    public T[] ParseJsonArray<T>(string json) where T : Parsable, new()
    {
        JSONArray root = JSON.Parse(json)["data"].AsArray;
        T[] nodes = new T[root.Count];
        for(int i = 0; i < root.Count; i++)
        {
            T newParsable = new T();
            newParsable.Parse(root[i]);
            nodes[i] = newParsable;
        }

        return nodes;
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM