3.3.6.Walkthrough: Implementation of error handling for POST API

  • 如果POST失敗, 只回400是不夠的, 為了讓開發找更能addressing issue, Steps to improve POST error handling

    • 1.Steup the error codes and description for API specific errors

    • 2.Create the template for the error response body

    • 3.Code a utility function for creating the error response

    • 4.Implement the error handling code for POST /vacations

      • Send back status code for duplicate & vacation errors

  • 建議使用的status code

    • code 5000: unknown Error

    • code 6xxx: Any database error such as duplicate keys

    • code 7xxx: Validation error

  • 程式碼解析

    • api/v1/vacation

      • 1.在POST方法中

        • 1.建立了useError物件

        • 2.在Response中設定Content-Type: "application/json"

      • 2.宣告函數表達式processMongooseErrors: 回傳error物件

      • 3.宣告函數表達式processValidationErrors: 處理Validation Error

    module.exports = function (router) {
        'use strict';

        // CREATE new vacation packages
        router.route(URI).post(function (req, res, next) {
            console.log("POST  Vacations")

            //1. Get the data
            var doc = req.body;

            //2. Call the insert method
            db.save(doc, function (err, saved) {
                if (err) {
                    // Creates the error response
                    // EARLIER it was >>>  res.status(400).send("err")
                    var userError = processMongooseErrors(apiMessages.errors.API_MESSAGE_CREATE_FAILED, "POST", URI, err,{});
                    res.setHeader('content-type', 'application/json')
                    res.status(400).send(userError)
                } else {
                    res.send(saved)
                }
            });
        });
    }
    /**
     * Converts the Mongoose validation errors to API specific errors
     */
    var processMongooseErrors = function (message, method, endpoint, err,payload) {
        var errorList = []
        // Check for validation error
        if (err.name === 'ValidationError'){
            errorList = processValidationErrors(err)
        } else if(err.code == 11000){
            // it could be database error - 11000 is for duplicate key
            errorList.push(apiErrors.errors.PACKAGE_ALREADY_EXISTS)
        } else {
            var errUnknown = apiErrors.errors.UNKNOWN_ERROR
            errUnknown.payload = err
            errorList = [apiErrors.errors.UNKNOWN_ERROR]
        }
        return apiErrors.create(message, method, endpoint, errorList, payload)
    }

    /**
     * Converts Mongoose errors to API specific errors
     */
    var processValidationErrors = function (err) {
        var errorList = []
        // Check if there is an issue with the Num of Nights
        if (err.errors.numberOfNights) {
            if (err.errors.numberOfNights.kind === apiErrors.kinds.MIN_ERROR 
            || err.errors.numberOfNights.kind  === apiErrors.kinds.MAX_ERROR 
            || err.errors.numberOfNights.kind === apiErrors.kinds.NUMBER_ERROR ) {
                errorList.push(apiErrors.errors.FORMAT_NUM_OF_NIGHTS)
            }
        }
        // Check if name of the package is missing
        if (err.errors.name) {
            if (err.errors.name.kind === apiErrors.kinds.REQUIRED) {
                errorList.push(apiErrors.errors.MISSING_PACKAGE_NAME)
            }
        }

        // Check if description of the package is missing
        if (err.errors.description) {
            if (err.errors.description.kind === apiErrors.kinds.REQUIRED) {
                errorList.push(apiErrors.errors.MISSING_PACKAGE_DESCRIPTION)
            }
        }

    return errorList;
}
  • util/error

    • 1.建立error list物件

    • 2.create方法會回傳text:message, timestamp, method, endpoint, errors, payload

    exports.errors = {
      // This is a catch all error
      // Ideally this should never be thrown
      UNKNOWN_ERROR : {
      code:5000,
      text:"Unknown error !!!",
      hints:["Please contact development team wit information on 'how to reproduce this error'. Thank you for your help and support."],
      info:"http://developer.acme.com/unknownerror"
    },
    
    PACKAGE_ALREADY_EXISTS :{
      code:6000,
      text:"Vacation package with the provided 'name' already exist",
      hints:["Please use PUT for update instead of POST"],
      info:"http://developer.acme.com/errors#6000"
    },
    
    // All required/missing field errors start with number 7
    MISSING_PACKAGE_NAME : {
      code:7001,
      text:"Required field vacation 'name' is missing",
      hints:["Please check that user has provided the non null value for 'name'"],
      info:"http://developer.acme.com/error#RequiredFields"
    },
    MISSING_PACKAGE_DESCRIPTION :  {
      code:7002,
      text:"Required field vacation 'description' is missing",
      hints:["Please check that user has provided the non null value for description"],
      info:"http://developer.acme.com/error#RequiredFields"
    }  ,
    MISSING_PACKAGE_NUM_OF_NIGHTS : 
    {
      code:7003,
      text:"Required field vacation 'number of nights' is missing",
      hints:["Please check that user has provided a number (between 1 & 31)"],
      info:"http://developer.acme.com/error#RequiredFields"
    },
    // All format errors begin with 8
    FORMAT_NUM_OF_NIGHTS : {
      code:7004,
      text:"Number of nights MUST be a number (between 1 & 31)",
      hints:["Please check that user has provided a numeric value for 'number of nights'"],
      info:"http://developer.acme.com/error#RequiredFields"
    }
    }
    /**
    * Utility methods
    * Creates the error response body to be sent back to the caller
    */
    exports.create = function(message,httpMethod,endpointInformation,errorList,receivedPayload){
    return    {
      // Meant for the developer 
      text:message,
      timestamp:new Date(),
      // POST, GET ....
      method:httpMethod,
      // Endpoint information
      endpoint:endpointInformation,
      // An array of all errors
      errors : errorList,
      // OPTIONAL - Use only during development
      payload: receivedPayload
    }
    }
    
    // Mongoose validation error types
    exports.kinds = {
    REQUIRED:"required",
    NOT_VALID:"notvalid",
    NUMBER_ERROR:"Number",
    MIN_ERROR:"min",
    MAX_ERROR:"max",
    }
    • 結果

Last updated