+2347067162698
tclassified.com@gmail.com

Nodejs Stack up

Educational Technology and ICT

Created with Sketch.

Nodejs Stack up

Node is a javascript runtime for building backends in javascript

create folder dev-prj
……………………………………………………..
npm install -g @angular/cli
git clone https://github.com/OpenClassrooms-Student-Center/5614116-front-end-app.git frontend
cd frontend
npm install
ng serve
………………………………………..
create a backend folder inside your root directory
……………………………………………………….
From within your backend directory, run the terminal command npm init to initialize your project. You can use the default options, or change them as you wish — however, your entry point should be server.js , which you will create shortly.

You can also initialize a Git repo at this point by running git init from within your backend folder. Don’t forget to create a .gitignore file containing the line node_modules so as not to push this large folder to your remote repo.

Create a server.js file inside your backend folder — this will contain your first Node server.
……………………………………………………………
server.js
………
const http = require(‘http’);

const server = http.createServer((req, res) => {
res.end(‘This is my server response!’);
});

server.listen(process.env.PORT || 3000);
………………………………………………………

instal nodemone to watch and refresh your server

npm install -g nodemon
…………………………..
then run the server with either
node server
or
nodemon server
……………………………………….
Create an Express app
Install Express
To add Express to your project, run the following from within your backend folder:

npm install –save express
Create a new app.js file which will contain your Express app:

const express = require(‘express’);

const app = express();

module.exports = app;
………………………………………………..
Run the Express app on the Node server
Go back to your server.js file, and modify it as follows:

const http = require(‘http’);
const app = require(‘./app’);

app.set(‘port’, process.env.PORT || 3000);
const server = http.createServer(app);

server.listen(process.env.PORT || 3000);

…………………………………….
Making a request to this server will throw an Express-generated 404 error, as our Express app has no way of responding yet. Let’s set up a simple response just to make sure everything is working properly by making an addition to our app.js file:

const express = require(‘express’);

const app = express();

app.use((req, res) => {
res.json({ message: ‘Your request was successful!’ });
});

module.exports = app;
……………………………………………………….

Add some middleware with the next method
app.js

const express = require(‘express’);

const app = express();

app.use((req, res, next) => {
console.log(‘Request received!’);
next();
});

app.use((req, res, next) => {
res.status(201);
next();
});

app.use((req, res, next) => {
res.json({ message: ‘Your request was successful!’ });
next();
});

app.use((req, res, next) => {
console.log(‘Response sent successfully!’);
});

module.exports = app;
……………………………………………….
improve server.js t make it suitable for deployment
server.js

const http = require(‘http’);
const app = require(‘./app’);

const normalizePort = val => {
const port = parseInt(val, 10);

if (isNaN(port)) {
return val;
}
if (port >= 0) {
return port;
}
return false;
};
const port = normalizePort(process.env.PORT || ‘3000’);
app.set(‘port’, port);

const errorHandler = error => {
if (error.syscall !== ‘listen’) {
throw error;
}
const address = server.address();
const bind = typeof address === ‘string’ ? ‘pipe ‘ + address : ‘port: ‘ + port;
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;
}
};

const server = http.createServer(app);

server.on(‘error’, errorHandler);
server.on(‘listening’, () => {
const address = server.address();
const bind = typeof address === ‘string’ ? ‘pipe ‘ + address : ‘port ‘ + port;
console.log(‘Listening on ‘ + bind);
});

server.listen(port);
………………………………………………………………

part three
create a get route

