├── .babelrc ├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .travis.yml ├── LICENSE.md ├── README.md ├── README_CN.md ├── assets └── uploads │ └── .gitkeep ├── ecosystem.config.js ├── gulpfile.js ├── logs └── .gitkeep ├── package-lock.json ├── package.json ├── sql └── x-restful-api-generator-koa.sql ├── src ├── api.js ├── app.js ├── apps │ ├── Articles │ │ ├── Ctrl.js │ │ ├── Model.js │ │ └── Routers.js │ ├── Files │ │ ├── Ctrl.js │ │ ├── Model.js │ │ ├── Routers.js │ │ └── upload.html │ └── demoModule_001 │ │ ├── Ctrl.js │ │ ├── Model.js │ │ └── Routers.js ├── auth.js ├── config.js ├── db.js ├── middleware │ └── index.js ├── routers.js ├── schema │ └── articles.js ├── server.js └── utils │ ├── index.js │ └── log.js ├── static └── .gitkeep └── test └── appListen.test.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "stage-2"], 3 | "plugins": ["transform-runtime"] 4 | } 5 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | build/*.js 2 | assets/*.js 3 | src/schema/*.js 4 | src/apps/Files/*.html 5 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parserOptions: { 4 | // 指定ECMAScript支持的版本,6为ES6,这里为了兼容async和await,设置为8 5 | ecmaVersion: 8, 6 | sourceType: 'module' 7 | }, 8 | extends: 'standard', 9 | plugins: [ 10 | 'html', 11 | 'promise' 12 | ], 13 | env: { 14 | 'node': true 15 | }, 16 | rules: { 17 | // allow console 18 | 'no-console': 0, 19 | // allow paren-less arrow functions 20 | 'arrow-parens': 0, 21 | // allow async-await 22 | 'generator-star-spacing': 0, 23 | // allow debugger during development 24 | 'no-debugger': 0 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | npm-debug.log 4 | test/unit/coverage 5 | test/e2e/reports 6 | selenium-debug.log 7 | .idea/ 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - stable 4 | - "7.6.0" 5 | install: 6 | - travis_wait npm install 7 | script: 8 | - npm run test 9 | - npm run cov 10 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017-present, OXOYO 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # X-RESTful-API-Generator-Koa 2 | 3 | A RESTful API service generator by Koa. 4 | 5 | [ ](https://travis-ci.org/OXOYO/X-RESTful-API-Generator-Koa) 6 | [](https://codecov.io/github/OXOYO/X-RESTful-API-Generator-Koa?branch=master) 7 | [](https://nodejs.org/) 8 | []() 9 | [](https://david-dm.org/OXOYO/X-RESTful-API-Generator-Koa) 10 | [](https://codebeat.co/projects/github-com-oxoyo-x-restful-api-generator-koa-master) 11 | []() 12 | [](https://gitter.im/X-RESTful-API-Generator-Koa/chat) 13 | 14 | English | [简体中文](./README_CN.md) 15 | 16 | ## Start 17 | ```bash 18 | # clone 19 | git clone 20 | 21 | # install dependencies 22 | npm i 23 | 24 | # import the src/x-restful-api-generator-koa.sql into the database. 25 | 26 | # start serve with hot reload 27 | npm run dev 28 | ``` 29 | Node.js >= 7.6.0 required. 30 | 31 | ## Develop Step 32 | 1.Edit config.js 33 | 34 | 2.Export the database to schema by [sequelize-auto](https://github.com/sequelize/sequelize-auto) 35 | 36 | ```bash 37 | npm -g install mysql 38 | sequelize-auto -o "./src/schema" -d x-restful-api-generator-koa -h localhost -u root -p 3306 -e mysql 39 | ``` 40 | 41 | 3.Create module directories and files 42 | ```bash 43 | apps 44 | \_ newModules 45 | Ctrl.js 46 | Model.js 47 | Routers.js 48 | ``` 49 | 50 | ## Build 51 | ```bash 52 | npm run build 53 | ``` 54 | 55 | ## production 56 | ```bash 57 | pm2 start ecosystem.config.js --name x-restful-api-generator-koa --env production 58 | ``` 59 | 60 | ## Demo 61 | 62 | To run the demo, you need to import the `./src/x-restful-api-generator-koa.sql` into Mysql 63 | 64 | ### demoModule_001 65 | URL: http://localhost:3000/x-restful-api-generator-koa/demoModule_001/login 66 | 67 | Resonse: 68 | ```bash 69 | { 70 | "code": 200, 71 | "msg": "登录成功!", 72 | "data": { 73 | "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyTmFtZSI6InRlc3QiLCJwYXNzd29yZCI6IjEyMzQ1NiIsImlhdCI6MTUwODkyMTY2OSwiZXhwIjoxNTA5MDA4MDY5fQ.2occtME3kLUDxntJXOz5e1dkspybGIVqbDPRgaE6lZA" 74 | } 75 | } 76 | ``` 77 | 78 | URL: http://localhost:3000/x-restful-api-generator-koa/demoModule_001/list 79 | 80 | Response: 81 | ```bash 82 | { 83 | "code": 200, 84 | "msg": "查询列表成功!", 85 | "data": { 86 | "count": 300, 87 | "list": [] 88 | } 89 | } 90 | ``` 91 | 92 | URL: http://localhost:3000/x-restful-api-generator-koa/demoModule_001/verify/list 93 | 94 | Response: 95 | ```bash 96 | { 97 | "code": 9999, 98 | "msg": "token无效!请重新登录!", 99 | "data": {} 100 | } 101 | ``` 102 | 103 | ### Articles 104 | 105 | URL: http://localhost:3000/x-restful-api-generator-koa/articles/add 106 | 107 | Request Body: 108 | ```bash 109 | { 110 | title: 'myArticle_001' 111 | content: 'yyyyyyyyyyyyyyyyyyyyyyy' 112 | } 113 | ``` 114 | 115 | Response: 116 | ```bash 117 | { 118 | "code": 200, 119 | "msg": "添加文章成功!", 120 | "data": { 121 | "id": 3, 122 | "title": "myArticle_001", 123 | "content": "yyyyyyyyyyyyyyyyyyyyyyy", 124 | "updatedAt": "2017-10-27T07:52:21.745Z", 125 | "createdAt": "2017-10-27T07:52:21.745Z" 126 | } 127 | } 128 | ``` 129 | 130 | URL: http://localhost:3000/x-restful-api-generator-koa/articles/update 131 | 132 | Request Body: 133 | ```bash 134 | { 135 | id: '3' 136 | content: 'xxxxxx' 137 | } 138 | ``` 139 | 140 | Response: 141 | ```bash 142 | { 143 | "code": 200, 144 | "msg": "编辑文章成功!", 145 | "data": { 146 | "id": 3, 147 | "title": "myArticle_003", 148 | "content": "xxxxxx", 149 | "createdAt": "2017-10-26T23:52:21.000Z", 150 | "updatedAt": "2017-10-27T00:08:55.000Z" 151 | } 152 | } 153 | ``` 154 | 155 | URL: http://localhost:3000/x-restful-api-generator-koa/articles/remove 156 | 157 | Request Body: 158 | ```bash 159 | { 160 | id: '2' 161 | } 162 | ``` 163 | 164 | Response: 165 | ```bash 166 | { 167 | "code": 200, 168 | "msg": "删除文章成功!", 169 | "data": 1 170 | } 171 | ``` 172 | 173 | URL: http://localhost:3000/x-restful-api-generator-koa/articles/list?pageSize=1¤tPage=1 174 | 175 | Response: 176 | ```bash 177 | { 178 | "code": 200, 179 | "msg": "查询账号列表成功!", 180 | "data": { 181 | "count": 2, 182 | "list": [ 183 | { 184 | "id": 1, 185 | "title": "myArticle_001", 186 | "content": "yyyyyyyyyyyyyyyyyyyyyyy", 187 | "createdAt": "2017-10-26T23:46:10.000Z", 188 | "updatedAt": "2017-10-26T23:46:10.000Z" 189 | } 190 | ] 191 | } 192 | } 193 | ``` 194 | 195 | ### File Upload 196 | URL: http://localhost:63342/X-RESTful-API-Generator-Koa/src/apps/Files/upload.html 197 | 198 | Response: 199 | ```bash 200 | { 201 | "status": 200, 202 | "msg": "上传成功!", 203 | "data": { 204 | "file": { 205 | "fieldname": "file", 206 | "originalname": "app.png", 207 | "encoding": "7bit", 208 | "mimetype": "image/png", 209 | "destination": "E:\\Webstorm_WorkSpace\\X-RESTful-API-Generator-Koa\\assets\\uploads", 210 | "filename": "1510817484098.png", 211 | "path": "E:\\Webstorm_WorkSpace\\X-RESTful-API-Generator-Koa\\assets\\uploads\\1510817484098.png", 212 | "size": 958 213 | }, 214 | "filename": "1510817484098.png", 215 | "url": "//localhost:3000/assets/uploads/1510817484098.png" 216 | } 217 | } 218 | ``` 219 | 220 | ## TODO 221 | 222 | ```bash 223 | 1.error handler middleware 224 | ``` 225 | 226 | ## License 227 | [MIT](http://opensource.org/licenses/MIT) 228 | -------------------------------------------------------------------------------- /README_CN.md: -------------------------------------------------------------------------------- 1 | # X-RESTful-API-Generator-Koa 2 | 3 | 一个基于 Koa 的 RESTful API 服务脚手架。 4 | 5 | [ ](https://travis-ci.org/OXOYO/X-RESTful-API-Generator-Koa) 6 | [](https://codecov.io/github/OXOYO/X-RESTful-API-Generator-Koa?branch=master) 7 | [](https://nodejs.org/) 8 | []() 9 | [](https://david-dm.org/OXOYO/X-RESTful-API-Generator-Koa) 10 | [](https://codebeat.co/projects/github-com-oxoyo-x-restful-api-generator-koa-master) 11 | []() 12 | [](https://gitter.im/X-RESTful-API-Generator-Koa/chat) 13 | 14 | [English](./README.md) | 简体中文 15 | 16 | ## 开始 17 | ```bash 18 | # clone 19 | git clone 20 | 21 | # install dependencies 22 | npm i 23 | 24 | # import the src/x-restful-api-generator-koa.sql into the database. 25 | 26 | # start serve with hot reload 27 | npm run dev 28 | ``` 29 | Node.js 版本需 >= 7.6.0. 30 | 31 | ## 开发步骤 32 | 1.编辑 config.js 33 | 34 | 2.使用 [sequelize-auto](https://github.com/sequelize/sequelize-auto) 将数据库导出为 schema 模型 35 | 36 | ```bash 37 | npm -g install mysql 38 | sequelize-auto -o "./src/schema" -d x-restful-api-generator-koa -h localhost -u root -p 3306 -e mysql 39 | ``` 40 | 41 | 3.创建模块目录、文件 42 | ```bash 43 | apps 44 | \_ newModules 45 | Ctrl.js 46 | Model.js 47 | Routers.js 48 | ``` 49 | 50 | ## 打包 51 | ```bash 52 | npm run build 53 | ``` 54 | 55 | ## 生产环境 56 | ```bash 57 | pm2 start ecosystem.config.js --name x-restful-api-generator-koa --env production 58 | ``` 59 | 60 | ## 栗子🌰 61 | 62 | 运行 demo 需要先将 `./src/x-restful-api-generator-koa.sql` 导入Mysql 63 | 64 | ### demoModule_001 65 | URL: http://localhost:3000/x-restful-api-generator-koa/demoModule_001/login 66 | 67 | Resonse: 68 | ```bash 69 | { 70 | "code": 200, 71 | "msg": "登录成功!", 72 | "data": { 73 | "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyTmFtZSI6InRlc3QiLCJwYXNzd29yZCI6IjEyMzQ1NiIsImlhdCI6MTUwODkyMTY2OSwiZXhwIjoxNTA5MDA4MDY5fQ.2occtME3kLUDxntJXOz5e1dkspybGIVqbDPRgaE6lZA" 74 | } 75 | } 76 | ``` 77 | 78 | URL: http://localhost:3000/x-restful-api-generator-koa/demoModule_001/list 79 | 80 | Response: 81 | ```bash 82 | { 83 | "code": 200, 84 | "msg": "查询列表成功!", 85 | "data": { 86 | "count": 300, 87 | "list": [] 88 | } 89 | } 90 | ``` 91 | 92 | URL: http://localhost:3000/x-restful-api-generator-koa/demoModule_001/verify/list 93 | 94 | Response: 95 | ```bash 96 | { 97 | "code": 9999, 98 | "msg": "token无效!请重新登录!", 99 | "data": {} 100 | } 101 | ``` 102 | 103 | ### Articles 104 | 105 | URL: http://localhost:3000/x-restful-api-generator-koa/articles/add 106 | 107 | Request Body: 108 | ```bash 109 | { 110 | title: 'myArticle_001' 111 | content: 'yyyyyyyyyyyyyyyyyyyyyyy' 112 | } 113 | ``` 114 | 115 | Response: 116 | ```bash 117 | { 118 | "code": 200, 119 | "msg": "添加文章成功!", 120 | "data": { 121 | "id": 3, 122 | "title": "myArticle_001", 123 | "content": "yyyyyyyyyyyyyyyyyyyyyyy", 124 | "updatedAt": "2017-10-27T07:52:21.745Z", 125 | "createdAt": "2017-10-27T07:52:21.745Z" 126 | } 127 | } 128 | ``` 129 | 130 | URL: http://localhost:3000/x-restful-api-generator-koa/articles/update 131 | 132 | Request Body: 133 | ```bash 134 | { 135 | id: '3' 136 | content: 'xxxxxx' 137 | } 138 | ``` 139 | 140 | Response: 141 | ```bash 142 | { 143 | "code": 200, 144 | "msg": "编辑文章成功!", 145 | "data": { 146 | "id": 3, 147 | "title": "myArticle_003", 148 | "content": "xxxxxx", 149 | "createdAt": "2017-10-26T23:52:21.000Z", 150 | "updatedAt": "2017-10-27T00:08:55.000Z" 151 | } 152 | } 153 | ``` 154 | 155 | URL: http://localhost:3000/x-restful-api-generator-koa/articles/remove 156 | 157 | Request Body: 158 | ```bash 159 | { 160 | id: '2' 161 | } 162 | ``` 163 | 164 | Response: 165 | ```bash 166 | { 167 | "code": 200, 168 | "msg": "删除文章成功!", 169 | "data": 1 170 | } 171 | ``` 172 | 173 | URL: http://localhost:3000/x-restful-api-generator-koa/articles/list?pageSize=1¤tPage=1 174 | 175 | Response: 176 | ```bash 177 | { 178 | "code": 200, 179 | "msg": "查询账号列表成功!", 180 | "data": { 181 | "count": 2, 182 | "list": [ 183 | { 184 | "id": 1, 185 | "title": "myArticle_001", 186 | "content": "yyyyyyyyyyyyyyyyyyyyyyy", 187 | "createdAt": "2017-10-26T23:46:10.000Z", 188 | "updatedAt": "2017-10-26T23:46:10.000Z" 189 | } 190 | ] 191 | } 192 | } 193 | ``` 194 | 195 | ### File Upload 196 | URL: http://localhost:63342/X-RESTful-API-Generator-Koa/src/apps/Files/upload.html 197 | 198 | Response: 199 | ```bash 200 | { 201 | "status": 200, 202 | "msg": "上传成功!", 203 | "data": { 204 | "file": { 205 | "fieldname": "file", 206 | "originalname": "app.png", 207 | "encoding": "7bit", 208 | "mimetype": "image/png", 209 | "destination": "E:\\Webstorm_WorkSpace\\X-RESTful-API-Generator-Koa\\assets\\uploads", 210 | "filename": "1510817484098.png", 211 | "path": "E:\\Webstorm_WorkSpace\\X-RESTful-API-Generator-Koa\\assets\\uploads\\1510817484098.png", 212 | "size": 958 213 | }, 214 | "filename": "1510817484098.png", 215 | "url": "//localhost:3000/assets/uploads/1510817484098.png" 216 | } 217 | } 218 | ``` 219 | 220 | ## TODO 221 | 222 | ```bash 223 | 1.error handler middleware 224 | ``` 225 | 226 | ## License 227 | [MIT](http://opensource.org/licenses/MIT) 228 | -------------------------------------------------------------------------------- /assets/uploads/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OXOYO/X-RESTful-API-Generator-Koa/ac4715102d21702d3fc7fac254fc4a8008306313/assets/uploads/.gitkeep -------------------------------------------------------------------------------- /ecosystem.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by OXOYO on 2017/10/31. 3 | */ 4 | 5 | module.exports = { 6 | apps : [ 7 | // 应用配置 8 | { 9 | name: 'x-restful-api-generator-koa', 10 | script: './dist/server.js', 11 | watch: true, 12 | env: { 13 | NODE_ENV: 'development' 14 | }, 15 | env_production : { 16 | NODE_ENV: 'production' 17 | } 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by OXOYO on 2017/10/25. 3 | */ 4 | 5 | const gulp = require('gulp') 6 | const gulpEslint = require('gulp-eslint') 7 | const gulpNodemon = require('gulp-nodemon') 8 | const gulpSequence = require('gulp-sequence') 9 | const eslintFriendlyFormatter = require('eslint-friendly-formatter') 10 | 11 | const config = { 12 | server: { 13 | script: './src/server.js' 14 | } 15 | } 16 | 17 | const lintFiles = (files) => { 18 | return gulp.src( 19 | files 20 | ).pipe( 21 | gulpEslint({ 22 | configFile: './.eslintrc.js' 23 | }) 24 | ).pipe( 25 | gulpEslint.format(eslintFriendlyFormatter) 26 | ).pipe( 27 | gulpEslint.result(results => { 28 | // Called for each ESLint result. 29 | console.log(`ESLint result: ${results.filePath}`) 30 | console.log(`# Messages: ${results.messages.length}`) 31 | console.log(`# Warnings: ${results.warningCount}`) 32 | console.log(`# Errors: ${results.errorCount}`) 33 | }) 34 | ).pipe( 35 | gulpEslint.results(results => { 36 | // Called once for all ESLint results. 37 | console.log(`Total Results: ${results.length}`) 38 | console.log(`Total Warnings: ${results.warningCount}`) 39 | console.log(`Total Errors: ${results.errorCount}`) 40 | }) 41 | ) 42 | } 43 | 44 | // eslint 45 | gulp.task('ESlint', () => { 46 | lintFiles([ 47 | 'src/**', 48 | '!node_modules/**' 49 | ]) 50 | }) 51 | 52 | // nodemon 53 | gulp.task('nodemon', () => { 54 | let stream = gulpNodemon({ 55 | script: config.server.script, 56 | ext: 'js', 57 | env: { 58 | 'NODE_ENV': 'development' 59 | }, 60 | tasks: (changedFiles) => { 61 | lintFiles(changedFiles) 62 | return [] 63 | } 64 | }) 65 | stream.on('restart', () => { 66 | console.log('Service restarted!') 67 | }).on('crash', () => { 68 | console.error('Service has crashed!\n') 69 | // restart the server in 10 seconds 70 | // stream.emit('restart', 10) 71 | }) 72 | }) 73 | 74 | // default 75 | gulp.task('default', () => { 76 | gulpSequence('ESlint', 'nodemon')(() => { 77 | console.log('Service started!') 78 | }) 79 | }) 80 | -------------------------------------------------------------------------------- /logs/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OXOYO/X-RESTful-API-Generator-Koa/ac4715102d21702d3fc7fac254fc4a8008306313/logs/.gitkeep -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "x-restful-api-generator-koa", 3 | "version": "1.0.1", 4 | "description": "A RESTful API service generator by Koa.", 5 | "main": "server.js", 6 | "scripts": { 7 | "test": "npm run build && mocha -u bdd", 8 | "cov": "istanbul cover node_modules/mocha/bin/_mocha && codecov", 9 | "dev": "gulp default", 10 | "start": "gulp default", 11 | "build": "babel src -d dist" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+https://github.com/OXOYO/X-RESTful-API-Generator-Koa.git" 16 | }, 17 | "author": "OXOYO", 18 | "license": "MIT", 19 | "bugs": { 20 | "url": "https://github.com/OXOYO/X-RESTful-API-Generator-Koa/issues" 21 | }, 22 | "homepage": "https://github.com/OXOYO/X-RESTful-API-Generator-Koa#readme", 23 | "dependencies": { 24 | "codecov": "^3.0.0", 25 | "jsonwebtoken": "^8.1.0", 26 | "koa": "^2.3.0", 27 | "koa-bodyparser": "^4.2.0", 28 | "koa-compose": "^4.0.0", 29 | "koa-convert": "^1.2.0", 30 | "koa-cors": "0.0.16", 31 | "koa-generic-session": "^2.0.0", 32 | "koa-helmet": "^3.2.0", 33 | "koa-logger": "^3.1.0", 34 | "koa-multer": "^1.0.2", 35 | "koa-qs": "^2.0.0", 36 | "koa-router": "^7.2.1", 37 | "koa-static": "^4.0.1", 38 | "log4js": "^2.3.11", 39 | "mysql2": "^1.4.2", 40 | "require-directory": "^2.1.1", 41 | "sequelize": "^4.18.0", 42 | "sequelize-auto": "^0.4.29" 43 | }, 44 | "devDependencies": { 45 | "babel-cli": "^6.26.0", 46 | "babel-plugin-transform-runtime": "^6.23.0", 47 | "babel-polyfill": "^6.26.0", 48 | "babel-preset-es2015": "^6.24.1", 49 | "babel-preset-stage-2": "^6.24.1", 50 | "babel-register": "^6.26.0", 51 | "babel-runtime": "^6.26.0", 52 | "eslint-config-standard": "^10.2.1", 53 | "eslint-friendly-formatter": "^3.0.0", 54 | "eslint-plugin-html": "^3.2.2", 55 | "eslint-plugin-import": "^2.8.0", 56 | "eslint-plugin-node": "^5.2.1", 57 | "eslint-plugin-promise": "^3.6.0", 58 | "eslint-plugin-standard": "^3.0.1", 59 | "gulp": "^3.9.1", 60 | "gulp-eslint": "^4.0.0", 61 | "gulp-nodemon": "^2.2.1", 62 | "gulp-sequence": "^0.4.6", 63 | "istanbul": "^0.4.5", 64 | "mocha": "^4.0.1", 65 | "nodemon": "^1.12.1", 66 | "supertest": "^3.0.0" 67 | }, 68 | "engines": { 69 | "node": ">= 7.6.0", 70 | "npm": ">= 4.1.2" 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /sql/x-restful-api-generator-koa.sql: -------------------------------------------------------------------------------- 1 | -- phpMyAdmin SQL Dump 2 | -- version 4.6.4 3 | -- https://www.phpmyadmin.net/ 4 | -- 5 | -- Host: 127.0.0.1 6 | -- Generation Time: 2017-10-27 16:24:41 7 | -- 服务器版本: 5.7.14 8 | -- PHP Version: 5.6.25 9 | 10 | SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; 11 | SET time_zone = "+00:00"; 12 | 13 | 14 | /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; 15 | /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; 16 | /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; 17 | /*!40101 SET NAMES utf8mb4 */; 18 | 19 | -- 20 | -- Database: `x-restful-api-generator-koa` 21 | -- 22 | 23 | -- -------------------------------------------------------- 24 | 25 | -- 26 | -- 表的结构 `articles` 27 | -- 28 | 29 | CREATE TABLE `articles` ( 30 | `id` int(11) NOT NULL, 31 | `title` varchar(100) NOT NULL, 32 | `content` varchar(600) NOT NULL, 33 | `createdAt` timestamp NOT NULL, 34 | `updatedAt` timestamp NOT NULL 35 | ) ENGINE=MyISAM DEFAULT CHARSET=utf8; 36 | 37 | -- 38 | -- 转存表中的数据 `articles` 39 | -- 40 | 41 | INSERT INTO `articles` (`id`, `title`, `content`, `createdAt`, `updatedAt`) VALUES 42 | (1, 'myArticle_001', 'yyyyyyyyyyyyyyyyyyyyyyy', '2017-10-27 07:46:10', '2017-10-27 07:46:10'), 43 | (3, 'myArticle_003', 'xxxxxx', '2017-10-27 07:52:21', '2017-10-27 08:08:55'); 44 | 45 | -- 46 | -- Indexes for dumped tables 47 | -- 48 | 49 | -- 50 | -- Indexes for table `articles` 51 | -- 52 | ALTER TABLE `articles` 53 | ADD PRIMARY KEY (`id`); 54 | 55 | -- 56 | -- 在导出的表使用AUTO_INCREMENT 57 | -- 58 | 59 | -- 60 | -- 使用表AUTO_INCREMENT `articles` 61 | -- 62 | ALTER TABLE `articles` 63 | MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=4; 64 | /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; 65 | /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; 66 | /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; 67 | -------------------------------------------------------------------------------- /src/api.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by OXOYO on 2017/10/23. 3 | */ 4 | 5 | import compose from 'koa-compose' 6 | import Router from 'koa-router' 7 | 8 | // 导入配置信息 9 | import { Api as ApiConfig } from './config' 10 | // 导入路由表 11 | import routers from './routers' 12 | 13 | export default function api () { 14 | let router = new Router({ prefix: ApiConfig.prefix }) 15 | Object.keys(routers).forEach(name => routers[name](router)) 16 | // 添加根路由 17 | router.get('/', async (ctx, next) => { 18 | await next() 19 | ctx.status = 200 20 | ctx.body = {} 21 | }) 22 | 23 | return compose([ 24 | router.routes(), 25 | router.allowedMethods({ 26 | throw: true 27 | }) 28 | ]) 29 | } 30 | -------------------------------------------------------------------------------- /src/app.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by OXOYO on 2017/10/23. 3 | */ 4 | 5 | import Koa from 'koa' 6 | 7 | import middleware from './middleware' 8 | import utils from './utils' 9 | import api from './api' 10 | 11 | const app = new Koa() 12 | const env = process.env.NODE_ENV || 'development' 13 | 14 | // 注册log 15 | app.use(async (ctx, next) => { 16 | let startTime = new Date() 17 | let ms 18 | try { 19 | await next() 20 | ms = new Date() - startTime 21 | utils.log.response(ctx, ms) 22 | } catch (err) { 23 | ms = new Date() - startTime 24 | utils.log.error(ctx, err, ms) 25 | } 26 | }) 27 | 28 | // 注册qs 29 | require('koa-qs')(app) 30 | // 注册路由 31 | app.use(api()) 32 | // 注册中间件 33 | app.use(middleware(app)) 34 | 35 | if (env === 'development') { 36 | // logger 37 | app.use((ctx, next) => { 38 | const start = new Date() 39 | return next().then(() => { 40 | const ms = new Date() - start 41 | console.log(`${ctx.method} ${ctx.url} - ${ms}ms`) 42 | }) 43 | }) 44 | } 45 | 46 | app.on('error', function (err, ctx) { 47 | console.log('Service error', err) 48 | }) 49 | 50 | exports = module.exports = app 51 | -------------------------------------------------------------------------------- /src/apps/Articles/Ctrl.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by OXOYO on 2017/10/27. 3 | */ 4 | 5 | import Model from './Model' 6 | 7 | export default { 8 | getList: async (ctx, next) => { 9 | await next() 10 | let reqQuery = ctx.query 11 | // 查询结果 12 | let res = await Model.getList(reqQuery) 13 | // 处理结果 14 | if (res) { 15 | res = { 16 | code: 200, 17 | msg: '查询账号列表成功!', 18 | data: { 19 | count: res.count, 20 | list: res.rows 21 | } 22 | } 23 | } else { 24 | res = { 25 | code: 5000, 26 | msg: '查询账号列表失败!', 27 | data: {} 28 | } 29 | } 30 | 31 | ctx.body = res || {} 32 | }, 33 | // 添加账号 34 | doAdd: async (ctx, next) => { 35 | await next() 36 | // 查询结果 37 | let reqBody = ctx.request.body 38 | let timeNow = new Date() 39 | let data = { 40 | ...reqBody, 41 | createdAt: timeNow, 42 | updatedAt: timeNow 43 | } 44 | let res 45 | if (data && data.title && data.content) { 46 | res = await Model.doAdd(data) 47 | // 最后一项为插入成功与否标识 48 | let [resAccount] = res 49 | let isSuccess = res.pop() 50 | // 处理结果 51 | if (isSuccess) { 52 | res = { 53 | code: 200, 54 | msg: '添加文章成功!', 55 | data: resAccount 56 | } 57 | } else if (resAccount) { 58 | res = { 59 | code: 5000, 60 | msg: '添加文章失败,该文章已存在!', 61 | data: resAccount 62 | } 63 | } else { 64 | res = { 65 | code: 5000, 66 | msg: '添加文章失败!', 67 | data: {} 68 | } 69 | } 70 | } else { 71 | res = { 72 | code: 5001, 73 | msg: '添加文章失败,上送参数有误!', 74 | data: {} 75 | } 76 | } 77 | 78 | ctx.body = res || {} 79 | }, 80 | doUpdate: async (ctx, next) => { 81 | await next() 82 | let reqBody = ctx.request.body 83 | let timeNow = new Date() 84 | let data = { 85 | ...reqBody, 86 | updatedAt: timeNow 87 | } 88 | let res 89 | if (data) { 90 | res = await Model.doUpdate(data) 91 | // 处理结果 92 | if (res) { 93 | let detail = await Model.getDetail(data) 94 | res = { 95 | code: 200, 96 | msg: '编辑文章成功!', 97 | data: detail 98 | } 99 | } else { 100 | res = { 101 | code: 5000, 102 | msg: '编辑文章失败!', 103 | data: {} 104 | } 105 | } 106 | } else { 107 | res = { 108 | code: 5001, 109 | msg: '编辑文章失败,上送参数有误!', 110 | data: {} 111 | } 112 | } 113 | 114 | ctx.body = res || {} 115 | }, 116 | doRemove: async (ctx, next) => { 117 | await next() 118 | let reqBody = ctx.request.body 119 | let data = reqBody 120 | let res 121 | if ((Object.keys(data)).length) { 122 | res = await Model.doRemove(data) 123 | // 处理结果 124 | if (res) { 125 | res = { 126 | code: 200, 127 | msg: '删除文章成功!', 128 | data: res 129 | } 130 | } else { 131 | res = { 132 | code: 5000, 133 | msg: '删除文章失败!', 134 | data: {} 135 | } 136 | } 137 | } else { 138 | res = { 139 | code: 5001, 140 | msg: '删除文章失败,上送参数有误!', 141 | data: {} 142 | } 143 | } 144 | 145 | ctx.body = res || {} 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /src/apps/Articles/Model.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by OXOYO on 2017/10/27. 3 | */ 4 | 5 | import db from '../../db' 6 | 7 | const articlesModel = '../../schema/articles' 8 | const articlesSchema = db.import(articlesModel) 9 | 10 | export default { 11 | getList: async (data) => { 12 | let options = {} 13 | // 处理分页 14 | let pageSize = data.pageSize || 10 15 | let currentPage = data.currentPage || 1 16 | options['limit'] = parseInt(pageSize) 17 | options['offset'] = parseInt((currentPage - 1) * pageSize) 18 | // 拼装where条件 19 | let whereObj = {} 20 | // 处理关键词过滤 21 | let filterType = data.filterType || null 22 | if (filterType && data.keywords) { 23 | // 模糊匹配 24 | whereObj[filterType] = { 25 | $like: '%' + data.keywords + '%' 26 | } 27 | } 28 | if ((Object.keys(whereObj)).length) { 29 | options['where'] = whereObj 30 | } 31 | let res = await articlesSchema.findAndCountAll(options) 32 | return res 33 | }, 34 | // 添加账号 35 | doAdd: async (data) => { 36 | let res = await articlesSchema.findOrCreate({ 37 | where: { 38 | title: data.title 39 | }, 40 | defaults: data 41 | }) 42 | return res 43 | }, 44 | doUpdate: async (data) => { 45 | let res = await articlesSchema.update(data, { 46 | where: { 47 | id: data.id 48 | } 49 | }) 50 | return res 51 | }, 52 | doRemove: async (data) => { 53 | // 删除账号 54 | let res = await articlesSchema.destroy({ 55 | 'where': { 56 | 'id': Object.values(data) 57 | } 58 | }) 59 | return res 60 | }, 61 | getDetail: async (data) => { 62 | let res = await articlesSchema.findById(data.id) 63 | return res 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/apps/Articles/Routers.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by OXOYO on 2017/10/27. 3 | */ 4 | 5 | import Ctrl from './Ctrl' 6 | import auth from '../../auth' 7 | 8 | const namespace = '/articles/' 9 | 10 | export default (router) => { 11 | router 12 | // full path: 13 | // http://localhost:3000/x-restful-api-generator-koa/articles/verify/list 14 | .get(namespace + 'verify/list', auth.verify, Ctrl.getList) 15 | // full path: 16 | // http://localhost:3000/x-restful-api-generator-koa/articles/list 17 | .get(namespace + 'list', Ctrl.getList) 18 | // full path: 19 | // http://localhost:3000/x-restful-api-generator-koa/articles/add 20 | .post(namespace + 'add', Ctrl.doAdd) 21 | // full path: 22 | // http://localhost:3000/x-restful-api-generator-koa/articles/update 23 | .post(namespace + 'update', Ctrl.doUpdate) 24 | // full path: 25 | // http://localhost:3000/x-restful-api-generator-koa/articles/remove 26 | .post(namespace + 'remove', Ctrl.doRemove) 27 | } 28 | -------------------------------------------------------------------------------- /src/apps/Files/Ctrl.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by OXOYO on 2017/11/1. 3 | */ 4 | const path = require('path') 5 | const multer = require('koa-multer') 6 | 7 | export default { 8 | doUpload: async (ctx, next) => { 9 | await next() 10 | let uploadDir = 'assets/uploads/' 11 | // 配置 12 | let storage = multer.diskStorage({ 13 | // 文件保存路径 14 | destination: (req, file, cb) => { 15 | cb(null, path.resolve(uploadDir)) 16 | }, 17 | // 文件重命名 18 | filename: (req, file, cb) => { 19 | let originalnameArr = file.originalname.split('.') 20 | let postfix = originalnameArr[originalnameArr.length - 1] 21 | console.log('originalnameArr', originalnameArr) 22 | let timeNow = Date.now() 23 | cb(null, timeNow + '.' + postfix) 24 | } 25 | }) 26 | // 上传实例 27 | let upload = multer({ 28 | storage: storage 29 | }) 30 | // 执行单文件上传 31 | let handle = await upload.single('file') 32 | let response = await handle(ctx) 33 | console.log('upload res', response) 34 | let res 35 | if (response) { 36 | res = { 37 | status: 200, 38 | msg: '上传成功!', 39 | data: { 40 | file: response.req.file, 41 | filename: response.req.file.filename, 42 | url: '//' + response.request.header.host + '/' + uploadDir + response.req.file.filename 43 | } 44 | } 45 | } else { 46 | res = { 47 | status: 5000, 48 | msg: '上传失败!', 49 | data: response 50 | } 51 | } 52 | ctx.body = res || {} 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/apps/Files/Model.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by OXOYO on 2017/11/1. 3 | */ 4 | -------------------------------------------------------------------------------- /src/apps/Files/Routers.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by OXOYO on 2017/11/1. 3 | */ 4 | 5 | import Ctrl from './Ctrl' 6 | 7 | const namespace = '/files/' 8 | 9 | export default (router) => { 10 | router 11 | // full path: 12 | // http://localhost:3000/x-restful-api-generator-koa/files/upload 13 | .post(namespace + 'upload', Ctrl.doUpload) 14 | } 15 | -------------------------------------------------------------------------------- /src/apps/Files/upload.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 |