diff --git a/api/middleware/middleware.js b/api/middleware/middleware.js index 0cceb716a..03e58f1f6 100644 --- a/api/middleware/middleware.js +++ b/api/middleware/middleware.js @@ -1,17 +1,68 @@ +const User = require('../users/users-model') + function logger(req, res, next) { // DO YOUR MAGIC + const timeStamp = new Date().toLocaleString() + const method = req.method + const url = req.originalUrl + // console.log('logger middleware'); + console.log(`[${timeStamp}] ${method} to ${url}`); + next() } -function validateUserId(req, res, next) { +async function validateUserId(req, res, next) { // DO YOUR MAGIC + // console.log('validateUserId middleware'); + try { + const user = await User.getById(req.params.id) + if(!user){ + res.status(404).json({ + message: 'user not found' + }) + }else { + req.user = user + next() + } + } catch (err) { + res.status(500).json({ + message: 'Problem finding user' + }) + } } function validateUser(req, res, next) { // DO YOUR MAGIC + // console.log('validateUser middleware'); + const { name } = req.body + if(!name || !name.trim()) { + res.status(400).json({ + message: 'missing required name field' + }) + }else { + req.name = name.trim() + next() + } + } function validatePost(req, res, next) { // DO YOUR MAGIC + // console.log('validatePosts middleware'); + const { text } = req.body + if(!text || !text.trim()) { + res.status(400).json({ + message: 'missing required text field' + }) + }else { + req.name = text.trim() + next() + } } // 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..9bc6fdbeb 100644 --- a/api/server.js +++ b/api/server.js @@ -1,8 +1,13 @@ const express = require('express'); +const userRouter = require('./users/users-router.js'); +const { logger } = require('./middleware/middleware'); const server = express(); // remember express by default cannot parse JSON in request bodies +server.use(express.json()); +server.use('/api/users', userRouter) +server.use(logger) // global middlewares and the user's router need to be connected here diff --git a/api/users/users-router.js b/api/users/users-router.js index 9d8a0e278..20f075e07 100644 --- a/api/users/users-router.js +++ b/api/users/users-router.js @@ -1,44 +1,108 @@ const express = require('express'); +const User = require('../users/users-model') +const Posts = require('../posts/posts-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 const router = express.Router(); -router.get('/', (req, res) => { +router.get('/', (req, res, next) => { // RETURN AN ARRAY WITH ALL THE USERS + User.get() + .then(users => { + res.json(users) + }) + .catch(next) }); -router.get('/:id', (req, res) => { +router.get('/:id', validateUserId, (req, res) => { // RETURN THE USER OBJECT // this needs a middleware to verify user id + res.json(req.user) + console.log(req.user); }); -router.post('/', (req, res) => { +router.post('/', validateUser, (req, res, next) => { // RETURN THE NEWLY CREATED USER OBJECT // this needs a middleware to check that the request body is valid + User.insert({ name: req.name }) + .then(newUser => { + res.status(201).json(newUser) + }) + .catch(next) + console.log(req.user); + console.log(req.name); }); -router.put('/:id', (req, res) => { +router.put('/:id', validateUserId, validateUser, (req, res, next) => { // 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 + User.update(req.params.id, { name: req.name }) + .then(() => { + return User.getById(req.params.id) + }) + .then(user => { + res.json(user) + }) + .catch(next) + console.log(req.user); + console.log(req.name); }); -router.delete('/:id', (req, res) => { +router.delete('/:id', validateUserId, async (req, res, next) => { // RETURN THE FRESHLY DELETED USER OBJECT // this needs a middleware to verify user id + try{ + await User.remove(req.params.id) + res.json(req.user) + }catch(err) { + next(err) + } + console.log(req.user); }); -router.get('/:id/posts', (req, res) => { +router.get('/:id/posts', validateUserId, async (req, res, next) => { // RETURN THE ARRAY OF USER POSTS // this needs a middleware to verify user id + try{ + const posts = await User.getUserPosts(req.params.id) + res.json(posts) + }catch (err){ + next(err) + } + console.log(req.user); }); -router.post('/:id/posts', (req, res) => { +router.post('/:id/posts', + validateUserId, + validatePost, + async (req, res, next) => { // 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 + try{ + const newPost = await Post.insert({ + user_id: req.params.id, + text: req.text, + }) + res.status(201).json(newPost) + }catch (err){ + next(err) + } + console.log(req.user); + console.log(req.text); }); +router.use((err, req, res, next) => { + res.status(err.status || 500).json({ + customMessage: 'Error inside posts router', + message: err.message, + stack: err.stack + }) +}) + // 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..676efe399 100644 --- a/index.js +++ b/index.js @@ -1 +1,9 @@ // require your server and launch it +const server = require('./api/server') +require('colors') + +const port = 8000 + +server.listen(port, () => { + console.log(`Server running on http://localhost:${port}`.cyan); +}) \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 88b87652e..5ede9277f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,11 +5,13 @@ "requires": true, "packages": { "": { - "name": "node-api3-project", "version": "1.0.0", "dependencies": { + "colors": "^1.4.0", "express": "^4.17.1", + "helmet": "^4.6.0", "knex": "^0.95.11", + "morgan": "^1.10.0", "sqlite3": "^5.0.2" }, "devDependencies": { @@ -1552,6 +1554,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", @@ -2000,6 +2013,14 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "engines": { + "node": ">=0.1.90" + } + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -3389,6 +3410,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 +4977,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 +5429,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", @@ -8453,6 +8526,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", @@ -8805,6 +8886,11 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==" + }, "combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -9883,6 +9969,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", @@ -11085,6 +11176,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", @@ -11405,6 +11528,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 19860c4af..2b3608481 100644 --- a/package.json +++ b/package.json @@ -13,8 +13,11 @@ "url": "git+https://github.com/LambdaSchool/node-api3-project.git" }, "dependencies": { + "colors": "^1.4.0", "express": "^4.17.1", + "helmet": "^4.6.0", "knex": "^0.95.11", + "morgan": "^1.10.0", "sqlite3": "^5.0.2" }, "devDependencies": {