From 69f665eb489e0440e17cddbdc739a94f964220cf Mon Sep 17 00:00:00 2001 From: ozbk Date: Sat, 29 Feb 2020 22:05:46 +0800 Subject: [PATCH] finish --- app/config/index.js | 9 ++ app/constant/error-code.js | 3 + app/constant/status-code.js | 5 ++ app/lib/database.js | 27 ++++++ app/routes/index.js | 5 ++ app/routes/player.js | 136 ++++++++++++++++++++++++++++++ app/schema/index.js | 5 ++ app/schema/player.schema.js | 9 ++ app/server.js | 22 ++++- app/utils/index.js | 7 ++ package.json | 32 +++++++ test/player.test.js | 162 ++++++++++++++++++++++++++++++++++++ 12 files changed, 419 insertions(+), 3 deletions(-) create mode 100644 app/config/index.js create mode 100644 app/constant/error-code.js create mode 100644 app/constant/status-code.js create mode 100644 app/lib/database.js create mode 100644 app/routes/index.js create mode 100644 app/routes/player.js create mode 100644 app/schema/index.js create mode 100644 app/schema/player.schema.js create mode 100644 app/utils/index.js create mode 100644 package.json create mode 100644 test/player.test.js diff --git a/app/config/index.js b/app/config/index.js new file mode 100644 index 0000000..5b7f54c --- /dev/null +++ b/app/config/index.js @@ -0,0 +1,9 @@ +module.exports = { + db: { + user: 'admin', + password: '123456', + host: 'localhost', + port: 27017, + name: 'nba' + } +} \ No newline at end of file diff --git a/app/constant/error-code.js b/app/constant/error-code.js new file mode 100644 index 0000000..7ddfc4c --- /dev/null +++ b/app/constant/error-code.js @@ -0,0 +1,3 @@ +module.exports = { + 'ParameterError': -2001 +} \ No newline at end of file diff --git a/app/constant/status-code.js b/app/constant/status-code.js new file mode 100644 index 0000000..81c8a83 --- /dev/null +++ b/app/constant/status-code.js @@ -0,0 +1,5 @@ +module.exports = { + Ok: 200, + BadRequest: 400, + NotFound: 404 +} \ No newline at end of file diff --git a/app/lib/database.js b/app/lib/database.js new file mode 100644 index 0000000..0e6563e --- /dev/null +++ b/app/lib/database.js @@ -0,0 +1,27 @@ +const mongoose = require('mongoose'); +const config = require('../config'); +const util = require('../utils'); +const schema = require('../schema'); + +const log = util.log; + +const connectionString = `mongodb://${config.db.host}:${config.db.port}/${config.db.name}`; + +const db = module.exports = {}; + +db.Table = {}; + +db.Table.Player = mongoose.model('Player', schema.PlayerSchema); + +db.connect = function() { + return new Promise(resolve => { + mongoose.connect(connectionString, { useNewUrlParser: true, useUnifiedTopology: true, useFindAndModify: false }, err => { + if(err) { + log('Mongodb occured error when it was connecting.') + throw err; + } + log('Mongodb has been connected.'); + resolve(); + }); + }); +} diff --git a/app/routes/index.js b/app/routes/index.js new file mode 100644 index 0000000..c5919cc --- /dev/null +++ b/app/routes/index.js @@ -0,0 +1,5 @@ +const PlayerRouter = require('./player'); + +module.exports = { + PlayerRouter +} \ No newline at end of file diff --git a/app/routes/player.js b/app/routes/player.js new file mode 100644 index 0000000..353cf75 --- /dev/null +++ b/app/routes/player.js @@ -0,0 +1,136 @@ +const express = require('express'); +const db = require('../lib/database'); +const util = require('../utils'); + +const log = util.log; + +const router = express.Router(); + +function checkParameter(data) { + if(data.hasOwnProperty('id') && data.hasOwnProperty('name') && data.hasOwnProperty('position')) { + return true; + } + return false; +} + +router.post('/', async (req, res) => { + let payload = {}; + + if(req.headers['content-type'] === 'application/xml') { + if(!checkParameter(req.body.Player)) { + res.status(405).send(); + return; + } else { + payload.id = req.body.Player['id'][0]; + payload.name = req.body.Player['name'][0]; + payload.position = req.body.Player['position'][0]; + } + } else { + if(!checkParameter(req.body)) { + res.status(405).send(); + return; + } else { + payload.id = req.body.id + payload.name = req.body.name; + payload.position = req.body.position; + } + } + + await db.Table.Player.create([ + { + id: payload.id, + name: payload.name, + position: payload.position + } + ], (err, ret) => { + if(err) { + log(`Add player failed. [${err}]`); + res.status(405).send(); + return; + } + res.status(200).send(); + }); +}); + +router.put('/', async (req, res) => { + let payload = {}; + + if(req.headers['content-type'] === 'application/xml') { + if(!checkParameter(req.body.Player)) { + res.status(405).send(); + return; + } else { + payload.id = req.body.Player['id'][0]; + payload.name = req.body.Player['name'][0]; + payload.position = req.body.Player['position'][0]; + } + } else { + if(!checkParameter(req.body)) { + res.status(405).send(); + return; + } else { + payload.id = req.body.id + payload.name = req.body.name; + payload.position = req.body.position; + } + } + + await db.Table.Player.findOneAndUpdate({id: payload.id}, payload, (err, ret) => { + if(err) { + log(`Update player failed. [${err}]`); + res.status(405).send(); + return; + } + if(ret === null) { + res.status(404).send(); + return; + } + res.status(200).send(); + }); +}); + +router.get('/:id', async (req, res) => { + if(!req.params.hasOwnProperty('id')) { + res.status(400).send(); + return; + } + + await db.Table.Player.findOne({ id: req.params.id }, (err, ret) => { + if(err) { + log(`Get player failed. [${err}]`); + res.status(400).send(); + return; + } + if(ret == null) { + res.status(404).send(); + return; + } + res.send({ + id: ret.id, + name: ret.name, + position: ret.position + }); + }); +}); + +router.delete('/:id', async (req, res) => { + if(!req.params.hasOwnProperty('id')) { + res.status(400).send(); + return; + } + + await db.Table.Player.deleteOne({ id: req.params.id }, (err, ret) => { + if(err) { + log(`Delete player failed. [${err}]`); + res.status(400).send(); + return; + } + if(ret.deletedCount === 0) { + res.status(404).send(); + return; + } + res.sendStatus(200); + }); +}); + +module.exports = router; \ No newline at end of file diff --git a/app/schema/index.js b/app/schema/index.js new file mode 100644 index 0000000..c6d94ea --- /dev/null +++ b/app/schema/index.js @@ -0,0 +1,5 @@ +const PlayerSchema = require('./player.schema'); + +module.exports = { + PlayerSchema +} \ No newline at end of file diff --git a/app/schema/player.schema.js b/app/schema/player.schema.js new file mode 100644 index 0000000..2e8bf79 --- /dev/null +++ b/app/schema/player.schema.js @@ -0,0 +1,9 @@ +const { Schema } = require('mongoose'); + +let PlayerSchema = new Schema({ + id: { type: Number }, + name: { type: String }, + position: { type: String, enum: ['C', 'PF', 'SF', 'PG', 'SG'] } +}); + +module.exports = PlayerSchema; \ No newline at end of file diff --git a/app/server.js b/app/server.js index 72e5b39..f7f4aca 100755 --- a/app/server.js +++ b/app/server.js @@ -1,11 +1,27 @@ const express = require('express'); +const bodyParser = require('body-parser'); +const xmlBodyParser = require('body-parser-xml')(bodyParser); +const db = require('./lib/database'); +const router = require('./routes'); +const util = require('./utils'); const app = express(); +app.use(bodyParser.urlencoded({ extended: false, limit: '20mb' })); +app.use(bodyParser.json({ limit: '20mb' })); +app.use(bodyParser.xml()); + 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 +app.use('/player', router.PlayerRouter); + +const appStart = async () => { + await db.connect(); + app.listen(3000, () => { + util.log("RESTful Server is listening on port 3000"); + }); +} + +appStart(); \ No newline at end of file diff --git a/app/utils/index.js b/app/utils/index.js new file mode 100644 index 0000000..248a827 --- /dev/null +++ b/app/utils/index.js @@ -0,0 +1,7 @@ +const log = function(msg) { + console.log(`[${new Date()}] ${msg}`); +} + +module.exports = { + log +} \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..dee8594 --- /dev/null +++ b/package.json @@ -0,0 +1,32 @@ +{ + "name": "node-examination", + "version": "1.0.0", + "description": "Building a RESTful CRUD API with Node.js(>=v10.15.0), Express/Koa and MongoDB/MySQL.", + "main": "index.js", + "scripts": { + "start": "node app/server.js", + "test": "mocha" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/bridge5/node-examination.git" + }, + "keywords": [], + "author": "", + "license": "ISC", + "bugs": { + "url": "https://github.com/bridge5/node-examination/issues" + }, + "homepage": "https://github.com/bridge5/node-examination#readme", + "dependencies": { + "body-parser": "^1.19.0", + "body-parser-xml": "^1.1.0", + "express": "^4.17.1", + "express-xml-bodyparser": "^0.3.0", + "mongoose": "^5.9.2" + }, + "devDependencies": { + "mocha": "^7.1.0", + "supertest": "^4.0.2" + } +} diff --git a/test/player.test.js b/test/player.test.js new file mode 100644 index 0000000..9773338 --- /dev/null +++ b/test/player.test.js @@ -0,0 +1,162 @@ +const request = require('supertest'); +const app = require('../app/server'); + +describe('Player', () => { + it('add player 200', done => { + request('http://localhost:3000') + .post('/player') + .send({ + id: 9, + name: 'test', + position: 'PF' + }) + .expect(200, (err, res) => { + if(err) { + console.log(err); + done(err); + } else { + done(); + } + }) + }); + + it('add player 405 A', done => { + request('http://localhost:3000') + .post('/player') + .send({ + id: 1, + name: 'test', + position: 'PFF' + }) + .expect(405, (err, res) => { + if(err) { + console.log(err); + done(err); + } else { + done(); + } + }); + }); + + it('add player 405 B', done => { + request('http://localhost:3000') + .post('/player') + .send({ + name: 'test', + position: 'PF' + }) + .expect(405, (err, res) => { + if(err) { + console.log(err); + done(err); + } else { + done(); + } + }); + }); + + it('update player 200', done => { + request('http://localhost:3000') + .put('/player') + .send({ + id: 9, + name: 'test01', + position: 'PF' + }) + .expect(200, (err, res) => { + if(err) { + console.log(err); + done(err); + } else { + done(); + } + }); + }); + + it('update player 404', done => { + request('http://localhost:3000') + .put('/player') + .send({ + id: 9988, + name: 'test01', + position: 'PF' + }) + .expect(404, (err, res) => { + if(err) { + console.log(err); + done(err); + } else { + done(); + } + }); + }); + + it('update player 405', done => { + request('http://localhost:3000') + .put('/player') + .send({ + id: 1, + name: 'test01' + }) + .expect(405, (err, res) => { + if(err) { + console.log(err); + done(err); + } else { + done(); + } + }); + }); + + it('get player 200', done => { + request('http://localhost:3000') + .get('/player/9') + .expect(200, (err, res) => { + if(err) { + console.log(err); + done(err); + } else { + done(); + } + }); + }); + + it('get player 404', done => { + request('http://localhost:3000') + .get('/player/6789') + .expect(404, (err, res) => { + if(err) { + console.log(err); + done(err); + } else { + done(); + } + }); + }); + + it('delete player 200', done => { + request('http://localhost:3000') + .delete('/player/9') + .expect(200, (err, res) => { + if(err) { + console.log(err); + done(err); + } else { + done(); + } + }); + }); + + it('delete player 404', done => { + request('http://localhost:3000') + .delete('/player/9') + .expect(404, (err, res) => { + if(err) { + console.log(err); + done(err); + } else { + done(); + } + }); + }); +}); \ No newline at end of file