3

Public api:

getClients / getClientById - returns a json object like:

    { clientid: 1, name: "Client1" }

getProjects / getProjectById - returns a json object like
    { projectid: 5, name: "MyProject", clientid: 1}

Question: How do you design a library and set of objects to interact with this API specifically with the problem of how project contains the clientId. What I keep clashing against is that the project object contains a clientid so do I build my project object with just an ID or also a client object i.e

class Project
{
    int projectId ...
    string name ....

    int clientId....
    Client client // Not sure about this pattern as it wont always be initialized?
}

As a couple of solutions/ideas you could:

  • Force Project to take a Client object in the constructor but now you force a hit to the API before creating a project.
  • Not have the Client member in Project but now to use the library but does this make the object system harder to use?
  • Have the project object go grab the client from the API as needed

Concerns

  • Every time you are in a project object having to do a trip to the public API to get the client name.
  • When you are in a project object the client reference could be null (if you include it).
  • If the project knows how to get a client via the API the object now our code is becoming a jumbled mess.

How I handle this up to now

Keep the client and project objects as close to the API definitions as possible and in my API wrapper class build in some caching so I am not as bothered about calling it to get the client everytime I need it. Code is still not great though because it ends up looking like:

var project = apiWrapper.getProject(5)
out("This project belongs to client " + apiWrapper.getClient(project.clientId)
// note this call to getClient has cahcing in my implemtation
  • have you looked at how object-relational-mappers like (n)hibernate are doing this? (n)hibernate does not need to have a seperate project.clientId. instead it uses either eager loading (if loading a project then the client ist also loaded) or lazy loading meaning creating a client-item in project that only has the clientID set. once acceccing project.getClient() the client is loaded on demand. – k3b Nov 16 '14 at 21:54
1

Forget about the API to start with. Model your business domain, which means a Project has a Client: not a clientId, a Client.

Then, in the API, translate to and from the model and the external (JSON) view. That's one of the standard responsibilities of the API ("controller") layer. Of course, this approach only really makes sense if you're using an ORM (e.g. Hibernate) that will automate the synchronization and persistence of the model for you.

For create/update use cases, the API layer, or Data Access layer, should translate from IDs to actual objects, e.g. if the JSON Project has a clientId, lookup the Client with that ID and set it on the Project. The ORM itself is unlikely to do this for you: its job is to convert between tables/rows and your object model, not between JSON and your object model. Some app frameworks (e.g. Spring in the Java world) do things like this: parsing JSON and constructing your object model, using a suitable JSON parser. Usually, your JSON library would allow you to markup your code with annotations to specify how to map to/from JSON.

For the query use cases (e.g. getProject) the default JSON serialization should be to include referenced objects, e.g. a Project contains a 'client' property that is a sub-object in JSON format. However, there are 2 reasons to deviate from this and include only the sub-object's ID, not the whole object itself:

  1. Efficiency: if your request rates are very high and/or the sub-object is very large, and the typical client will not always use the sub-object detail
  2. Cycles: in the case where Project refers to Client, but Client also refers back to a list of Projects, you have a cycle. Typically, you can "break" these cycles using your JSON annotations (if any), or exposing only one side of the relationship in your model.
  • upvote. 1st paragraph is right on. Said another way: A database relational model is not a domain model. It's ok if a class contains a db table primary key - but for heaven's sake don't let the API user code screw around with primary keys! Encapsulate - i.e. "protect" - it in a class. The OP is not thinking OO, but DB. The database is merely an implementation detail. – radarbob Sep 6 '15 at 15:45
0

Why can't Client also contain its own id value? Then you will always use the Client object (it is, after all, the data you need) whilst still maintaining the id reference to use to uniquely identify that particular client.

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.