0

I need to access and process different resources from a REST API. For this I've come up with two different approaches:

Approach 1:

Create one class per resource, that handles accessing the data from the API.

public class User {
  String name;

  public static User getUserFromApi() {
    //access API, set Attributes, parse JSON result
  }

  public Response createUser() {
    //access API
  }
}

Approach 2:

Create two classes per resource: one that handles API access, and the other one is a class representation of the resource.

public class User {
  String name;
  public User(String name) {
    this.name = name;
  }
}

public class UserApi {
  //should this return a Response or a User and handle JSON parsing?
  public Response get() {
    //access API
  }

  public Response create() {
    //access API
  }
}

In my opinion, the second approach looks better (separation of concerns) and leads to smaller classes. Now I have a few questions about this:

  • Is this approach considered good software quality?
  • Where should I do the parsing? In the UserApi class or should I create a different constructor in the User class that parses the response?
  • For the second approach should I create different packages for the User (com.example.resource) and UserApi (com.example.api) classes?
3
  • 1
    Do you mean public static User getUserFromApi in your first example? Otherwise how do you get a User to call getUserFromApi on?
    – Caleth
    Oct 22 '21 at 9:58
  • @Caleth: of course I meant it to be static, updated it in the question.
    – sininen
    Oct 22 '21 at 10:08
  • @Caleth: I don't advocate for it (at all), but I've seen people do things like new User().getUserFromApi(). I think it's ugly but it does compile and work.
    – Flater
    Oct 22 '21 at 10:13
1

Create two classes per resource: one that handles API access, and the other one is a class representation of the resource.

This is my preference. The supporting argument is based on Parnas 1971.

Briefly summarized: "Each module in the second decomposition is characterized by its knowledge of a design decision which it hides from all others".

It's not mandatory, of course. As Parnas noted: "both schemes will work" -- the java runtime cares very little about how your source code is organized, and whether or not that source code is optimized for the activities of the human maintainers.


Create two classes per resource: one that handles API access, and the other one is a class representation of the resource.

This feels very strongly two me like two different design decisions. The schema of our representations is part of the contract (be it implicit or explicit) that our client has with the API.

The actual API access might interact with the API by directly manipulating HTTP requests and responses, or it might interact with the API via a headless web browser. That's a sort of design decision that you should want to hide from your other modules. Notice that it is purely an implementation concern - it can change independently of the API contract itself.

Parsing, I would guess is going to turn into another module.

a parser is just a function that consumes less-structured input and produces more-structured output. -- Alexis King, 2019

How we convert a stream of bytes (less-structured) into an in memory representation of domain information (more-structured) is again a separate design decision. We'd be deciding, for example, whether we should be treating our serialized JSON as a single Document to be loaded "all at once", or a stream of events to be considered each in turn.


For the second approach should I create different packages

This is a fantastic question; and in 20 years of searching I haven't found satisfactory literature to address it.

I think you can be confident that circular dependencies between packages are going to be a bad idea. Beyond that... the opinions I've found have a lot more idealism/wishing than supporting evidence.

That said, you may want to look into the module system in detail and consider the implications on your package design.

2

You're going to find conflicting opinions here.

Some people really dislike anemic models and advocate that OOP code should not separate its data and behavior into separate classes. I'm not as allergic to anemic models, at least to some degree. I think a healthy balance should be struck, and it shouldn't be black nor white.

I would opt for separating the two here. This means that you can encapsulate the handling of your external API into the UserApi class (which I would call UserApiService), whereas the User object contains no trace of the external API and can be passed around your codebase without risking it leaking any api-specific dependencies/syntax on its journey through the codebase.

Separating them also helps you with testability. Your code (and tests) can use the User type without needing to worry that it might call the real API. If you don't separate them, then you run that risk.
You could inject a mockable dependency in User to avoid this, but then you've really already separated the User from its api-calling logic (since it needs to be injected), and I really dislike the notion of needing to inject a service into a DTO.

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.