diff --git a/api/middleware/middleware.js b/api/middleware/middleware.js index 0cceb716a..dab3970b9 100644 --- a/api/middleware/middleware.js +++ b/api/middleware/middleware.js @@ -1,17 +1,60 @@ +const Users = require('../users/users-model'); + function logger(req, res, next) { // DO YOUR MAGIC + console.log(req.url, req.method) + next() } -function validateUserId(req, res, next) { // DO YOUR MAGIC + const validateUserId = async (req, res, next) => { + try{ + const {id} = req.params + const user = await Users.getById(id) + if(!user){ + res.status(404).json({message: 'User not found'}) + }else{ + req.user = user + next() + } + }catch(err){ + res.status(500).json({message: err}) + } } function validateUser(req, res, next) { // DO YOUR MAGIC + try{ + const user = req.body + if(!user.name){ + res.status(400).json({message: 'Missing required name field'}) + }else{ + next() + } + }catch(err){ + console.log(err) + res.status(500).json({message: err}) + } } function validatePost(req, res, next) { // DO YOUR MAGIC + try{ + const {text} = req.body + if(!text){ + res.status(400).json({message: 'Missing required text field'}) + }else{ + next() + } + }catch(err){ + res.status(500).json({message: err.message}) + } } // do not forget to expose these functions to other modules +module.exports = { + logger, + validateUserId, + validateUser, + validatePost +} \ No newline at end of file diff --git a/api/server.js b/api/server.js index badc3026a..089897f29 100644 --- a/api/server.js +++ b/api/server.js @@ -1,10 +1,18 @@ const express = require('express'); - const server = express(); - +const morgan = require("morgan"); +const helmet = require("helmet"); +const {logger} = require('./middleware/middleware'); +const userRouter = require('./users/users-router') // remember express by default cannot parse JSON in request bodies - +server.use(express.json()); // global middlewares and the user's router need to be connected here +server.use(morgan('dev')); +server.use(express.json()); +server.use(helmet()); +server.use(logger) +server.use('/api/users', logger, userRouter) + server.get('/', (req, res) => { res.send(`

Let's write some middleware!

`); diff --git a/api/users/users-router.js b/api/users/users-router.js index 9d8a0e278..2d6307ae7 100644 --- a/api/users/users-router.js +++ b/api/users/users-router.js @@ -1,5 +1,9 @@ const express = require('express'); - +const Users = require('./users-model'); +const { + validateUserId, + validateUser, + validatePost} = require('../middleware/middleware'); // You will need `users-model.js` and `posts-model.js` both // The middleware functions also need to be required @@ -7,38 +11,72 @@ const router = express.Router(); router.get('/', (req, res) => { // RETURN AN ARRAY WITH ALL THE USERS + Users.get() + .then(user => { + res.status(200).json(user) + }) + .catch(err => { + res.status(500).json({message: err.message}) + }) }); -router.get('/:id', (req, res) => { +router.get('/:id', validateUserId, (req, res) => { // RETURN THE USER OBJECT // this needs a middleware to verify user id + res.status(200).json(req.user) }); -router.post('/', (req, res) => { +router.post('/', validateUser, async (req, res) => { // RETURN THE NEWLY CREATED USER OBJECT // this needs a middleware to check that the request body is valid + try{ + const newUser = await Users.insert(req.body) + res.status(201).json(newUser) + }catch (err){ + res.status(500).json({message: 'Something went wrong'}) + } }); -router.put('/:id', (req, res) => { +router.put('/:id', validateUser, validateUserId, async (req, res) => { // RETURN THE FRESHLY UPDATED USER OBJECT // this needs a middleware to verify user id // and another middleware to check that the request body is valid + const changes = req.body + const {id} = req.params + const updatedUser = await Users.update(id, changes) + res.status(201).json(updatedUser) }); -router.delete('/:id', (req, res) => { +router.delete('/:id', validateUserId, async (req, res) => { // RETURN THE FRESHLY DELETED USER OBJECT // this needs a middleware to verify user id + try{ + const user = await Users.getById(req.params.id) + res.status(200).json(user) + }catch(err){ + res.status(500).json({message: 'something went wrong'}) + } }); -router.get('/:id/posts', (req, res) => { +router.get('/:id/posts', validateUserId, (req, res) => { // RETURN THE ARRAY OF USER POSTS // this needs a middleware to verify user id + const {id} = req.params + Users.getUserPosts(id) + .then(messages => { + res.status(200).json(messages) + }) + .catch(err => { + console.log(err) + res.status(500).json({message: 'Error getting the posts for the user'}) + }) }); -router.post('/:id/posts', (req, res) => { +router.post('/:id/posts', validateUserId, (req, res) => { // RETURN THE NEWLY CREATED USER POST // this needs a middleware to verify user id // and another middleware to check that the request body is valid }); // do not forget to export the router +module.exports = router; \ No newline at end of file diff --git a/index.js b/index.js index 602039f1b..ddcc758db 100644 --- a/index.js +++ b/index.js @@ -1 +1,6 @@ // require your server and launch it +const server = require('./api/server') + +server.listen(9000, () => { + console.log('*** Server listening on port 9000 ***') +}) \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index a073034f1..6eb20a8d4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,11 +5,12 @@ "requires": true, "packages": { "": { - "name": "node-api3-project", "version": "1.0.0", "dependencies": { "express": "^4.17.1", + "helmet": "^4.6.0", "knex": "^0.95.14", + "morgan": "^1.10.0", "sqlite3": "^5.0.2" }, "devDependencies": { @@ -1530,6 +1531,17 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "node_modules/basic-auth": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "dependencies": { + "safe-buffer": "5.1.2" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/bcrypt-pbkdf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", @@ -3374,6 +3386,14 @@ "node": ">=8" } }, + "node_modules/helmet": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/helmet/-/helmet-4.6.0.tgz", + "integrity": "sha512-HVqALKZlR95ROkrnesdhbbZJFi/rIVSoNq6f3jA/9u6MIbTsPh3xZwihjeI5+DO/2sOV6HMHooXcEOuwskHpTg==", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/html-encoding-sniffer": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", @@ -4948,6 +4968,42 @@ "mkdirp": "bin/cmd.js" } }, + "node_modules/morgan": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", + "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", + "dependencies": { + "basic-auth": "~2.0.1", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-finished": "~2.3.0", + "on-headers": "~1.0.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/morgan/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/morgan/node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/morgan/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -5364,6 +5420,14 @@ "node": ">= 0.8" } }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -8414,6 +8478,14 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "basic-auth": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "requires": { + "safe-buffer": "5.1.2" + } + }, "bcrypt-pbkdf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", @@ -9850,6 +9922,11 @@ "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", "dev": true }, + "helmet": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/helmet/-/helmet-4.6.0.tgz", + "integrity": "sha512-HVqALKZlR95ROkrnesdhbbZJFi/rIVSoNq6f3jA/9u6MIbTsPh3xZwihjeI5+DO/2sOV6HMHooXcEOuwskHpTg==" + }, "html-encoding-sniffer": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", @@ -11056,6 +11133,38 @@ "minimist": "^1.2.5" } }, + "morgan": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", + "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", + "requires": { + "basic-auth": "~2.0.1", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-finished": "~2.3.0", + "on-headers": "~1.0.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -11376,6 +11485,11 @@ "ee-first": "1.1.1" } }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", diff --git a/package.json b/package.json index 8f31b3fe7..c2a7209a7 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,9 @@ }, "dependencies": { "express": "^4.17.1", + "helmet": "^4.6.0", "knex": "^0.95.14", + "morgan": "^1.10.0", "sqlite3": "^5.0.2" }, "devDependencies": {