0

I'm making an HTTP API for ASP.NET Core Identity.

Basically what I want is a remote version of this: https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.identity.usermanager-1?view=aspnetcore-2.1

It has methods like ChangePasswordAsync, ChangePhoneNumberAsync etc.

The easiest way to do this would be to have a separate request model for each of those methods like ChangeUserPasswordRequest, ChangeUserPhoneNumberRequest and separate endpoint for each change like POST /users/changePassword, POST /users/changePhoneNumber.

This is much easier to implement than PUT /users/:id but it is slightly more complicated on the client side with 1 form for everything(where I have just 1 save button). And it would be much easier to have 1 model like UserDto and 1 endpoint for editing everything like PUT /users/:id.

Compare yourself:

public class UserDto
{
    public int Id { get; set; }
    public string PhoneNumber { get; set; }
    public string Email { get; set; }
    public string UserName { get; set; }

    // ... other properties of the user
    // ...
}

[HttpPut("{id}")]
public async Task<IActionResult> Put(int id, UserDto userDto)
{
     var user = await _userManager.FindByIdAsync(id.ToString());
     if (user == null) return NotFound();

     if (userDto.PhoneNumber != user.PhoneNumber) // phone number has changed
     {
         var identityResult = await _userManager.ChangePhoneNumberAsync(user, userDto.PhoneNumber, userDto.Token);
         //... error handling
     }
     // compare each property like that and call adequate method
     //...
}

This is much easier for the client, as you just bind UserDto to the form and send it back on the server with one method like UpdateUser(userDto).

Now compare it to action that has single responsibility:

public class ChangeUserPhoneNumberRequest 
{
    public ChangeUserPhoneNumberRequest(string userId, string phoneNumber, string token)
    {
        UserId = userId;
        PhoneNumber = phoneNumber;
        Token = token;
    }

    public string UserId { get; }
    public string PhoneNumber { get; }
    public string Token { get; }
}

[HttpPost("changePhoneNumber")]
public async Task<IActionResult> ChangePhoneNumber(ChangeUserPhoneNumberRequest request)
{
    var user = await _userManager.FindByIdAsync(request.UserId.ToString());
    if (user == null) return NotFound();
    var identityResult = await _userManager.ChangePhoneNumberAsync(user, request.PhoneNumber, request.Token);
    //... error handling
}

This looks slightly better on the server and the action is more explicit, however, it seems harder on the client, as you don't have the comfort like with 1 model that you can just send with 1 method like UpdateUser(userDto) this also has the advantage of not sending unnecessary properties. Instead, you have to send many requests for each property you want to change like SendChangeUserPasswordRequest, SendChangeUserEmailRequest and so on. My UI is not task-based but CRUD-based, hence it is harder.

My UI looks like this:

CRUD based UI

(From: http://balazblogspot.blogspot.com/2018/07/what-is-task-based-ui.html)

In this kind of UI, it seems more natural to have something like PUT, but it is less natural to implement on the server.

I don't want to change my UI.

Which approach should I take?

Thank you in advance.

  • This is much easier to implement than PUT /users/:id but it is slightly more complicated on the client side with 1 form for everything(where I have just 1 save button) then do a mix. Do send an array of changes. Do stack changes till save button is clicked. For a cannonical input data model, you could take RPC protocols as example – Laiv Oct 18 '18 at 16:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.