diff --git a/app/app.js b/app/app.js new file mode 100644 index 0000000..3237fcc --- /dev/null +++ b/app/app.js @@ -0,0 +1,18 @@ +const express = require('express'); +const app = express(); +const bodyParser = require('body-parser'); + +app.use(bodyParser.json()); +app.use(bodyParser.urlencoded({ extended: false })); + +const routerV1=require('./router/router.v1.js') +app.use('/api/v1',routerV1) +app.get('/', (req, res) => { + res.json({"message": "Building a RESTful CRUD API with Node.js, Express/Koa and MongoDB."}); +}); + +// app.listen(8000, () => { +// console.log("Server is listening on port 3000"); +// }); + +module.exports=app diff --git a/app/config/default.js b/app/config/default.js new file mode 100644 index 0000000..b0a2d1b --- /dev/null +++ b/app/config/default.js @@ -0,0 +1,37 @@ +const DBURL=`mongodb://localhost:27017/";`; +const DBNAME=`nba`; +const SERVERPORT=8000; +const RESPONSE={ + + INVALIDIDSUPPLIED:{ + code:400, + description:"Invalid ID supplied" + }, + PLAYERNOTFOUND:{ + code:404, + description:"Player not found" + }, + VALIDATIONEXCEPTION:{ + code:405, + description:"Validation exception" + }, + INVALIDINPUT:{ + code:405, + description:"Invalid input" + }, + SUCCESS:{ + code:200, + description:"success" + }, + SUCCESSWITHDATA:{ + code:200, + description:"success", + data:null + } +} +module.exports={ + DBURL, + DBNAME, + RESPONSE, + SERVERPORT +} diff --git a/app/config/dev.js b/app/config/dev.js new file mode 100644 index 0000000..ff7ce18 --- /dev/null +++ b/app/config/dev.js @@ -0,0 +1,6 @@ +const DBURL=`mongodb://localhost:27017/";`; +const DBNAME=`nba`; +module.exports={ + DBURL, + DBNAME +} diff --git a/app/config/product.js b/app/config/product.js new file mode 100644 index 0000000..ff7ce18 --- /dev/null +++ b/app/config/product.js @@ -0,0 +1,6 @@ +const DBURL=`mongodb://localhost:27017/";`; +const DBNAME=`nba`; +module.exports={ + DBURL, + DBNAME +} diff --git a/app/config/test.js b/app/config/test.js new file mode 100644 index 0000000..ff7ce18 --- /dev/null +++ b/app/config/test.js @@ -0,0 +1,6 @@ +const DBURL=`mongodb://localhost:27017/";`; +const DBNAME=`nba`; +module.exports={ + DBURL, + DBNAME +} diff --git a/app/controller/player.controller.js b/app/controller/player.controller.js new file mode 100644 index 0000000..ae74bfa --- /dev/null +++ b/app/controller/player.controller.js @@ -0,0 +1,92 @@ +const db=require('../lib/mongo.lib.js'); +const common=require('../lib/common.js'); +const conllection=`player`; +const {RESPONSE}=require('config-lite')(__dirname); + +/** + * add player + * @param req + * @param res + * @returns {Promise} + */ +let addPlayer=async function(req,res){ + let {name,id,position}=req.body; + if(!name||!position||id*1<0||isNaN(id*1)){ + res.send(RESPONSE.INVALIDINPUT); + } + let result =await db.insertOne(conllection,req.body); + res.send(RESPONSE.SUCCESS); +} + +/** + * get player by id + * @param req + * @param res + * @returns {Promise} + */ +let getPlayer=async function(req,res){ + let {SUCCESS}=RESPONSE; + let {playerid}=req.params; + if(playerid*1<0||isNaN(playerid*1)){ + res.send(RESPONSE.INVALIDIDSUPPLIED); + return; + } + let result =await db.find(conllection,{id:playerid*1}); + if(result.length<=0){ + res.send(RESPONSE.PLAYERNOTFOUND); + return; + } + let success=common.apiSuccess(RESPONSE.SUCCESS,result) + res.send(success); + +} + +/** + * update player by id + * @param req + * @param res + * @returns {Promise} + */ +let updatePlayer=async function(req,res){ + let {name,id,position}=req.body; + if(id*1<0||isNaN(id*1)){ + res.send(RESPONSE.INVALIDIDSUPPLIED); + return; + } + let getUserResult =await db.find(conllection,{id:id*1}); + if(getUserResult.length<=0){ + res.send(RESPONSE.PLAYERNOTFOUND); + return; + } + let result =await db.update(conllection,{id:id},{$set:{name,position}}); + res.send(RESPONSE.SUCCESS); +} + +/** + * delete player by id + * @param req + * @param res + * @returns {Promise} + */ +let deletePlayer=async function(req,res){ + let {SUCCESS}=RESPONSE; + let {playerid}=req.params; + if(playerid*1<0||isNaN(playerid*1)){ + res.send(RESPONSE.INVALIDIDSUPPLIED); + return; + } + let getUserResult =await db.find(conllection,{id:playerid*1}); + if(getUserResult.length<=0){ + res.send(RESPONSE.PLAYERNOTFOUND); + return; + } + let deleteUserResult=await db.deleteOne(conllection,{id:playerid*1}); + res.send(RESPONSE.SUCCESS) +} + +module.exports={ + addPlayer, + getPlayer, + updatePlayer, + deletePlayer +} diff --git a/app/lib/mongo.lib.js b/app/lib/mongo.lib.js new file mode 100644 index 0000000..f45b0bb --- /dev/null +++ b/app/lib/mongo.lib.js @@ -0,0 +1,81 @@ +const MongoClient = require('mongodb').MongoClient; +const {DBURL, DBNAME}=require('config-lite')(__dirname); + + +let insertOne=async function(collection,data){ + return new Promise((resolve,reject)=>{ + MongoClient.connect(DBURL, function(err, db) { + if (err) throw err; + var dbo = db.db(DBNAME); + dbo.collection(collection).insertOne(data, function(err, res) { + if (err){ + throw err; + } else{ + db.close(); + resolve(res) + } + + }); + }); + }); +} + +let find=async function(collection,whereObject={}){ + return new Promise((resolve,reject)=>{ + MongoClient.connect(DBURL, function(err, db) { + if (err) throw err; + var dbo = db.db(DBNAME); + dbo.collection(collection). find(whereObject).toArray(function(err, result) { // 返回集合中所有数据 + if (err){ + throw err; + } else{ + db.close(); + console.log(result) + resolve(result) + } + }); + }); + }); +} + +let update=async function(collection,whereObject={},updateObject){ + return new Promise((resolve,reject)=>{ + MongoClient.connect(DBURL, function(err, db) { + if (err) throw err; + var dbo = db.db(DBNAME); + dbo.collection(collection).update(whereObject, updateObject, function(err, res) { + if (err){ + throw err; + } else{ + db.close(); + console.log(res) + resolve(res) + } + }); + }); + }); +} + +let deleteOne=async function(collection,whereObject={}){ + return new Promise((resolve,reject)=>{ + MongoClient.connect(DBURL, function(err, db) { + if (err) throw err; + var dbo = db.db(DBNAME); + dbo.collection(collection).deleteOne(whereObject, function(err, obj) { + if (err){ + throw err; + } else{ + db.close(); + console.log(obj) + resolve(obj) + } + }); + }); + }); +} +module.exports={ + insertOne, + find, + update, + deleteOne +} diff --git a/app/package.json b/app/package.json index 6b480b3..e5a7f74 100755 --- a/app/package.json +++ b/app/package.json @@ -7,14 +7,18 @@ "scripts": { "start": "NODE_ENV=development node server.js", "start:prod": "NODE_ENV=production node server.js", - "test": "echo \"Error: no test specified\" && exit 1" + "test": "mocha test.js --reporter mocha-junit-reporter --timeout 60000 --exit" }, "dependencies": { + "config-lite": "^3.0.0", "express": "^4.17.1", - "mongoose": "^5.9.2" + "mocha": "^8.3.2", + "mongodb": "^3.6.5", + "mongoose": "^5.9.2", + "supertest": "^6.1.3" }, "devDependencies": { - "chai": "^4.2.0" + "chai": "^4.3.4" }, "engines": { "node": ">=10.15.0" diff --git a/app/router/router.v1.js b/app/router/router.v1.js new file mode 100644 index 0000000..c917781 --- /dev/null +++ b/app/router/router.v1.js @@ -0,0 +1,8 @@ +const express=require('express'); +const router=express.Router(); +const playerRouter=require('./v1/player.router.js'); + +router.use('/player',playerRouter) +module.exports=router; + + diff --git a/app/router/v1/player.router.js b/app/router/v1/player.router.js new file mode 100644 index 0000000..468ce5f --- /dev/null +++ b/app/router/v1/player.router.js @@ -0,0 +1,17 @@ +const express=require('express'); +const playerController=require('../../controller/player.controller.js'); +const router=express.Router(); +router.post('/',(req,res)=>{ + playerController.addPlayer(req,res) +}) +router.get('/:playerid',(req,res)=>{ + playerController.getPlayer(req,res) +}) +router.put('/',(req,res)=>{ + playerController.updatePlayer(req,res) +}) +router.delete('/:playerid',(req,res)=>{ + playerController.deletePlayer(req,res) +}) + +module.exports=router; diff --git a/app/server.js b/app/server.js index 72e5b39..0a04d3b 100755 --- a/app/server.js +++ b/app/server.js @@ -1,11 +1,35 @@ const express = require('express'); - const app = express(); +const bodyParser = require('body-parser'); +const {SERVERPORT}=require('config-lite')(__dirname); + +app.use(bodyParser.json()); +app.use(bodyParser.urlencoded({ extended: false })); +const routerV1=require('./router/router.v1.js') +app.use('/api/v1',routerV1) app.get('/', (req, res) => { res.json({"message": "Building a RESTful CRUD API with Node.js, Express/Koa and MongoDB."}); }); -app.listen(3000, () => { - console.log("Server is listening on port 3000"); -}); \ No newline at end of file + +// catch 404 and forward to error handler +app.use(function(req, res, next) { + next(createError(404)); +}); + +// error handler +app.use(function(err, req, res, next) { + // set locals, only providing error in development + res.locals.message = err.message; + res.locals.error = req.app.get('env') === 'development' ? err : {}; + + // render the error page + res.status(err.status || 500); + res.render('error'); +}); + +app.listen(SERVERPORT, () => { + console.log(`Server is listening on port ${SERVERPORT}`); +}); + diff --git a/app/test/player.test.js b/app/test/player.test.js new file mode 100644 index 0000000..1481ea9 --- /dev/null +++ b/app/test/player.test.js @@ -0,0 +1,55 @@ +const request=require('supertest') +const app=require('../app.js') +const expect = require('chai').expect; +const {SERVERPORT}=require('config-lite')(__dirname); + +describe("#test express app",function(){//http测试 + let server; + before(function() {//执行测试用例前开启服务器 + // runs before all tests in this block + server=app.listen(SERVERPORT); + }); + + after(function() { + // runs after all tests in this block + server.close(); + }); + + describe('#test player api',function(){ + it('delete player ', function (done) { + request(server) + .delete('/api/v1/player/0') + .set('Accept', 'application/json') + .expect('Content-Type', /json/) + .expect(200,function(err,res){ + if(err){ + console.log(err) + done(err) + }else{ + expect(res.body).to.include.keys('code'); + expect(res.body).to.include.keys('description'); + + done() + } + }) + }); + it('#player not foud /',function(done){ + request(server) + .get('/api/v1/player/0') + .set('Accept', 'application/json') + .expect('Content-Type', /json/) + .expect(200,function(err,res){ + if(err){ + console.log(err) + done(err) + }else{ + // console.log(res.body) + expect(res.body).to.include.keys('code'); + expect(res.body).to.include.keys('description'); + expect(res.body.code).to.be.equal(404) + done() + } + }) + }); + }) +})