# 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)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET 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?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
