Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,6 @@ bin/Release
.idea

# Mac files
.DS_Store
.DS_Store

.env
1 change: 1 addition & 0 deletions app/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
MONGODB_URL=mongodb://127.0.0.1/test
54 changes: 54 additions & 0 deletions app/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
const express = require('express');
const path = require('path');
const debug = require('debug')('app:server');
const mongoose = require('mongoose');
require('dotenv').config();

const indexRouter = require('./routes/index');

const app = express();

app.use(express.json());

// connect MongoDB
const url = process.env.MONGODB_URL || 'mongodb://127.0.0.1/test';

mongoose.connect(url, {
useNewUrlParser: true,
useUnifiedTopology: true
}).catch(console.error.bind(console, 'connection error:'));

mongoose.connection.once('open', () => {
debug("MongoDB connected!");
});

app.use('/', indexRouter);

// catch mongoose ValidationError
app.use(function(err, req, res, next) {
if (err instanceof mongoose.Error.ValidationError) {
let errors = [];

createError(err.errors['name']);
createError(err.errors['position']);
createError(err.errors['id']);

res.status(400).json({ errors });

// create error
function createError(err) {
if (err) {
errors.push({
kind: err.kind,
message: err.message,
path: err.path
});
}
}

} else {
next(err);
}
});

module.exports = app;
90 changes: 90 additions & 0 deletions app/bin/www
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
#!/usr/bin/env node

/**
* Module dependencies.
*/

var app = require('../app');
var debug = require('debug')('app:server');
var http = require('http');

/**
* Get port from environment and store in Express.
*/

var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);

/**
* Create HTTP server.
*/

var server = http.createServer(app);

/**
* Listen on provided port, on all network interfaces.
*/

server.listen(port);
server.on('error', onError);
server.on('listening', onListening);

/**
* Normalize a port into a number, string, or false.
*/

function normalizePort(val) {
var port = parseInt(val, 10);

if (isNaN(port)) {
// named pipe
return val;
}

if (port >= 0) {
// port number
return port;
}

return false;
}

/**
* Event listener for HTTP server "error" event.
*/

function onError(error) {
if (error.syscall !== 'listen') {
throw error;
}

var bind = typeof port === 'string'
? 'Pipe ' + port
: 'Port ' + port;

// handle specific listen errors with friendly messages
switch (error.code) {
case 'EACCES':
console.error(bind + ' requires elevated privileges');
process.exit(1);
break;
case 'EADDRINUSE':
console.error(bind + ' is already in use');
process.exit(1);
break;
default:
throw error;
}
}

/**
* Event listener for HTTP server "listening" event.
*/

function onListening() {
var addr = server.address();
var bind = typeof addr === 'string'
? 'pipe ' + addr
: 'port ' + addr.port;
debug('Listening on ' + bind);
}
83 changes: 83 additions & 0 deletions app/controllers/playerController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
const Player = require('../models/playerModel');

// show a player
exports.show = async function(req, res, next) {
let { id } = req.params;

const player = await Player.findOne({ _id: id, deletedAt: undefined });

if (!player) {
return res.status(404).end('player not found');
}

res.json({
id: player.id,
name: player.name,
position: player.position
});
};

// create a player
exports.create = function(req, res, next) {
const { name, position } = req.body;

const player = new Player({ name, position });

player.save((err, player) => {
if (err) return next(err);

res.json({
id: player.id,
name: player.name,
position: player.position
});
});
};

// update a player
exports.update = async function(req, res, next) {
let { id } = req.params;
let { name, position } = req.body;

const player = await Player.findOne({ _id: id, deletedAt: undefined });

if (!player) {
return res.status(404).end('player not found');
}

player.name = name;
player.position = position;

player.save((err, player) => {
if (err) return next(err);

res.json({
id: player.id,
name: player.name,
position: player.position
});
});
};

// soft delete a player
exports.delete = async function(req, res, next) {
let { id } = req.params;

const player = await Player.findOne({ _id: id, deletedAt: undefined });

if (!player) {
return res.status(404).end('player not found');
}

player.deletedAt = new Date();

player.save((err, player) => {
if (err) return next(err);

res.json({
id: player.id,
name: player.name,
position: player.position
});
});
};
9 changes: 9 additions & 0 deletions app/models/playerModel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const mongoose = require('mongoose');

const schema = new mongoose.Schema({
name: { type: String, required: true },
position: { type: String, enum: ['C', 'PF', 'SF', 'PG', 'SG'] },
deletedAt: Date
}, { timestamps: true });

module.exports = mongoose.model('Player', schema);
25 changes: 15 additions & 10 deletions app/package.json
100755 → 100644
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
{
"private": true,
"name": "node-examination",
"version": "0.0.1",
"description": "Building a RESTful CRUD API with Node.js, Express/Koa and MongoDB.",
"private": true,
"main": "server.js",
"scripts": {
"start": "NODE_ENV=development node server.js",
"start:prod": "NODE_ENV=production node server.js",
"test": "echo \"Error: no test specified\" && exit 1"
"start": "nodemon ./bin/www",
"start:prod": "NODE_ENV=production node ./bin/www",
"test": "mocha --exit"
},
"dependencies": {
"express": "^4.17.1",
"mongoose": "^5.9.2"
},
"devDependencies": {
"chai": "^4.2.0"
"debug": "~2.6.9",
"dotenv": "^8.2.0",
"express": "~4.16.1",
"mongoose": "^5.9.5",
"morgan": "~1.9.1"
},
"engines": {
"node": ">=10.15.0"
Expand All @@ -24,5 +24,10 @@
"not dead",
"not ie <= 11",
"not op_mini all"
]
],
"devDependencies": {
"mocha": "^7.1.1",
"nodemon": "^2.0.2",
"supertest": "^4.0.2"
}
}
18 changes: 18 additions & 0 deletions app/routes/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
const express = require('express');
const playerController = require('../controllers/playerController');

const router = express.Router();

/* GET home page. */
router.get('/', function(req, res, next) {
res.json({
message: 'Building a RESTful CRUD API with Node.js, Express and MongoDB.'
});
});

router.get('/player/:id([0-9a-f]{24})', playerController.show);
router.post('/player', playerController.create);
router.put('/player/:id([0-9a-f]{24})', playerController.update);
router.delete('/player/:id([0-9a-f]{24})', playerController.delete);

module.exports = router;
11 changes: 0 additions & 11 deletions app/server.js

This file was deleted.

Loading