REST logic with Clean Architecture

198 views
Skip to first unread message

Konstantin Shilovsky

unread,
Jan 15, 2015, 5:31:07 AM1/15/15
to clean-code...@googlegroups.com
I am experimenting with Clean Architecture in my project and want to implement simple REST communication logic. I've started with simple "user login" use case. I am curious if my understanding of boundaries crossing is correct.
The main goal is to implement communication between network and business(use case) layers.
So here is the structure I plan to have: 
LoginInteractor - business layer
LoginProcessor - interface from Network layer
NetworkLoginProcessor - implementation of LoginProcessor

LoginInteractor will hold the reference to LoginProcessor(interface). LoginProcessor will have one method login(name, password) which returns UserEntity or throws an exception. 
I am not sure how to deal with the exceptions since they may occur due to different reasons. I am thinking of introducing UserLoginError  and have specific error as the cause. For example:

public class UserLoginError extends RuntimeException{
 
...
}


public class BadCredentials extends RuntimeException{
 
...
}


public class NetworkError extends RuntimeException{
 
}


public class UserBlockedError extends RuntimeException{
 
...
}


public class UserAccountNotActivatedError extends RuntimeException{
 
...
}


So LoginInteractor may look like this:

public class LoginInteractor {
 
private final LoginProcessor loginProcessor;


 
@Inject
 
public LoginInteractor(LoginProcessor processor){
 
this.loginProcessor = processor;
 
}


 
/**
 * Performs login and returns user data.
 *
 * @throws UserLoginError
 * //TODO list all possible causes
 */

 
public User loginUser(String userName, String password){
   
return processor.login(userName, password);
 
}
}


I feel that passing UserEntity and the exceptions from the networking layer(LoginProcessor) first to business layer and then directly to UI layer is not correct.
Does it mean that I need to create a separate User object returned in LoginInteractor#loginUser() method?
What about the exceptions?
What have I misunderstood?

Looking forward to your suggestions.

jk

unread,
Jan 16, 2015, 2:35:31 PM1/16/15
to clean-code...@googlegroups.com
Does it mean that I need to create a separate User object returned in LoginInteractor#loginUser() method?
Close, but not quite. Return the DATA that represents the user, but not the user entity itself. Use a simple struct, hash, or methodless class. Clean Architecture calls them "Response Models".

Also "return" doesn't have to be a literal return. You could pass another class to the LoginInteractor constructor that will receive this user data. This is what Clean Architecture describes as the "Presenter". An interactor passes the data structure to the presenter, the presenter moves the data into view models, and the view sources its dynamic context from the view model.

What about the exceptions?
I'm still finding the best way to do this -- but previously I've passed a "listener" to the interactor. The listener has an interface such as "password_incorrect()", "user_blocked()", etc. This conforms to "tell don't ask" -- The interactor is literally telling another object that a password was incorrect, or the user was blocked. It's up to the concrete listener to know what to do with it. This way when an Interactor is instantiated it would accept any object that conforms to that interface. examples "LoginConsolePrinter", "LoginFileSystemLog" or even a NullObject.

One quirk that I've yet to solve is that often i find my Interactors having a collection of if's, listener calls, and return statements at the top of the execute function. I don't like that it pushes the meat of the interactor further down the source file.
Message has been deleted

Konstantin Shilovsky

unread,
Jan 21, 2015, 6:11:21 AM1/21/15
to clean-code...@googlegroups.com
Thanks for the answer.
What will be the difference between UserEntity class and UserData returned by the use case then?
Could you provide an example of UserEntity?

Ramon Chiara

unread,
Jan 21, 2015, 9:12:25 AM1/21/15
to clean-code...@googlegroups.com
My 2 cents: instead of returning the user, you can have a response model that has the user data (as suggested) AND some flags indicating specific errors.
Then it's up to the presenter define the best way to handle all those data/flags.



Reply all
Reply to author
Forward
0 new messages