Search code examples
c#apiexceptionhttp-status-codeserror-code

API Response Http Status Code and Custom Error Codes Mapping


How do I store the mappings of http status code and error codes. To give a basic idea the status code and error code which I am working on is similar to twitter Error codes.

Now the question is if I have multiple error codes for a single http status code (in case of twitter the error codes 3,44,215,323,324,325,407 are mappedd to the http status code 400), how do I store this values in my code. Do I use Dictionary<int, List<int>> or is there any other way I can do it?.

I will be setting the error code in the Exception. The Exception Filter will parse the error code and set the appropriate http status code and send the API Response back.

Exception Class

public class APIException : Exception
{
    public int ErrorCode { get; set; }


    public APIException(int errorCode, string message) : base(message)
    {
        ErrorCode = errorCode;
    }
}

Exception Filter Code Snippet

var apiException = actionExecutedContext.Exception as APIException;

int statusCode = GetHttpStatusCode(apiException.ErrorCode)

var response = new HttpResponseMessage((HttpStatusCode)(statusCode));

var apiResult = new APIResult(apiException.ErrorCode, apiException.Message);

response.Content = new ObjectContent<APIResult>(apiResult, new JsonMediaTypeFormatter(), "application/json");

actionExecutedContext.Response = response;

Now the question is on the implementation of GetHttpStatusCode() function. Currently I am thinking to use Dictionary<int, List<int>> to store the mappings. Get the Key(httpStatusCode) by searching in the Values(error codes).

I can have a flat Dictionary<int,int> where error code is key and http status code is value. But the list will grow huge and readability will be difficult if I have to see what all error codes we have for a specific status code.


Solution

  • Frankly, that with a flat dictionary

    [...] the list will grow huge and readability will be difficult if I have to see what all error codes we have for a specific status code.

    is not a very good excuse to make the code overly complex and less performant. While the readability of the Dictionary<int, List<int>> would maybe be a bit better, the readability of the code itself (and it should be the code that matters) would suffer. IMHO it's rather a symptom of an suboptimal code structure.

    With a flat dictionary, the lookup gets as simple as

    int GetHttpStatus(int errorCode)
    {
       return errorCodeMappings[errorCode]; 
    }
    

    And since a key cannot exist more than once in a dictionary, there is no way of error codes being added multiply.

    (As a plus, this is super-fast compared to a solution that uses a Dictionary<int, List<int>> with reverse lookups, because you can make use of hashing. While this would most likely not be the bottleneck, it's nice to have for free.)

    If you wrapped this in some StatusCodeMapper class, you could define your constructor as

    public ErrorCodeMapper(Dictionary<int, List<int>> reverseMappings)
    {
        // Convert mappings to a more efficient format
        this.mappings = reverseMappings.SelectMany(entry => entry.Value.Select(errorCode => new { errorCode, status=entry.Key}))
                                       .ToDictionary(mapping => mapping.errorCode, mapping => mapping.status)
    }
    

    and retain your Dictionary<int, List<int>> at a top-level, but make use of the more concide and faster lookup and automatic checking for duplicate error codes you get with Dictionary if used as intended. If you create only a single instance of ErrorCodeMapper, the "expensive" code (well, not too expensive though, but more than a hash lookup) will run only once.