Search code examples
c#asp.net-web-apiasp.net-core-webapiblazorblazor-client-side

Client-side multiple api responses handling


My api has a method that returns multiple response types: GetTokenResponse, ErrorsResponse, ErrorResponse.

[HttpPost("token")]
[ProducesResponseType(typeof(GetTokenResponse), (int)HttpStatusCode.OK)]
[ProducesResponseType(typeof(ErrorsResponse), (int)HttpStatusCode.BadRequest)]
[ProducesResponseType(typeof(ErrorResponse), (int)HttpStatusCode.Forbidden)]
public async Task<IActionResult> GetToken([FromBody] GetTokenRequest request)
{
    try
    {
        var token = await _authService.LoginAsync(request.Email, request.Password);
        return Ok(new GetTokenResponse { Token = token });
    }
    catch (Exception ex) when (ex is UserNotFoundException || ex is InvalidPasswordException)
    {
        return BadRequest(new ErrorsResponse("Invalid username or password."));
    }
    catch (EmailNotConfirmedException ex)
    {
        return StatusCode((int)HttpStatusCode.Forbidden, new ErrorResponse(ex.Message));
    }
}

and the client side service has a method to make the request

public async Task<bool> LoginAsync(GetTokenRequest request)
{
    var response = await _client.PostAsJsonAsync($"{_apiUrl}{Requests.Token}", request);

    if (response.StatusCode != HttpStatusCode.OK)
    {
        return false;
    }

    var responseString = await response.Content.ReadAsStringAsync();
    var result = JsonConvert.DeserializeObject<GetTokenResponse>(responseString);
    await Authenticate(result.Token, request.Email);

    return true;
}

In the current implementation method can return either true or false, only GetTokenResponse is processed but I want to handle all response types. Actually this is the question. What is the best way to do it? I thought about returning response content from the service and parsing response type on the caller side, creating a base response type \ wrapper for responses but what do best practices say?


Solution

  • I added extension method EnsureSuccess() that throws exceptions

    public async Task LoginAsync(GetTokenRequest request)
    {
        var response = await _client.PostAsJsonAsync($"{_apiUrl}{Requests.Token}", request);
        var result = await response.EnsureSuccess<GetTokenResponse>();
    
        await Authenticate(result.Token, request.Email);
    }
    

    Then on the page

    public async Task ExecuteLogin()
    {
        try
        {
            await AuthService.LoginAsync(_request);
            NavigationManager.NavigateTo("/");
        }
        catch (BadRequestException ex)
        {
            var response = ex.Response.Deserialize<ErrorsResponse>();
            Errors = response.Result.Messages;
        }
        catch (ForbiddenException ex)
        {
            var response = ex.Response.Deserialize<ErrorResponse>();
            Errors = new List<string> { response.Result.Message };
        }
    }