1

I'm trying to learn .NET Core; my background is largely PHP where the absence of a type system makes what I'm trying to do here trivial.

I'm trying to create an API with a small wrapper for the response. So that instead of sending {"user": "..."} I can send {"message": "...", "data": {"user": "..."}}

To start, I began with a POCO for the wrapper:

public class AppResponse<T>
{
    public string Message { get; set; }
    public T data { get; set; }
}

Then, I instantiate the wrapper differently each time I need a response object:

[HttpPost]
public async Task<IActionResult> Register(RegisterViewModel model)
{
    if (ModelState.IsValid)
    {
        var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
        var result = await _userManager.CreateAsync(user, model.Password);

        if (result.Succeeded)
        {
            var okResponse = new AppResponse<RegisterViewModel>();
            okResponse.Message = "Your account has been created.";
            return Ok(okResponse);
        }
        else
        {
            var errorResponse = new AppResponse<IEnumerable<IdentityError>>();
            errorResponse.data = result.Errors;
            return BadRequest(errorResponse);
        }
    }
    var badRequest = new AppResponse<RegisterViewModel>();
    badRequest.data = model;

    return BadRequest(badRequest);
}

Is there an easier/better way to do this in .NET Core? I intend for this to be a Web API, so the ability to make more complicated JSON responses (for things such as pagination, validation errors, etc.) is crucial.

I apologize for the confusion of camel case in variables, I'm still figuring out best practices in C#.

EDIT: I have simplified my code to use a more RESTful approach. This is it currently:

public async Task<IActionResult> Register(RegisterViewModel model)
{
    if (ModelState.IsValid)
    {
        var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
        var result = await _userManager.CreateAsync(user, model.Password);

        if (result.Succeeded)
        {
            return Ok(user);
        }
        return BadRequest(result);
    }

    // If we got this far, something failed.
    return BadRequest(new
    {
        Errors = ModelState
    });
}
charmeleon
  • 2,693
  • 1
  • 20
  • 35
  • this might be similar question http://stackoverflow.com/questions/39120798/net-filter-for-wrapping-jsonresult-actions-response – Moamen Naanou Nov 13 '16 at 14:24
  • Well one question here is, do you even need the `Message` property at all? I mean in a restful service a http code of 200 already succeeds success and it's up for the consumer (angular2 api, mobile app or another server-sided application) clear that it was created successfully – Tseng Nov 13 '16 at 15:49
  • @Tseng That's true on a success request, but how about different reasons for failure? Say for a /login endpoint, how do you tell your client the the reason for failure was that the user is locked out vs invalid credentials? The RFC for HTTP status code 400 says it's for "The request could not be understood by the server due to malformed syntax." so it's not even appropriate for invalid credentials. – charmeleon Nov 13 '16 at 16:04
  • You already return a list of errors in the data property here `errorResponse.data = result.Errors;`, which is from the `IdentityResult`. – Tseng Nov 13 '16 at 16:15
  • Unfortunately, `Microsoft.AspNetCore.Identity.SignInResult` does not follow the same pattern. The object doesn't have an 'Errors' property, I would have to send back the entire object back for the client to figure out which scenario took place. But I guess that would make sense. Thanks for the input, I'll try to go it along and see if I can come up with something sensible. – charmeleon Nov 13 '16 at 16:29

0 Answers0