1

Maybe it’s trivial situation but it’s confusing for me and I need some clarification how to deal with it in the right way.

To make it simple the model is as fallow:

User * - * Project

(User is assigned to many projects and project has many users assigned to).

I created rest controller for assigning and dismissing users from specific project:

…\Api\v1\Projects\{projectId}\users\{userId}

Two http action are allowed:

  • POST action to assign existing user to project and
  • DELETE to dismiss user from project. (Not sure if it’s right solution but it works for me).

API Controller use service layer to perform these operation. Service interface is as fallow:

void projectService.assignUser(int projectId, int userId)
void projectService.dismissUser(int projectId, int userId)

Service use dbContext to perform these operation.

Question 1: Which element should be responsible for checking if projectId and userId are correct? IMHO it’s better to put this logic in service layer as it can be reuse.

Question 2: What these method should return in case the projectId and userid are incorrect (for instance: project/user does not exist or is not allowed to be assigned)?

My first thought was to return null value but I think it’s not very meaningful. Mainly because the similar methods in service returns null if enitiyId is incorrect. For instance: projectService.getProject(projectId) – return null if project doesn’t exists

The second though was to return bool. False is at least one of argument is incorrect

The third thought was to throw ArgumentException with message. It’s seems to be good but it makes api controller to catch the exception.

laszczm
  • 173
  • 6

2 Answers2

1

Q1) I think placing them in the Service Layer is a valid idea, I can think of many scenarios where you may want to reuse these methods.

Q2) This one is a bit tricky and subject to opinion, but it really depends on how you want to communicate with your business logic layer (which is where those methods would probably live). One approach that I used recently was creating a special Service Message Class to communicate between the Service Layer and the Business Layer (I presume you can use this to communicate between the presentation layer and the service layer as well with some changes). A class may look like this:

public class BusinessLogicMessage<T> where T : new()
    {
        public BusinessLogicMessage(T result)
        {
            Result = result;
            Status = BusinessLogicStatus.Success;
            Message = string.Empty;
        }

        public BusinessLogicMessage(T result, BusinessLogicStatus status, string message)
        {
            Result = result;
            Status = status;
            Message = message;
        }

        public BusinessLogicStatus Status { get; set; }
        public string Message { get; set; }
        public T Result { get; set; }
    }

    public class BusinessLogicMessage
    {
        public BusinessLogicMessage()
        {
            Status = BusinessLogicStatus.Success;
            Message = string.Empty;
        }

        public BusinessLogicMessage(BusinessLogicStatus status, string message)
        {
            Status = status;
            Message = message;
        }

        public BusinessLogicStatus Status { get; set; }
        public string Message { get; set; }
    }

    public enum BusinessLogicStatus
    {
        Success,
        Failure,
        Warning
    }

So, if your method succeeds, you simply return the default constructor of the class, which has a status of Success. If failure or else happens you can add details. If you need to return a special result object for that method you can attach it to Result

My two cents.

Updated for better answer.

FailedUnitTest
  • 1,637
  • 3
  • 20
  • 43
  • How do you figure out which HTTP status code to return from the REST api controller based on BusinessLogicStatus? 404, 403, 409, 500 etc? – Vinod Dec 15 '16 at 18:54
  • That is somewhat different question, but you can see some examples here: http://stackoverflow.com/questions/10655350/returning-http-status-code-from-web-api-controller – FailedUnitTest Dec 15 '16 at 18:57
  • Of course that is up to you, but you can for example return Status 500 if Status = Failure. Others like 404 and 403 are usually handled by the framework. – FailedUnitTest Dec 15 '16 at 19:09
  • I understand the part on How to return status code, my question was more towards, what is right way to return status code. May be enhance your BusinessLogicStatus with more granular statuses like NotFound, UnAuthorized (data level authorization), Conflict (Concurrency issues), Success... and in API Controller transform it into appropriate Http Status Code... just thinking out loud. – Vinod Dec 15 '16 at 19:09
  • See my reply above, but many of these status codes are handled at the API level by the framework. If you really want to have the ability to return them you can add them to the Status Enum, but I haven't seen this very much because normally you shouldn't reveal details about concurrency and about data authorization issues to the API, I would just log and return failure in that case. – FailedUnitTest Dec 15 '16 at 19:14
0

Answer 1: You should keep validating projectId/userId to service layer for reuse and Call those functions wherever needed.

Answer 2: Create a json based on valid/invalid projectId/userId . It might contain details related to user or project in case both are valid and return error message and error Id (Eg 1 for invalid project, 2 for Invalid User) in case of invalid Ids.

a) JsonObject projectService.assignUser(int projectId, int userId)

Eg:
Valid Ids (both):

{"stat": "ok", "userId": "userId Here", "projectId": "projectId Here"}

Invalid Project Id:

{"errorMsg":"Invalid Project Id","stat":"fail","error":1}

b) JsonObject projectService.dismissUser(int projectId, int userId)

Valid Ids (both):

{"stat": "ok"}

Invalid User Id:

{"errorMsg":"Invalid User Id","stat":"fail","error":2}

Nilu
  • 262
  • 1
  • 8
  • Please don't use the answer section for questions - either get enough reputation to comment (if you're looking for clarification of an existing answer) or create a separate question. – EJoshuaS - Stand with Ukraine Dec 15 '16 at 19:31
  • @EJoshuaS these were the answers. I was just not clear that i was providing solutions to the Questions.I was not asking questions. Will take Care from next time. – Nilu Dec 15 '16 at 19:47