Restful API 中的錯誤處理

  • 2019 年 10 月 3 日
  • 筆記

??

???????????????????? Web ?????????? Restful API?
Restful API ???????????????????????????????????????? ???????????????????????????
??????? Restful API ??????????????????????????
??????????????????????????????????????????????????????????
????? Restful API ?????????

??????

? Restful API ???????????????????????????????
????? Github, Google, Facebook, Twitter, Twilio ??????????

Github (use http status)

{    "message": "Validation Failed",    "errors": [      {        "resource": "Issue",        "field": "title",        "code": "missing_field"      }    ]  }

Google (use http status)

{    "error": {      "errors": [        {          "domain": "global",          "reason": "insufficientFilePermissions",          "message": "The user does not have sufficient permissions for file {fileId}."        }      ],      "code": 403,      "message": "The user does not have sufficient permissions for file {fileId}."    }  }

Facebook (use http status)

{    "error": {      "message": "Message describing the error",      "type": "OAuthException",      "code": 190,      "error_subcode": 460,      "error_user_title": "A title",      "error_user_msg": "A message",      "fbtrace_id": "EJplcsCHuLu"    }  }

Twitter (use http status)

{    "errors": [      {        "message": "Sorry, that page does not exist",        "code": 34      }    ]  }

Twilio (use http status)

{    "code": 21211,    "message": "The 'To' number 5551234567 is not a valid phone number.",    "more_info": "https://www.twilio.com/docs/errors/21211",    "status": 400  }

??????????????????????

  • ???? Http ???
  • ??????????
  • ???????????????
  • ???????????????

Http ???

? Restful API ??? Http ??????????????????? Http ????????????????
?? Http ?????????????????????????????????????????????

  • API ???? (200, 201)
  • ????? (400, 401, 403, 404)
  • ????? (500, 503)

?????

?????????????????????
???????? Http ?????????????????????????????/????????

?????????

????????????????????????????????????????
?????????????????????????

??????????

???? API ????????????????????????????????????

??????

???????????? Http ??????????????
??????????????????????? ? 4xx ??????

?????????????????

  • 400 Bad Request
    ??????????????????????????????????????????????
    ????????????????????????????
  • 401 Unauthorized
    ???????????
    ??????????????????? API ??????????
  • 403 Forbidden
    ???????????????????401?????????????????????
    ????????????(???/??????????????)?????????
  • 404 Not Found
    ?????????????????????????
    ?????????????????

???????? Http ????????????
?????????????? Http ??????????????? Http ????

// Node.js  if (!res.body.title) {    res.statusCode = 400  }    if (!user) {    res.statusCode = 401  }    if (!post) {    res.statusCode = 404  }

????????????????????????????????????????????
??????????????????????????????
?????????????????

  • ???? (FORMAT_INVALID)
  • ????? (DATA_NOT_FOUND)
  • ????? (DATA_EXISTED)
  • ???? (DATA_INVALID)
  • ???? (LOGIN_REQUIRED)
  • ???? (PERMISSION_DENIED)

????????????????????????

if (!res.body.title) {    throw new Error(ERROR.FORMAT_INVALID)  }    if (!user) {    throw new Error(ERROR.LOGIN_REQUIRED)  }    if (!post) {    throw new Error(ERROR.DATA_NOT_FOUND)  }    if (post.creator.id !== user.id) {    throw new Error(ERROR.PERMISSION_DENIED)  }

?????????????????????????????????
????????????????????????????

???????

??????????????????????????????????????
???????????????

{    "type": "",    "code": 0,    "message": "",    "detail": ""  }

???????????

  • ???????????type, code, message
  • detail ?????????????????
const ERROR = {    FORMAT_INVALID: 'FORMAT_INVALID',    DATA_NOT_FOUND: 'DATA_NOT_FOUND',    DATA_EXISTED: 'DATA_EXISTED',    DATA_INVALID: 'DATA_INVALID',    LOGIN_REQUIRED: 'LOGIN_REQUIRED',    PERMISSION_DENIED: 'PERMISSION_DENIED'  }    const ERROR_MAP = {    FORMAT_INVALID: {      code: 1,      message: 'The request format is invalid'    },    DATA_NOT_FOUND: {      code: 2,      message: 'The data is not found in database'    },    DATA_EXISTED: {      code: 3,      message: 'The data has exist in database'    },    DATA_INVALID: {      code: 4,      message: 'The data is invalid'    },    LOGIN_REQUIRED: {      code 5,      message: 'Please login first'    },    PERMISSION_DENIED: {      code: 6,      message: 'You have no permission to operate'    }  }    class CError extends Error {    constructor(type, detail) {      super()      Error.captureStackTrace(this, this.constructor)        let error = ERROR_MAP[type]      if (!error) {        error = {          code: 999,          message: 'Unknow error type'        }      }        this.name = 'CError'      this.type = error.code !== 999 ? type : 'UNDEFINED'      this.code = error.code      this.message = error.message      this.detail = detail    }  }

??????????????????????

// in controller  if (!user) {    throw new CError(ERROR.LOGIN_REQUIRED, 'You should login first')  }    if (!req.body.title) {    throw new CError(ERROR.FORMAT_INVALID, 'Title is required')  }    if (!post) {    throw new CError(ERROR.DATA_NOT_FOUND, 'The post you required is not found')  }

?????????????????????????????????????

??????

? Controller ?????????????????????????????
?????? koa 2 ?? web ????? restful api???????????????????:

module.exports = async function errorHandler (ctx, next) {    try {      await next()    } catch (err) {        let status        switch (err.type) {        case ERROR.FORMAT_INVALID:        case ERROR.DATA_EXISTED:        case ERROR.DATA_INVALID:          status = 400          break        case ERROR.LOGIN_REQUIRED:          status = 401        case ERROR.PERMISSION_DENIED:          status = 403        case ERROR.DATA_NOT_FOUND:          status = 404          break        default:          status = 500      }        ctx.status = status      ctx.body = err    }  }    // in app.js  app.use(errorHandler)  app.use(router.routes())

???????????????? Restful API ????????

????

https://zh.wikipedia.org/zh-hans/HTTP%E7%8A%B6%E6%80%81%E7%A0%81
https://www.loggly.com/blog/node-js-error-handling/
http://blog.restcase.com/rest-api-error-codes-101/
https://apigee.com/about/blg/technology/restful-api-design-what-about-errors
http://stackoverflow.com/questions/942951/rest-api-error-return-good-practices
http://goldbergyoni.com/checklist-best-practices-of-node-js-error-handling/
http://blogs.mulesoft.com/dev/api-dev/api-best-practices-response-handling/
https://developers.facebook.com/docs/graph-api/using-graph-api/#errors
https://developers.google.com/drive/v3/web/handle-errors
https://developer.github.com/v3/#client-errors
https://dev.twitter.com/overview/api/response-codes
https://www.twilio.com/docs/api/errors