locked
What is the best practice in handling error responses in ASP Core 2 Web API? RRS feed

  • Question

  • User-1305530094 posted

    I have been reading a lot about means and ways of relaying responses from server to client, among these methods, <g class="gr_ gr_13 gr-alert gr_gramm gr_inline_cards gr_disable_anim_appear Style multiReplace" id="13" data-gr-id="13">i.e </g>400<g class="gr_ gr_13 gr-alert gr_gramm gr_inline_cards gr_disable_anim_appear Style multiReplace" id="13" data-gr-id="13">,</g> we can either do,

    return BadRequest(<g class="gr_ gr_10 gr-alert gr_spell gr_inline_cards gr_disable_anim_appear ContextualSpelling ins-del multiReplace" id="10" data-gr-id="10">Modeltate</g>);

    or

    return StatusCode(400, ModelState);

    Which one is considered more proper for a web API? in the following example I just want to show the error handling needed some more work to extract the error from response

    I will provide and example based on login controller and handling response in Angular app,

    web API controller,

      [HttpPost]
            [AllowAnonymous]
            public async Task<IActionResult> Login([FromBody] CredentialsViewModel credentials)
            {
                await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);
                var accessToken = new AccessTokenViewModel();
                if (!ModelState.IsValid)
                {
                    return BadRequest(ModelState);
                };
    
                if (RegexUtilities.IsValidEmail(credentials.UniqueId))
                {
                    var user = await this._usersService.FindUserByEmailAsync(credentials.UniqueId);
                    if (StaticHandlers.IsNullObject(user))
                    {
                        credentials.UniqueId = Guid.NewGuid().ToString(); // count as wrong entry and initiate lock down
                    }
                    else
                    {
                        credentials.UniqueId = user.UserName;
    
                    }
                }
                var result = await signInManager.PasswordSignInAsync(credentials.UniqueId, credentials.Password, credentials.RememberMe, lockoutOnFailure: true);
    
                if (result.Succeeded)
                    {
                        var userToVerify = await userManager.FindByNameAsync(credentials.UniqueId);
                        (accessToken.AuthToken, accessToken.TokenId) = await _tokenStoreService.CreateJwtTokens(userToVerify).ConfigureAwait(false);
                        logger.LogInformation( credentials.UniqueId + " logged in.");
                        return Ok(accessToken);
                    }
    
                else
                {
                    ModelState.AddModelError("Invalid Credentials", "Invalid credentials, please try again!");
                    return BadRequest(ModelState);
                    logger.LogCritical("Invalid Credentials");
                    // return StatusCode(400, "ModelState"); =======> this response handling on the client side is different from the method shown below
                    return BadRequest(ModelState);
                } 
            }

    And in my front end

    errors: string[] = [];
    login() {
         if (this.loginForm.valid) {
    
          this.userService.login(this.loginForm.value)
            .subscribe((response) => {
              console.log(response);
              this.store.dispatch(new authActions.Signin);
              this.store.dispatch(new authActions.SetToken(response['authToken']));
              if (response['authToken']) {
                localStorage.setItem('token', response['authToken']);
                this.router.navigate(['/dbapp']);
              }
            },
            (error) => {
            this.errors = (this.modelStateHandler.ErrorResponseHandler(error));
            })
         }
      }
    
    
    
        public ErrorResponseHandler(error: string[]) {
            let modelStateErrorArray: Array<Array<string>>;
            let errorArray:string[] = [];
            console.log(error);
            if (error){
            if (error['status'] == '400') {
                modelStateErrorArray = error['error'];
                var errorKeys:string[] = Object.keys((modelStateErrorArray));            
                for (let errorKey of errorKeys) {
                    let errorMsg: string= (modelStateErrorArray[errorKey][0]);
                    errorArray.push(errorMsg);
                }
                console.log(errorArray);
                return errorArray;
            }
            }
        }

    HTML component 

                      <div *ngIf="errors" class="alert alert-danger" role="alert">
                            <strong>Oops!</strong> 
                          <div *ngFor="let error of errors">
                              {{error}}
                          </div>
                        </div>

     

    Monday, December 25, 2017 6:17 AM

Answers

  • User283571144 posted

    Hi Embryologist,

    Which one is considered more proper for a web API? in the following example I just want to show the error handling needed some more work to extract the error from response

    In my opinion, the main difference between  BadRequest and StatusCode class is the badrequest will only return 400 error, but the statuscode could set your own error status.

    I suggest you could try to use statuscode method, so that you could use your own status codes which means the specific error message.

    Best Regards,

    Brando

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Tuesday, December 26, 2017 6:10 AM
  • User753101303 posted

    Hi,

    Use F12 network to see if it makes a difference for the http response or see the Open Source code to see how it is implemented (likely a thin wrapper).

    BadRequest is rather when a request is technically bad (malformed, header size too big etc...). A 401 error might be better for incorrect credentials.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Saturday, January 6, 2018 11:18 AM

All replies

  • User1120430333 posted

    http://tools.ietf.org/html/rfc2616#section-6.1.1

    What the documentation is stating is that you can make your own custom 4xx error code that doesn't conflict with an existing code with code you make meaning something to you and the client. I would say  just returning the 400 error code may not be suitable on bad login credentials.

    Monday, December 25, 2017 5:59 PM
  • User283571144 posted

    Hi Embryologist,

    Which one is considered more proper for a web API? in the following example I just want to show the error handling needed some more work to extract the error from response

    In my opinion, the main difference between  BadRequest and StatusCode class is the badrequest will only return 400 error, but the statuscode could set your own error status.

    I suggest you could try to use statuscode method, so that you could use your own status codes which means the specific error message.

    Best Regards,

    Brando

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Tuesday, December 26, 2017 6:10 AM
  • User753101303 posted

    Hi,

    Use F12 network to see if it makes a difference for the http response or see the Open Source code to see how it is implemented (likely a thin wrapper).

    BadRequest is rather when a request is technically bad (malformed, header size too big etc...). A 401 error might be better for incorrect credentials.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Saturday, January 6, 2018 11:18 AM