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