> For the complete documentation index, see [llms.txt](https://jen-hsuan-hsieh.gitbook.io/asp-net/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://jen-hsuan-hsieh.gitbook.io/asp-net/chapter3rest-api-design-development-and-management/33designing-rest-api/336walkthrough-implementation-of-error-handling-for-post-api.md).

# 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&#x20;
  * code 6xxx: Any database error such as duplicate keys&#x20;
  * code 7xxx: Validation error
* 程式碼解析
  * api/v1/vacation
    * 1.在POST方法中
      * 1.建立了useError物件
      * 2.在Response中設定Content-Type: "application/json"
    * 2.宣告[函數表達式](https://jenhsuan.gitbooks.io/javascript-node-js/content/chapter1/1236han-shu-chen-shu-ju-yu-han-shu-biao-shi-shi.html)processMongooseErrors: 回傳error物件
    * 3.宣告[函數表達式](https://jenhsuan.gitbooks.io/javascript-node-js/content/chapter1/1236han-shu-chen-shu-ju-yu-han-shu-biao-shi-shi.html)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",
  }
  ```

  * 結果

    ![](/files/-M4M0XCr7l9gYxlYKkLG)
