ASP .NET
  • Introduction
  • Chapter1.MVC 5
    • 1.1.The Complete ASP.NET MVC 5 Course
      • 1.0. Deploy .NET project to IIS
      • 1.1.Getting started
        • 1.1.1.MVC Architectural
        • 1.1.2.Setting up the development environment
        • 1.1.3.Create MVC APP
        • 1.1.4.Add a new Model, Controller, View
      • 1.2.ASP.NET MVC Fundamentals
        • 1.2.1.Action
        • 1.2.2.Route
        • 1.2.3.Pass data to views
        • 1.2.4.ViewModel
        • 1.2.5.View
      • 1.3.Working with data
        • 1.3.1.Entity framework
        • 1.3.2.Database First v.s. Code First
        • 1.3.3.Code-first Migrations
        • 1.3.4.Seeding the database
        • 1.3.5.Overriding conventions
        • 1.3.6.Query objects
      • 1.4.Building Forms
        • 1.4.1.The Markup (labelFor, textbox, checkbox)
        • 1.4.2.Labels
        • 1.4.3.Drop down list
        • 1.4.4.Model binding and save data
        • 1.4.5.Edit form
      • 1.5.Implement validation
        • 1.5.1.Adding validation
        • 1.5.2.Data annotation
        • 1.5.3.Client side validation
        • 1.5.4.Anti-forgery Tokens
      • 1.6. Building RESTful API
        • 1.6.1. What is Web API?
        • 1.6.2. RESTful convetion
        • 1.6.3. Building a API and testing
        • 1.6.4. Data Transfer Object
        • 1.6.5. Use camel annotation
        • 1.6.6. Use IHttpActionResult
      • 1.7.Client-side Development
        • 1.7.1.Calling an API using jQuery
        • 1.7.2.Bootbox plug-in
        • 1.7.3.DataTable plug-in using AJAX source
        • 1.7.4.Returning Hierarchical Data
      • 1.8.Authentication and Authorization
        • 1.8.1.The problem
        • 1.8.2.Authentication options
        • 1.8.3.Restricting Access
        • 1.8.4.Seeding Users and Roles
        • 1.8.5.Working with Roles
        • 1.8.6.Adding Profile Data
        • 1.8.7.OAuth
        • 1.8.8.Social Logins
      • 1.9.Performance Optimization
        • 1.9.1.Overview
        • 1.9.2.Data Tier
        • 1.9.3.Glimpse
        • 1.9.4.Output Cache
        • 1.9.5.Data Cache
        • 1.9.6.Async
        • 1.9.7.Disabling Session
        • 1.9.8.Client Tier
      • 1.10.Building a Feature End-to-End Systematically
        • 1.10.1.Domain Modelling
        • 1.10.2.Adding Auto-completion
        • 1.10.3.Updating the DOM
        • 1.10.4.Implementing Client-side Validation
      • 1.11.Deployment
        • 1.11.1.Deploying the application
        • 1.11.2.Deploying the database
        • 1.11.3.Build configurations
        • 1.11.4.Application settings
        • 1.11.5.Custom Error Pages
        • 1.11.6.Logging Unhandled Exceptions
      • 1.12.Approved collection server
        • 1.12.1.Overview
        • 1.12.2.測試上傳審批資料
        • 1.12.3.取得Token的方式
        • 1.12.4.測試取得審批資料, Log資料
        • 1.12.5.將API接口綁定到雲之家審批
    • 1.2.Skilltree MVC 實戰營筆記
      • 1.2.1..NET MVC overview and razor view
      • 1.2.2.Controller, Model, Entity framework, service
      • 1.2.3.HTML helper, Extension method, Validation
      • 1.2.4.Security, ActionFilter, ActionResult
      • 1.2.5.DataType, Templates
  • Chapter2.SignalR
    • 2.1.Getting started
      • 2.1.1.Install signalR on VS2013
    • 2.2.Basic of SignalR
      • 2.2.1.Chat App Ovierview
      • 2.2.2.Creating a hub
      • 2.2.3.Connecting to the hub
      • 2.2.4.Create A server method and calling from client
      • 2.2.5.Passing parameters to server method from client
      • 2.2.6.Creating a client method and calling from server
    • 2.3. Exploring the class hub and group chat
      • 2.3.1.OnConnected, OnDisconnected
      • 2.3.2. ContextObject and JSON serialization
      • 2.3.3. Clients Object's Methods
      • 2.3.4. Add Or Remove Connection From Groups
      • 2.3.5. Sending Messages To Different Groups
  • Chapter3.REST API Design, Development & Management
    • 3.1.Evolution of RESTful services
      • 3.1.1.Evolution of REST/JSON API
      • 3.1.2.Introduction to RESTful API
      • 3.1.3.Private, Public and Partner API
    • 3.2.REST API Architectural Constraints
      • 3.2.1.Introduction to REST Architecture Constraints
      • 3.2.2.Client-Server
      • 3.2.3.Uniform Interface
      • 3.2.4.Statelessness
      • 3.2.5.Caching
      • 3.2.6.Layered system
      • 3.2.7.Code on demand
      • 3.2.8.Richardson Maturity Model for REST API
    • 3.3.Designing REST API
      • 3.3.1.API value chain
      • 3.3.2.Practices for Resource Names, Actions & Associations
      • 3.3.3.Implementing REST API CRUD operations
      • 3.3.4.Walkthrough: Creating a Vacations API in Node JS
      • 3.3.5.REST API Error Handling Practices
      • 3.3.6.Walkthrough: Implementation of error handling for POST API
      • 3.3.7.Versioning the API
      • 3.3.8.API Caching (1 of 2) Concepts & Design decisions
      • 3.3.9.API Caching (2 of 2) Concepts & Design decisions
      • 3.3.10. Demo - API Caching using Cache-Control Directives
      • 3.3.11.Building support for Partial Responses
    • 3.4.REST API Security
      • 3.4.1.REST API Security - Introduction
      • 3.4.2.Securing API with Basic Authentication
      • 3.4.3.Securing API with Tokens & JWT
      • 3.4.4.Securing API with API Key & Secret
      • 3.4.5.API Authorization using OAuth2.0
        • 3.4.5.1.Authorization scope grant (Refresh token grant)
        • 3.4.5.2.Client credentials grant
        • 3.4.5.3.Implicit Grant
        • 3.4.5.4.Resource owner credentials grant
      • 3.4.6.API Security - Functional Attack
    • 3.5.REST API Specifications using Swagger 2.0 / OAI
      • 3.5.1.Requirements Analysis Process & Intro to REST Specifications
      • 3.5.2.Swagger/OAI Specifications Walkthrough
      • 3.5.3.Swagger/OAI Specifications, Part 1 of 3
      • 3.5.4.Swagger/OAI Specifications, Part 2 of 3
      • 3.5.5.Swagger/OAI Specifications, Part 3 of 3
    • 3.6.API management
      • 3.6.1.Introduction to API Management
      • 3.6.2.API Lifecycle & Developer Productivity
      • 3.6.3.API Developer Portal
      • 3.6.4.API Security management
      • 3.6.5.API Traffic Management
      • 3.6.6.API Analytics
      • 3.6.7.API Product and API Monetization
    • 3.7.Summary
  • Chapter4.REST API/Web Services testing with SoapUI
    • 4.1.Web Service Basics
      • 4.1.1.Introduction of WSDL
      • 4.1.2.Introduction of SOAP
      • 4.1.3.Introduction to XML
    • 4.2.SoapUI Basics
      • 4.2.1.Create TestSuite and TestCase
      • 4.2.2.Exporting and Importing project into workspace
      • 4.2.3.Running mock service- might come handy when your actual service is down
    • 4.3.Assertion
      • 4.3.1.XPath Expression
      • 4.3.2.Writing first assertion
      • 4.3.3.Assertions - Compliance,Status & Standards
      • 4.3.4.XQuery assertion
      • 4.3.5.Handling CDATA - using XPath and Groovy
    • 4.4.Working with Properties
      • 4.4.1.Property expansion
Powered by GitBook
On this page

Was this helpful?

  1. Chapter3.REST API Design, Development & Management
  2. 3.3.Designing REST API

3.3.6.Walkthrough: Implementation of error handling for POST API

Previous3.3.5.REST API Error Handling PracticesNext3.3.7.Versioning the API

Last updated 5 years ago

Was this helpful?

  • 如果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",
    }
    • 結果

函數表達式
函數表達式