The question is about a desktop application I'm creating in C# and WPF. As very common I'm using the repository pattern in my Data Access Layer for my CRUD operations. All data comes from the serverside part of the application, using a REST API.
For each repository an interface is defined. So the usercode of the repositories can rely on some consistency.
You can think of my repository as
ApiUserRepository : IUserRepository. If anywhere in the future another repository implementation is necessary, like
FileUserRepository : IUserRepository there is no problem about incompatibility because of the principle of interfaces at all.
The repositories actually wrap API calls, and return the result of course. The methods for data operations (like
GetUserById(...)) are all async.
At this time, I just return the data from the repository methods. So the
GetUserById(...) method returns a User object. If the user is not found, it returns null.
Each interation with a repository can produce four types of results, I take a reading operation as example:
- The requested data is returned.
- The requested data was not found (I return null or an empty list).
- The data source (in this case REST API) that's used by the repository, returns an error saying the API is called the wrong way or invalid (user) input is provided.
- There was a technical exceptional error, Like Bad HTTP Request, Time-out, Internal server error, etc.)
Case 1. and 2. are already handled, because the return value of a repository method just contains either the data or a null (or empty list).
My question is about how to handle case 3. and 4. in a repository design: how to communicate an error message coming from the data source (in this case REST API) to the usercode of the repository? In case 3. the API server responds with an error JSON object. In case 4 the repository can detect this via other ways. The repository can easily interpret all this and that's not my question. My question is about how to communicate this error to outside the repository, so the code that uses the repo can handle this further (and display an error message on screen for example). In case 4. we can say using exceptions is justified, but case 3...
The return value of a repository method can not be used anymore because it's already utilized for case 1. and 2.
Throwing exceptions from the repository for case 3. seems to be ugly to me.
What would be the best way to solve this design problem and keep it all clean?
Don't consider my repositories as just 'HTTP clients'. It just has to be able to inform the outside world if something went wrong, and what message was responded from the server.