{"id":13487498,"url":"https://github.com/eggjs/egg-rest","last_synced_at":"2025-10-14T14:17:27.584Z","repository":{"id":57220703,"uuid":"63536985","full_name":"eggjs/egg-rest","owner":"eggjs","description":"Restful API plugin for egg","archived":false,"fork":false,"pushed_at":"2020-02-07T01:28:09.000Z","size":60,"stargazers_count":107,"open_issues_count":3,"forks_count":18,"subscribers_count":32,"default_branch":"master","last_synced_at":"2025-09-27T15:43:56.729Z","etag":null,"topics":["egg","egg-plugin","egg-rest","rest-api","restful"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/eggjs.png","metadata":{"files":{"readme":"README.md","changelog":"History.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-07-17T14:49:08.000Z","updated_at":"2025-05-28T04:20:28.000Z","dependencies_parsed_at":"2022-08-29T04:01:35.235Z","dependency_job_id":null,"html_url":"https://github.com/eggjs/egg-rest","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/eggjs/egg-rest","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eggjs%2Fegg-rest","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eggjs%2Fegg-rest/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eggjs%2Fegg-rest/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eggjs%2Fegg-rest/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/eggjs","download_url":"https://codeload.github.com/eggjs/egg-rest/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eggjs%2Fegg-rest/sbom","scorecard":{"id":368766,"data":{"date":"2025-08-11","repo":{"name":"github.com/eggjs/egg-rest","commit":"e7649983af17d7df964b0911cb14a76046a633e9"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.9,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Code-Review","score":6,"reason":"Found 17/27 approved changesets -- score normalized to 6","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":0,"reason":"license file not detected","details":["Warn: project does not have a license file"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 18 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-18T12:29:42.828Z","repository_id":57220703,"created_at":"2025-08-18T12:29:42.828Z","updated_at":"2025-08-18T12:29:42.828Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279018963,"owners_count":26086576,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-14T02:00:06.444Z","response_time":60,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["egg","egg-plugin","egg-rest","rest-api","restful"],"created_at":"2024-07-31T18:01:00.062Z","updated_at":"2025-10-14T14:17:27.566Z","avatar_url":"https://github.com/eggjs.png","language":"JavaScript","readme":"# egg-rest\n\n[![NPM version][npm-image]][npm-url]\n[![build status][travis-image]][travis-url]\n[![Test coverage][codecov-image]][codecov-url]\n[![David deps][david-image]][david-url]\n[![Known Vulnerabilities][snyk-image]][snyk-url]\n[![npm download][download-image]][download-url]\n\n[npm-image]: https://img.shields.io/npm/v/egg-rest.svg?style=flat-square\n[npm-url]: https://npmjs.org/package/egg-rest\n[travis-image]: https://img.shields.io/travis/eggjs/egg-rest.svg?style=flat-square\n[travis-url]: https://travis-ci.org/eggjs/egg-rest\n[codecov-image]: https://codecov.io/github/eggjs/egg-rest/coverage.svg?branch=master\n[codecov-url]: https://codecov.io/github/eggjs/egg-rest?branch=master\n[david-image]: https://img.shields.io/david/eggjs/egg-rest.svg?style=flat-square\n[david-url]: https://david-dm.org/eggjs/egg-rest\n[snyk-image]: https://snyk.io/test/npm/egg-rest/badge.svg?style=flat-square\n[snyk-url]: https://snyk.io/test/npm/egg-rest\n[download-image]: https://img.shields.io/npm/dm/egg-rest.svg?style=flat-square\n[download-url]: https://npmjs.org/package/egg-rest\n\nRESTful API plugin for Egg.\n\nDeveloping RESTful API with egg-rest is very simple. You may read [JSON API spec](http://jsonapi.org.cn/format/) first.\n\n---\n\n## Install\n\n```bash\n$ npm i egg-rest --save\n```\n\n## Usage\n\nEnable the rest plugin in `plugin.js`:\n\n```js\nexports.rest = {\n  enable: true,\n  package: 'egg-rest',\n};\n```\n\n## Configuration\n\n- `urlprefix`: Prefix of rest api url. Default to `/api/`\n- `authRequest`: a function for getting some value of authentication\n- `authIgnores`: allow some request to ignore authentication\n- `errorResponse`: Error handling function\n\n\nExample: Configure the rest plugin in `config/config.default.js`:\n\n```js\nexports.rest = {\n  urlprefix: '/doc/api/', // Prefix of rest api url. Default to /api/\n  authRequest: null,\n  // authRequest: async ctx =\u003e {\n  //   // A truthy value must be returned when authentication succeeds.\n  //   // Otherwise the client will be responded with `401 Unauthorized`\n  //   return accessToken;\n  // }\n\n  // Specify the APIs for which authentication can be ignored.\n  // If authRequest is configured, authentication for all APIs is required by default.\n  authIgnores: null,\n  // authIgnores: {\n  //   users: {\n  //     show: true, // allow GET /api/users/:id to ignore authentication\n  //     index: true,\n  //   }\n  // }\n};\n```\n\n\nControllers in files matching `${baseDir}/app/api/**.js` will be loaded automatically according to routing rules.\n\n__Caution__\n\nIf your RESTful API is open to public systems or websites,\nyou should disable [ctoken] security validation, which is\nprovided by security plugin, for your RESTful url prefix:\n\n```js\nexports.security = {\n  ignore: '/doc/api/'\n};\n```\n\n## URL Routing\n\nFollow the naming conventions of rails:\n\nmethod     | url                                                    | file path               | controller name\n---        | ---                                                    | ---                     | ---\n**GET**    | `/doc/api/{objects}[?per_page={per_page}\u0026page={page}]` | `app/api/{objects}.js` | **index()**\n**GET**    | `/doc/api/{objects}/:id`                               | `app/api/{objects}.js` | **show()**\n**POST**   | `/doc/api/{objects}`                                   | `app/api/{objects}.js` | **create()**\n**PUT**    | `/doc/api/{objects}/:id`                               | `app/api/{objects}.js` | **update()**\n**DELETE** | `/doc/api/{objects}/:id[s]`                            | `app/api/{objects}.js` | **destroy()**\n\n### Nested Resources\n\nNesting of two layer at most is supported.\n\nmethod     | url                                                                       | file path                         | controller name\n---        | ---                                                                       | ---                               | ---\n**GET**    | `/doc/api/{parents}/:parent_id/{children}/:child_id/{objects}?per_page={per_page}\u0026page={page}` | `app/api/{parents}/{objects}.js` | **index()**\n**GET**    | `/doc/api/{parents}/:parent_id/{children}/:child_id/{objects}/:id`                             | `app/api/{parents}/{objects}.js` | **show()**\n**POST**   | `/doc/api/{parents}/:parent_id/{children}/:child_id/{objects}`                                 | `app/api/{parents}/{objects}.js` | **create()**\n**PUT**    | `/doc/api/{parents}/:parent_id/{children}/:child_id/{objects}/:id`                             | `app/api/{parents}/{objects}.js` | **update()**\n**DELETE** | `/doc/api/{parents}/:parent_id/{children}/:child_id/{objects}/:id[s]`                          | `app/api/{parents}/{objects}.js` | **destroy()**\n\nExample: `/api/users/3/posts/1/replies/2` =\u003e params: `{ parent_id: 3, child_id: 2, id: 1 }`. The idea is that you can can retrieve the ids from `this.params`,\nwhich you get values of `{ users: '3', posts: '1', replies: '2' }`. It matches the file path `/api/users/3/posts/1/replies/2`.\n\n**Note:** It does not support more than three level deep nesting. Example: `/api/users/3/posts/1/replies/2/answer` won't match file path\n`api/users/posts/replies/answer.js`. Currently, it can only retrieve maximum three query parameters.\n\nControllers can be loaded from `index.js` in parent directory.\n\nExample: `/doc/api/{parents}` =\u003e `app/api/{parents}/index.js`\n\n---\n\n## Resource Conventions\n\nAll RESTful API __must and will__ respond data with JSON format, following the JSON API spec.\n\nA JSON object MUST be at the root of every JSON API request and response containing data. This object defines a document’s “top level”.\n\n\nA document MUST contain at least one of the following top-level members:\n\n- meta: a meta object that contains non-standard meta-information, eg. paging info\n- links: a links object related to the primary data.\n- linked: resource objects linked in a relationship. When fetched, the related resource object(s) are returned as the response’s primary data.\n- data: the document’s “primary data”\n\nPrimary data MUST be either:\n\n- a single resource object, a single resource identifier object, or null, for requests that target single resources\n- an array of resource objects, an array of resource identifier objects, or an empty array ([]), for requests that target resource collections\n\nWhy should we use the 'data' field as the entry of accessing primary data, instead of respond with it directly?\nIn same cases, such as searching API, paging meta info is required other than primary data.\n\n### Single Resource Object\n\nHere’s how an post (i.e. a resource of type “post”) might appear in a document:\n\n```js\n{\n  \"data\": {\n    \"id\": \"1\",\n    // ... attributes of this post\n  }\n}\n```\n\nRepresent the post with just an id:\n\n```js\n{\n  \"data\": \"1\"\n}\n```\n\n### Resource Collection\n\n```js\n{\n  \"data\": [{\n    \"id\": \"1\"\n    // ... attributes of this post\n  }, {\n    \"id\": \"2\"\n    // ... attributes of this post\n  }],\n  \"meta\": {\n    \"count\": 100 // totol number of posts\n  }\n}\n```\n\nRepresent posts with an array of post Ids:\n\n```js\n{\n  \"data\": [\"1\", \"2\"]\n}\n```\n\n### Resource Fields\n\nFour reserved fields:\n\n- \"id\"\n- \"type\"\n- \"href\"\n- \"links\"\n\n---\n\n## Resource Searching `GET /doc/api/{objects}[?page={page}\u0026per_page={per_page}]`\n\n### Request\n\n```js\nGET /doc/api/users?per_page=2\nAccept: application/json\n```\n\n### Controller\n\nController `exports.index` will be loaded automatically.\n\nPaging params must be accessed by `this.params.page` and `this.params.per_page`.\nAnd both of them must be numbers.\n\n```js\n// app/api/user.js\n// routing: GET /doc/api/users\nexports.index = function* (next) {\n  // coding as a common controller\n  var users = yield uic.listUser({limit: this.params.per_page});\n  // totol number of users\n  var total = yield uic.total();\n\n  // set meta info\n  this.meta = {\n    total: total\n  };\n  this.data = users;\n};\n```\n\n### Response\n\n- `200 OK`: the resource exists, accessing it successfully\n\n```bash\nHTTP/1.1 200 OK\nContent-Type: application/json\n\n{\n  \"data\": [{\n    \"id\": 1024,\n    \"name\": \"shaoshuai0102\",\n    \"mobile\": '186xxxxxxxx'\n  }, {\n    \"id\": 1025,\n    \"name\": \"fengmk2\",\n    \"mobile\": '186xxxxxxxx'\n  }],\n  \"meta\": {\n    \"total\": 100000\n  }\n}\n```\n\n---\n\n## Fetching One Single Resource Document `GET /doc/api/{objects}/:id`\n\n### Request\n\n```bash\nGET /doc/api/users/1024\nAccept: application/json\n```\n\n### Controller\n\nController `exports.show` will be loaded automatically.\n\n```js\n// app/api/user.js\n// routing: GET /doc/api/users/:id\nexports.show = function* (next) {\n  // coding as a common controller\n  var user = yield uic.getUser(this.params.id);\n  if (!user) {\n    return yield* next;\n  }\n  this.data = user;\n};\n```\n\n### Response\n\n- `200 OK`: the resource exists, accessing it successfully\n\n```bash\nHTTP/1.1 200 OK\nContent-Type: application/json\n\n{\n  \"data\": {\n    \"id\": 1024,\n    \"name\": \"苏千\",\n    \"mobile\": '186xxxxxxxx'\n  }\n}\n```\n\n---\n\n## Fetching A Resource Collection `GET /doc/api/{objects}/:ids`\n\n### Request\n\n`GET /doc/api/users/:ids`, multiple ids are seperated with comma.\n\n```bash\nGET /doc/api/users/1024,10,111\nAccept: application/json\n```\n\n### Controller\n\nController `exports.show` will be loaded automatically.\n\nMultiple id can be accessed with `this.params.ids` as an array, if you want to support multiple id.\n\n```js\n// app/api/user.js\n// routing: GET /doc/api/users/:ids\nexports.show = function* (next) {\n  // coding as a common controller\n  const users = yield userService.listUsers(this.params.ids);\n  this.data = users;\n};\n```\n\n### Response\n\n- `200 OK`: the resource exists, accessing it successfully\n\n```bash\nHTTP/1.1 200 OK\nContent-Type: application/json\n\n{\n  \"data\": [{\n    \"id\": 1024,\n    \"name\": \"fengmk2\",\n    \"mobile\": '186xxxxxxxx'\n  }, {\n    \"id\": 10,\n    \"name\": \"shaoshuai0102\",\n    \"mobile\": '186xxxxxxxx'\n  }]\n}\n```\n\n---\n\n## Creating Resources `POST /doc/api/{objects}`\n\n### Request\n\nMust be a `POST` request:\n\n```bash\nPOST /doc/api/users\nContent-Type: application/json\nAccept: application/json\n\n{\n  \"name\": \"fengmk2\",\n  \"mobile\": '186xxxxxxxx'\n}\n```\n\n### Controller\n\nController `exports.create` will be loaded automatically.\n\n```js\n// app/api/user.js\n// Routing: POST /doc/api/users\nexports.create = function* (next) {\n  var newUser = this.params.data;\n  var user = yield userService.create(newUser);\n  this.data = user;\n};\n```\n\n### Response\n\nWhen resource document is created successfully, `201 Created` is returned, with the created document as the body.\n\n```bash\nHTTP/1.1 201 Created\nContent-Type: application/json\n\n{\n  \"data\": {\n    \"id\": 1024,\n    \"name\": \"fengmk2\",\n    \"mobile\": '186xxxxxxxx'\n  }\n}\n```\n\n---\n\n## Updating Resources `PUT /doc/api/{objects}/:id`\n\n### Request\n\nMust be a `PUT` request.\n\nIn the example below, only `mobile` field is updated:\n\n```bash\nPUT /doc/api/users/1024\nContent-Type: application/json\nAccept: application/json\n\n{\n  \"mobile\": '186xxxxxxxx'\n}\n```\n\n### Controller\n\nController `exports.update` is loaded automatically.\n\n```js\n// app/api/user.js\n// Routing: PUT /doc/api/users/:id\nexports.update = function* (next) {\n  var user = this.params.data;\n  yield userService.update(user);\n};\n```\n\n### Response\n\n- `204 No Content`: when an update is successful and the server\ndoesn’t update any attributes besides those provided,\nthe server MUST return `204 No Content` without the document.\n\n```bash\nHTTP/1.1 204 No Content\n```\n\n- `200 OK`: If a server accepts an update but also changes the\nresource(s) in ways other than those specified by the request\n(for example, updating the updated-at attribute or a computed sha),\nit MUST return a 200 OK response.\nThe response document MUST include a representation of the updated\nresource(s) as if a GET request was made to the request URL.\n\n```bash\nHTTP/1.1 200 OK\nContent-Type: application/json\n\n{\n  \"data\": {\n    \"id\": 1024,\n    \"name\": \"fengmk2\",\n    \"mobile\": '186xxxxxxxx'\n  }\n}\n```\n\n---\n\n## Deleting Resources `DELETE /doc/api/{objects}/:id[s]`\n\n### Request\n\n- Deleting one single resource document\n\n```bash\nDELETE /doc/api/users/1024\n```\n\n- Deleting multiple resource documents\n\n```bash\nDELETE /doc/api/users/1024,100,100023\n```\n\n### Controller\n\nController `exports.destroy` will be loaded automatically.\n\nMultiple id can be accessed with `this.params.ids` as an array, if you want to support multiple id.\n\n```js\n// app/api/user.js\n// Routing: DELETE /doc/api/users/:id\nexports.destroy = function* (next) {\n  yield userService.update(this.params.id);\n  // or `this.params.ids` for multiple id\n};\n```\n\n### Response\n\n- `204 No Content`: If a server deletes the document(s) successfully, it MUST return `204 No Content`.\n\n```bash\nHTTP/1.1 204 No Content\n```\n\n---\n\n## Errors\n\nAn error object is a special resource, with additional information about problems encountered while performing an operation.\n\n## Semantic Status Code\n\n### Success codes\n\n- `201 Created` should be used when creating content (INSERT),\n- `202 Accepted` should be used when a request is queued for background processing (async tasks),\n- `204 No Content` should be used when the request was properly executed but no content was returned (a good example would be when you delete something).\n\n### Client error codes\n\n- `400 Bad Request` should be used when there was an error while processing the request payload (malformed JSON, for instance).\n- `401 Unauthorized` should be used when a request is not authenticiated (wrong access token, or username or password).\n- `403 Forbidden` should be used when the request is successfully authenticiated (see 401), but the action was forbidden.\n- `406 Not Acceptable` should be used when the requested format is not available (for instance, when requesting an XML resource from a JSON only server).\n- `410 Gone` Should be returned when the requested resource is permenantely deleted and will never be available again.\n- `422 Unprocessable entity` Could be used when there was a validation error while creating an object.\n\n### Server error codes\n\n- `500 Internal Server Error` should be used when server unexpected error happend.\n\nA more complete list of status codes can be found in [RFC2616](http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html).\n\n## Server Error(5xx) Example\n\nUsually detailed error information will be hidden in production to prevent security issues for code leaking\nDetailed error information can be found in `$HOME/logs/$APPNAME/common-error.log`.\n\n```bash\nHTTP/1.1 500 Server Error\n\n{\n  \"message\": \"Internal Server Error\"\n}\n```\n\nDetailed infomation will be returned in development. It's helpful when developing and debuging.\n\n```json\n{\n  \"message\": \"TypeError: foo.bar is undefined\",\n  \"stack\": \"TypeError: foo.bar is undefined\\n    at Object.checkAuth (/Users/...\"\n}\n```\n\n## Client Error(4xx) Example\n\nRef: https://developer.github.com/v3/#client-errors\n\n### 404\n\nhttps://api.github.com/gists/df2d46e24563df97cd9b\n\n```bash\nHTTP/1.1 404 Not Found\n\n{\n  \"message\": \"Not Found\",\n  \"documentation_url\": \"https://developer.github.com/v3\"\n}\n```\n\n### 400\n\nThere's a problem when parsing the recieved data as JSON.\n\n```bash\nHTTP/1.1 400 Bad Request\n\n{\n  \"message\": \"Problems parsing JSON\"\n}\n```\n\nThe recieved data is not a JSON object.\n\n```bash\nHTTP/1.1 400 Bad Request\n\n{\n  \"message\": \"Body should be a JSON object\"\n}\n```\n\n### 422 Unprocessable Entity\n\nParam validation failed.\n\n```bash\nHTTP/1.1 422 Unprocessable Entity\n\n{\n  \"message\": \"Validation Failed\",\n  \"errors\": [\n    {\n      \"field\": \"username\",\n      \"code\": \"missing_field\",\n      \"message\": \"username required\"\n    }\n  ]\n}\n```\n\n### 401 Unauthorized\n\nAuthorization failed\n\n```bash\n$ curl -i localhost/doc/api/users/1 -u foo:bar\n\nHTTP/1.1 401 Unauthorized\n\n{\n  \"message\": \"Bad credentials\"\n}\n```\n\n## User-Agent is Required\n\nhttps://developer.github.com/v3/#user-agent-required\n\n```bash\n$ curl -iH 'User-Agent: ' https://api.github.com/meta\nHTTP/1.0 403 Forbidden\n\n{\n  \"message\": \"Please make sure your request has a User-Agent header\"\n}\n```\n\n## Parameter Validation\n\nRest plugin provides a way of validating request params.\n\nFor more details of validating rules, see [parameter](https://github.com/node-modules/parameter).\n\n### `createRule` and `updateRule`\n\n```js\n// Specify validation rules of create request\n// If failed, '422' will be returned automatically\nexports.createRule = {\n  username: 'email',\n  password: {\n    type: 'password',\n    compare: 're-password'\n  },\n  age: {\n    type: 'int',\n    required: false\n  }\n};\n\nexports.create = function* () {\n  var user = this.params.data;\n  // handle user\n};\n\n// Specify validation rules of create request\nexports.updateRule = {\n  age: {\n    type: 'int',\n    required: false\n  }\n};\n\nexports.update = function* () {\n\n};\n```\n\nValidation failure example:\n\n```bash\nHTTP/1.1 422 Unprocessable Entity\n\n{\n  \"message\": \"Validation Failed\",\n  \"errors\": [\n    {\n      \"field\": \"username\",\n      \"code\": \"invalid\",\n      \"message\": \"username should be an email\"\n    },\n    {\n      \"field\": \"password\",\n      \"code\": \"missing_field\",\n      \"message\": \"password required\"\n    },\n    {\n      \"field\": \"age\",\n      \"code\": \"invalid\",\n      \"message\": \"age should be an integer\"\n    }\n  ]\n}\n```\n\n### Execute Validation Manually\n\nIn most cases, the automatic way above is just fine.\nBut sometimes we need do the validation manualy.\nSo we can use `this.validate(rules[, data])`\n\n```js\nvar createRule = {...};\n\nexports.create = function* () {\n  var user = this.params.data;\n\n  // If validation failed, status 422 will be returned\n  this.validate(createRule, user);\n\n  // handle user\n};\n```\n\n## Custom Authentication\n\nIf you want to add request authentication, configure it with `rest.authRequest` in `config/config.default.js`:\n\n```js\nexports.rest = {\n  enable: true,\n  authIgnores: {\n    // allow users.show() and users.index() to ignore authentication\n    users: {\n      show: true,\n      index: true\n    }\n  },\n  authRequest: function* (ctx) {\n    if (ctx.query.private_token === 'admintoken-123') {\n      // If authentication succeeds, the info returned below can be accessed with `this.accessToken` in controller.\n      return {\n        name: 'admin'\n      };\n    }\n\n    // authentication failure\n    return null;\n  }\n};\n```\n\nFor `user.create()`, `user.update()` and `user.destroy()`, they will be invoked only after passing authentication.\n\nAuthentication failure response:\n\n```bash\nHTTP/1.1 401 Unauthorized\n\n{\n  \"message\": \"Bad credentials\"\n}\n```\n\n## Ref\n\n- [JSON API Spec](http://jsonapi.org.cn/format/)\n- [REST: Representational State Transfer](http://zh.wikipedia.org/zh/REST)\n- [ome REST best practices](https://bourgeois.me/rest/)\n- [Restful routing using resourceful and director](https://npm.taobao.org/package/restful)\n- [Rails Routing from the Outside In](http://guides.rubyonrails.org/routing.html)\n- [HTTP API design guide extracted from work on the Heroku Platform API](https://github.com/interagent/http-api-design)\n- [ctoken](https://github.com/eggjs/egg-security#ctoken)\n\n\n## License\n\n[MIT](LICENSE)\n","funding_links":[],"categories":["Plugins","仓库"],"sub_categories":["插件"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feggjs%2Fegg-rest","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feggjs%2Fegg-rest","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feggjs%2Fegg-rest/lists"}