You should have your front-end app running in a browser (run ng serve from the frontend directory and navigate your browser to http://localhost:4200) and head into “Parts 1 + 2.”

……………………………………………….
In your app.js file, replace all the middleware with the following middleware:
………………………………………………………………
app.use(‘/api/stuff’, (req, res, next) => {
const stuff = [
{
_id: ‘oeihfzeoi’,
title: ‘My first thing’,
description: ‘All of the info about my first thing’,
imageUrl: ”,
price: 4900,
userId: ‘qsomihvqios’,
},
{
_id: ‘oeihfzeomoihi’,
title: ‘My second thing’,
description: ‘All of the info about my second thing’,
imageUrl: ”,
price: 2900,
userId: ‘qsomihvqios’,
},
];
res.status(200).json(stuff);
});

……………………………………………………………………..
Back in the app.js file, add the following middleware before your API route: for cors error cross origin resource sharing
……………………………………………………………………
app.use((req, res, next) => {
res.setHeader(‘Access-Control-Allow-Origin’, ‘*’);
res.setHeader(‘Access-Control-Allow-Headers’, ‘Origin, X-Requested-With, Content, Accept, Content-Type, Authorization’);
res.setHeader(‘Access-Control-Allow-Methods’, ‘GET, POST, PUT, DELETE, PATCH, OPTIONS’);
next();
});
……………………………………………………………………..
put this later after verification or any image address link ‘https://upload.wikimedia.org/wikipedia/commons/e/e3/Canon_EOS_640_01.jpg’,

Create a POST route
Receive stuff from the front-end app
……………………………………….
npm install –save body-parser

Import it in your app.js file:
const bodyParser = require(‘body-parser’);

set json function as global middleware for the app
app.use(bodyPaser.json());

Now that body-parser has parsed the request body, we can write the following POST middleware:

app.post(‘/api/stuff’, (req, res, next) => {
console.log(req.body);
res.status(201).json({
message: ‘Thing created successfully!’
});
});

…………………………….
Setting up the database
……………………………..
go to mongodb.com
get started free
get started free again
set up an account
build a new cluster
aws
freetier closer to you
create cluster

while wait for cluster to create
go to security tab
add a new user
put user name and click on generate secure password
copy the password and paste somewhere for use in the db connection
read and write privilages
add user
go to ip whitelist
click on get beside delete
click on allow access from anywhere
click comfirm
go to overview tab
notice the cluster has finshed creating

……………………………………..
connecting your api to your mongodb cluster
…………………………………….
from the mongodb atlas, click connect button
select driver 3.6 or later
copy the srv addres generated

back to your project backend directory
npm install –save mongoose

just beneath app constant declaration

const mongoose = require(‘mongoose’);

then put the code below, makiing sure it has the password and srv connection string you copied

mongoose.connect(‘mongodb+srv://will:@cluster0-pme76.mongodb.net/test?retryWrites=true’)
.then(() => {
console.log(‘Successfully connected to MongoDB Atlas!’);
})
.catch((error) => {
console.log(‘Unable to connect to MongoDB Atlas!’);
console.error(error);
});

WWl5q48pU2j7zCzW
austine
mongodb+srv://austine:@cluster0-glfs3.mongodb.net/test?retryWrites=true&w=majority
……………………………..
Create a data schema
Inside your backend folder, create a new folder called models , and within that new folder, a file called thing.js

const mongoose = require(‘mongoose’);

const thingSchema = mongoose.Schema({
title: { type: String, required: true },
description: { type: String, required: true },
imageUrl: { type: String, required: true },
userId: { type: String, required: true },
price: { type: Number, required: true },
});

module.exports = mongoose.model(‘Thing’, thingSchema);
…………………………………………………………
Save and retrieve data

const Thing = require(‘./models/thing’);

app.post(‘/api/stuff’, (req, res, next) => {
const thing = new Thing({
title: req.body.title,
description: req.body.description,
imageUrl: req.body.imageUrl,
price: req.body.price,
userId: req.body.userId
});
thing.save().then(
() => {
res.status(201).json({
message: ‘Post saved successfully!’
});
}
).catch(
(error) => {
res.status(400).json({
error: error
});
}
);
});

Now we can implement our GET route to return all of the Things in the database:

Retrieving the list of Things for sale

app.use(‘/api/stuff’, (req, res, next) => {
Thing.find().then(
(things) => {
res.status(200).json(things);
}
).catch(
(error) => {
res.status(400).json({
error: error
});
}
);
});

Retrieving a specific Thing
app.get(‘/api/stuff/:id’, (req, res, next) => {
Thing.findOne({
_id: req.params.id
}).then(
(thing) => {
res.status(200).json(thing);
}
).catch(
(error) => {
res.status(404).json({
error: error
});
}
);
});
…………………………………………
Complete the CRUD with update and delete
Update an existing Thing

app.put(‘/api/stuff/:id’, (req, res, next) => {
const thing = new Thing({
_id: req.params.id,
title: req.body.title,
description: req.body.description,
imageUrl: req.body.imageUrl,
price: req.body.price,
userId: req.body.userId
});
Thing.updateOne({_id: req.params.id}, thing).then(
() => {
res.status(201).json({
message: ‘Thing updated successfully!’
});
}
).catch(
(error) => {
res.status(400).json({
error: error
});
}
);
});

Delete a thing

app.delete(‘/api/stuff/:id’, (req, res, next) => {
Thing.deleteOne({_id: req.params.id}).then(
() => {
res.status(200).json({
message: ‘Deleted!’
});
}
).catch(
(error) => {
res.status(400).json({
error: error
});
}
);
});

………………………………………………………………..
optimizing our backend for authentication
………………………………………………………………..
Create a new folder inside your backend folder called routes , and create a file inside it called stuff.js , which will contain the logic for our stuff routes:
…………………………………………………….
backend/routes/stuff.js
…………………………….
const express = require(‘express’);
const router = express.Router();

const Thing = require(‘../models/thing’);

router.post(‘/’, (req, res, next) => {
const thing = new Thing({
title: req.body.title,
description: req.body.description,
imageUrl: req.body.imageUrl,
price: req.body.price,
userId: req.body.userId
});
thing.save().then(
() => {
res.status(201).json({
message: ‘Post saved successfully!’
});
}
).catch(
(error) => {
res.status(400).json({
error: error
});
}
);
});

router.get(‘/:id’, (req, res, next) => {
Thing.findOne({
_id: req.params.id
}).then(
(thing) => {
res.status(200).json(thing);
}
).catch(
(error) => {
res.status(404).json({
error: error
});
}
);
});

router.put(‘/:id’, (req, res, next) => {
const thing = new Thing({
_id: req.params.id,
title: req.body.title,
description: req.body.description,
imageUrl: req.body.imageUrl,
price: req.body.price,
userId: req.body.userId
});
Thing.updateOne({_id: req.params.id}, thing).then(
() => {
res.status(201).json({
message: ‘Thing updated successfully!’
});
}
).catch(
(error) => {
res.status(400).json({
error: error
});
}
);
});

router.delete(‘/:id’, (req, res, next) => {
Thing.deleteOne({_id: req.params.id}).then(
() => {
res.status(200).json({
message: ‘Deleted!’
});
}
).catch(
(error) => {
res.status(400).json({
error: error
});
}
);
});

router.get(‘/’ +
”, (req, res, next) => {
Thing.find().then(
(things) => {
res.status(200).json(things);
}
).catch(
(error) => {
res.status(400).json({
error: error
});
}
);
});

module.exports = router;
…………………………………………………………….

Create a new controllers folder in your backend folder, and create another stuff.js file — this one will be our stuff controller. Let’s copy our first piece of business logic from our POST route to our controller:

……………………………..
backend/controllers/stuff.js
……………………………………….
const Thing = require(‘../models/thing’);

exports.createThing = (req, res, next) => {
const thing = new Thing({
title: req.body.title,
description: req.body.description,
imageUrl: req.body.imageUrl,
price: req.body.price,
userId: req.body.userId
});
thing.save().then(
() => {
res.status(201).json({
message: ‘Post saved successfully!’
});
}
).catch(
(error) => {
res.status(400).json({
error: error
});
}
);
};

exports.getOneThing = (req, res, next) => {
Thing.findOne({
_id: req.params.id
}).then(
(thing) => {
res.status(200).json(thing);
}
).catch(
(error) => {
res.status(404).json({
error: error
});
}
);
};

exports.modifyThing = (req, res, next) => {
const thing = new Thing({
_id: req.params.id,
title: req.body.title,
description: req.body.description,
imageUrl: req.body.imageUrl,
price: req.body.price,
userId: req.body.userId
});
Thing.updateOne({_id: req.params.id}, thing).then(
() => {
res.status(201).json({
message: ‘Thing updated successfully!’
});
}
).catch(
(error) => {
res.status(400).json({
error: error
});
}
);
};

exports.deleteThing = (req, res, next) => {
Thing.deleteOne({_id: req.params.id}).then(
() => {
res.status(200).json({
message: ‘Deleted!’
});
}
).catch(
(error) => {
res.status(400).json({
error: error
});
}
);
};

exports.getAllStuff = (req, res, next) => {
Thing.find().then(
(things) => {
res.status(200).json(things);
}
).catch(
(error) => {
res.status(400).json({
error: error
});
}
);
};

…………………………………..
updated routes
……………………………..
backend/routes/stuff.js
………………………………
const express = require(‘express’);
const router = express.Router();

const stuffCtrl = require(‘../controllers/stuff’);

router.get(‘/’, stuffCtrl.getAllStuff);
router.post(‘/’, stuffCtrl.createThing);
router.get(‘/:id’, stuffCtrl.getOneThing);
router.put(‘/:id’, stuffCtrl.modifyThing);
router.delete(‘/:id’, stuffCtrl.deleteThing);

module.exports = router;
……………………………………………
To make sure that two users cannot use the same email address, we will be using the unique keyword. However, the errors thrown by MongoDB by default can be tricky to unpack, so to make our lives easier, we will be installing a validation package to pre-validate information before saving:
………………………………………..
npm install –save mongoose-unique-validator
………………………………………….

backend/models/user.js
………………………………………………..
const mongoose = require(‘mongoose’);
const uniqueValidator = require(‘mongoose-unique-validator’);

const userSchema = mongoose.Schema({
email: { type: String, required: true, unique: true },
password: { type: String, required: true }
});

userSchema.plugin(uniqueValidator);

module.exports = mongoose.model(‘User’, userSchema);
………………………………………………..
Create another user.js file, this time in your routes folder:
………………………………….
backend/routes/user.js
………………………
const express = require(‘express’);
const router = express.Router();

const userCtrl = require(‘../controllers/user’);

router.post(‘/signup’, userCtrl.signup);
router.post(‘/login’, userCtrl.login);

module.exports = router;
………………………………….
Now let’s register our router with our app. First, import the router:

const userRoutes = require(‘./routes/user’);
And then register it:

app.use(‘/api/stuff’, stuffRoutes);
app.use(‘/api/auth’, userRoutes);
Our routes are now ready, so it’s time to start implementing the business logic.
……………………………………………………………

We will be needing the bcrypt encryption package for our signup function, so let’s install it to our project:

npm install –save bcrypt
We can now import it to our controller, and implement our signup function (don’t forget to import your user model!):
……………………………………………

To be able to create and verify authentication tokens, we will need a new package:

npm install –save jsonwebtoken
We will then import it in our user controller:
…………………………………..
backend/controllers/user.js
………………………………..
const jwt = require(‘jsonwebtoken’);
const bcrypt = require(‘bcrypt’);
const User = require(‘../models/user’);

exports.signup = (req, res, next) => {
bcrypt.hash(req.body.password, 10).then(
(hash) => {
const user = new User({
email: req.body.email,
password: hash
});
user.save().then(
() => {
res.status(201).json({
message: ‘User added successfully!’
});
}
).catch(
(error) => {
res.status(500).json({
error: error
});
}
);
}
);
};

exports.login = (req, res, next) => {
User.findOne({ email: req.body.email }).then(
(user) => {
if (!user) {
return res.status(401).json({
error: new Error(‘User not found!’)
});
}
bcrypt.compare(req.body.password, user.password).then(
(valid) => {
if (!valid) {
return res.status(401).json({
error: new Error(‘Incorrect password!’)
});
}
const token = jwt.sign(
{ userId: user._id },
‘RANDOM_TOKEN_SECRET’,
{ expiresIn: ’24h’ });
res.status(200).json({
userId: user._id,
token: token
});
}
).catch(
(error) => {
res.status(500).json({
error: error
});
}
);
}
).catch(
(error) => {
res.status(500).json({
error: error
});
}
);
}

…………………………………..
We are now going to create the middleware which will protect selected routes, and ensure that a user is authenticated before allowing their requests to go through.

Create a new middleware folder, and an auth.js file inside it:
………………………………
backend/middleware/auth.js
…………………………………………………
const jwt = require(‘jsonwebtoken’);

module.exports = (req, res, next) => {
try {
const token = req.headers.authorization.split(‘ ‘)[1];
const decodedToken = jwt.verify(token, ‘RANDOM_TOKEN_SECRET’);
const userId = decodedToken.userId;
if (req.body.userId && req.body.userId !== userId) {
throw ‘Invalid user ID’;
} else {
next();
}
} catch {
res.status(401).json({
error: new Error(‘Invalid request!’)
});
}
};
……………………………………………………
updated backend/routes/stuff.js
……………………………………………..
const express = require(‘express’);
const router = express.Router();

const auth = require(‘../middleware/auth’);

const stuffCtrl = require(‘../controllers/stuff’);

router.get(‘/’, auth, stuffCtrl.getAllStuff);
router.post(‘/’, auth, stuffCtrl.createThing);
router.get(‘/:id’, auth, stuffCtrl.getOneThing);
router.put(‘/:id’, auth, stuffCtrl.modifyThing);
router.delete(‘/:id’, auth, stuffCtrl.deleteThing);

module.exports = router;
……………………………………………..

add image files to our API
accept incoming files with multer
install multer in the backend directory
…………………………
npm install –save multer
……………………….
Now we can create a new piece of middleware in our middleware folder called multer-config.js :
……………………………………………
backend/middleware/multer-config.js
…………………………………
const multer = require(‘multer’);

const MIME_TYPES = {
‘image/jpg’: ‘jpg’,
‘image/jpeg’: ‘jpg’,
‘image/png’: ‘png’
};

const storage = multer.diskStorage({
destination: (req, file, callback) => {
callback(null, ‘images’);
},
filename: (req, file, callback) => {
const name = file.originalname.split(‘ ‘).join(‘_’);
const extension = MIME_TYPES[file.mimetype];
callback(null, name + Date.now() + ‘.’ + extension);
}
});

module.exports = multer({storage: storage}).single(‘image’);
……………………………………………………….
make sure you create a folder called images in your backend directory
………………………………………………………….

updated stuff.js controller
…………………………………..
backend/controllers/stuff.js
………………………………………..
const fs = require(‘fs’);

exports.createThing = (req, res, next) => {
req.body.thing = JSON.parse(req.body.thing);
const url = req.protocol + ‘://’ + req.get(‘host’);
const thing = new Thing({
title: req.body.thing.title,
description: req.body.thing.description,
imageUrl: url + ‘/images/’ + req.file.filename,
price: req.body.thing.price,
userId: req.body.thing.userId
});
thing.save().then(
() => {
res.status(201).json({
message: ‘Post saved successfully!’
});
}
).catch(
(error) => {
res.status(400).json({
error: error
});
}
);
};

exports.getOneThing = (req, res, next) => {
Thing.findOne({
_id: req.params.id
}).then(
(thing) => {
res.status(200).json(thing);
}
).catch(
(error) => {
res.status(404).json({
error: error
});
}
);
};

exports.modifyThing = (req, res, next) => {
let thing = new Thing({ _id: req.params._id });
if (req.file) {
const url = req.protocol + ‘://’ + req.get(‘host’);
req.body.thing = JSON.parse(req.body.thing);
thing = {
_id: req.params.id,
title: req.body.thing.title,
description: req.body.thing.description,
imageUrl: url + ‘/images/’ + req.file.filename,
price: req.body.thing.price,
userId: req.body.thing.userId
};
} else {
thing = {
_id: req.params.id,
title: req.body.title,
description: req.body.description,
imageUrl: req.body.imageUrl,
price: req.body.price,
userId: req.body.userId
};
}
Thing.updateOne({_id: req.params.id}, thing).then(
() => {
res.status(201).json({
message: ‘Thing updated successfully!’
});
}
).catch(
(error) => {
res.status(400).json({
error: error
});
}
);
};

exports.deleteThing = (req, res, next) => {
Thing.findOne({_id: req.params.id}).then(
(thing) => {
const filename = thing.imageUrl.split(‘/images/’)[1];
fs.unlink(‘images/’ + filename, () => {
Thing.deleteOne({_id: req.params.id}).then(
() => {
res.status(200).json({
message: ‘Deleted!’
});
}
).catch(
(error) => {
res.status(400).json({
error: error
});
}
);
});
}
);
};

exports.getAllStuff = (req, res, next) => {
Thing.find().then(
(things) => {
res.status(200).json(things);
}
).catch(
(error) => {
res.status(400).json({
error: error
});
}
);
};
……………………….
updated routes
………………………
backend/routes/stuff.js
…………………………..

const express = require(‘express’);
const router = express.Router();

const auth = require(‘../middleware/auth’);
const multer = require(‘../middleware/multer-config’);

const stuffCtrl = require(‘../controllers/stuff’);

router.get(‘/’, auth, stuffCtrl.getAllStuff);
router.post(‘/’, auth, multer, stuffCtrl.createThing);
router.get(‘/:id’, auth, stuffCtrl.getOneThing);
router.put(‘/:id’, auth, multer, stuffCtrl.modifyThing);
router.delete(‘/:id’, auth, stuffCtrl.deleteThing);

module.exports = router;
………………………………..
We will need a new import in app.js :

const path = require(‘path’);
And we add the following route handler just above our current routes:

app.use(‘/images’, express.static(path.join(__dirname, ‘images’)));
…………………………………………………………………………

Leave a Reply

Your email address will not be published. Required fields are marked *

Open chat