MERN - quick guide (for experts)
- npm init -y
- Create in root of the proj .prettierrc.json
- Add script --- "start:dev": "nodemon app.js" --- to package.json for starting backend
- create app.js
-
npm i express cors dotenv mongooseandnpm i nodemon -D
-
Add .env file in root of project with necessary
- PORT=5555
- DB_HOST=mongodb+srv://admin:PASSWORD@testcluster.8md36bg.mongodb.net/DBNAME?retryWrites=true&w=majority
-
Before pushing the initial repository to the github remember
about adding .gitignore to the project including in the
beginning
-
node_modules/
-
.env
- package-lock.json
-
-
Add to app.js simplest express backend server by
See the Pen 1-simplest Express web-server by Andrii (@imitator) on CodePen.
For checking of the server working type in terminal npm run start:dev and look at this on http://localhost:5555/ (or http://127.0.0.1:5555/ )
-
Create -- routes -- folder in our proj for separating routes
from main app.js
-
Create file
routes/products.routes.js
for making routes for product endpoints
See the Pen 3-A __ routes/products.routes.js by Andrii (@imitator) on CodePen.
-
In future we will have more routes (users, customers etc),
so we should group them in some kind of
routes/index.js
where we reexport products
const products = require('./products.routes');module.exports = { products, };
-
Then import routes in
app.js
const routes = require('./routes');
-
And use routes in app.js by
middleware like
app.use('/api/v1/products', routes.products);
-
For checking our products responding go to http://localhost:5555/api/v1/products
-
Create file
routes/products.routes.js
for making routes for product endpoints
-
The next step in making convenient web-server is separating
controllers from routes folder by creating controllers folder in
main project folder.
-
Create controllers/products folder,
so move controller from
routes/products.routes.js
-
controllers/products/getAllProductsCTRL.js
const getAllProductsCTRL = (req, res) => {
res.json([{name: 'IPhone5',price: 10000,}]);};module.exports = getAllProductsCTRL;
-
controllers/products/getAllProductsCTRL.js
-
Reexport functions from controllers folder by making
controllers/products/index.js file
-
controllers/products/index.js
const getAllProductsCTRL = require('./getAllProductsCTRL'); module.exports = {getAllProductsCTRL};
-
controllers/products/index.js
-
Import all product controllers from controllers/products
folder to controllers/index.js
-
controllers/index.js
const productsControllers = require('./products'); module.exports = { productsControllers };
-
controllers/index.js
-
Import product controllers from controllers folder & use
necessary one
-
routes/products.routes.js
const express = require('express'); const router = express.Router(); const { productsControllers: ctrl } = require('../controllers'); router.get('/', ctrl.getAllProductsCTRL); module.exports = router;
P.S. For checking again refresh or go to http://localhost:5555/api/v1/products
-
routes/products.routes.js
-
Create controllers/products folder,
so move controller from
routes/products.routes.js
-
Add mongoDB connection code to app.js
See the Pen 14 - MongoDB connection by Andrii (@imitator) on CodePen.
Or a little bit refactored app.js in this step.You may miss steps before taking repo (branch "master") with all structure, REMEMBER to check .env for existing PORT=, DB_HOST=, and make in terminal npm i
- Make the simplest Schema in models/schemas/product.schema.js for quick start with MongoDb (or go to MongoDb Schema for making a usual projects one).
-
POST
-
Create controllers/products/addProductCTRL.js
See the Pen 18 - POST ctrl using for MongoDB by Andrii (@imitator) on CodePen.
(remember about reexports in controllers\products\index.js)Some errors aren't in list of http-status-codes, so we try to handle them in catch(error){}, other errors we gather in other place by sending them in next(error), in app.js(index.js), this will be explaining in next Catching errors middleware guide
- Add Catching errors middleware to server.js (or index.js) after all middlewares.
- Create in routes/products.routes.js the route: router.post('/', ctrl.addProductCTRL);
- Make some post request (via POSTMAN f.e.)
-
Create controllers/products/addProductCTRL.js
-
The next step of creating a convenient web-server project is
separating transferring information to mongoDB from controllers
(means like Model.create(), Model.find()) to separate folder,
called services in root of a project.
-
Create services/products/addProductSRV.js
See the Pen 60__srv_addItem by Andrii (@imitator) on CodePen.
-
Reexport functions from services folder by making
services/products/index.js file
-
services/products/index.js
const addProductSRV = require('./addProductSRV'); module.exports = {addProductSRV};
-
services/products/index.js
-
Import all product services from services/products folder to
services/index.js
-
services/index.js
const productServices = require('./products'); module.exports = { productServices };
-
services/index.js
-
Refactor controllers/products/addProductCTRL.js
See the Pen 61__refactored addProductCTRL due to services by Andrii (@imitator) on CodePen.
-
Create services/products/addProductSRV.js
-
Refactor getAllProductsCTRL.js to the new organize folders
(means services)
-
Create
services/products/getAllProductsSRV.js
See the Pen 63__getAllProductsSRV by Andrii (@imitator) on CodePen.
p.s. Remember about reexports -
Refactor
getAllProductsCTRL.js
See the Pen 62__getAllProductsSRV by Andrii (@imitator) on CodePen.
-
Create
services/products/getAllProductsSRV.js
-
GET
Create getProductById
-
Create
services/products/getProductByIdSRV.js
See the Pen 64__getProductByIdSRV by Andrii (@imitator) on CodePen.
p.s. Remember about reexports -
Create
getProductByIdCTRL.js
See the Pen 65__getProductByIdCTRL by Andrii (@imitator) on CodePen.
p.s. Remember about reexports -
Add route to
-
routes\products.routes.js
router.get('/:id', ctrl.getProductByIdCTRL);
-
routes\products.routes.js
-
P.S. remember about other methods for finding item, like
Product.findOne({ _id: id });Product.findOne({ email });F.e. use service find by any filed findUserSRVUser.findOne(filter);in loginCTRL. So we find user by e-mail filed likeconst user = await service.findUser({ email: req.body.email });
-
Create
services/products/getProductByIdSRV.js
-
PUT
-
Create
services/products/updateProductByIdSRV.js
See the Pen 66__updateProductSRV by Andrii (@imitator) on CodePen.
-
Create
updateProductByIdCTRL.js
See the Pen 67__updateProductCTRL by Andrii (@imitator) on CodePen.
-
Add route to
-
routes\products.routes.js
router.put('/:id', ctrl.updateProductByIdCTRL);
-
routes\products.routes.js
- p.s. Remember about reexports
-
Create
services/products/updateProductByIdSRV.js
- DELETE
- Add "Not Found" middleware for looking unexpected route after all middlewares.
-
Create user schema & model& use schema inP.S. Remember about reexports form schemas/index.js and models/index.js
You may miss steps before taking repo (branch "1_main_ctrls") with all structure, REMEMBER to check .env for existing PORT=, DB_HOST=, and make in terminal npm i
For next convenience users CTRLs were added: getAll, getById, delete, these ctrl-s should used by admins adn were created for development -
User REGISTRATION
-
Main 2 steps in register
-
Look at an user existing in DB
-
services\users\findUserSRV.js
See the Pen 70__findUser.js by Andrii (@imitator) on CodePen.
P.S. Remember about reexport from services\users\index.jsAnd from services\index.jsconst findUser = require('./findUserSRV');module.exports = { findUser };const userServices = require('./users'); -
controllers\auth\registerCTRL.js
See the Pen 71__ by Andrii (@imitator) on CodePen.
Remember about reexports form-
controllers\auth\index.js
const registerCTRL = require('./registerCTRL');module.exports = { registerCTRL };
-
controllers\index.js
const authControllers = require('./auth');
-
controllers\auth\index.js
-
Add the route for registration
routes\auth.routes.js
See the Pen 44__Register-route by Andrii (@imitator) on CodePen.
P.S. Remember about reexport in routes\index.jsconst auth = require('./auth.routes'); -
Use auth routes in app.jsapp.use('/api/v1/auth', routes.auth);
-
Make necessary post request to
http://localhost:5555/api/v1/auth/register with
email & password fields for checking temporary
response:
message: 'Everything is ok, delete this if(){} before next step',
-
services\users\findUserSRV.js
-
Add user.
- npm i bcryptjs
- services\users\addUserSRV.js
-
controllers\auth\registerCTRL.js
See the Pen 46__Register_CTRL__add-user by Andrii (@imitator) on CodePen.
P.S. Make request tohttp://localhost:5555/api/v1/auth/registerone more time for user register.
-
Look at an user existing in DB
-
Main 2 steps in register
-
LOGIN (authentication)
-
Look at an user exists in DB
and compare password at the same time .
controllers\auth\loginCTRL.js
See the Pen 73_ by Andrii (@imitator) on CodePen.
P.S. Remember about reexport in controllers\auth\index.jsP.S. But if business give us task to write all answers, we should do it like this code -
Add the route for login
routes\auth.routes.jsrouter.post('/login', ctrl.loginCTRL);And check requesthttp://localhost:5555/api/v1/auth/loginwith necessary login and password
-
Generate token and return it in response
- npm i jsonwebtoken
- .env - add some kind of SECRET_KEY=someString
You may miss steps before taking repo (branch "2_register_login") with all structure, REMEMBER to check .env for existing PORT=, DB_HOST=, SECRET_KEY=, and make in terminal npm i
-
Look at an user exists in DB
and compare password at the same time .
-
Authorization
-
Use authorization from section "Authorization" in
Add registration, authentication & authorization.
There are two ways of using authorization via passport +
passport-jwt, MISS SHORT PART of guide
Automatically "Unauthorized" response & minimum settings
in passport.authenticate() method
You may miss steps before by taking repo (branch "3_authorization") with all structure, REMEMBER to check .env for existing PORT=, DB_HOST=, SECRET_KEY=, and make in terminal npm i
-
Use authorization from section "Authorization" in
Add registration, authentication & authorization.
There are two ways of using authorization via passport +
passport-jwt, MISS SHORT PART of guide
Automatically "Unauthorized" response & minimum settings
in passport.authenticate() method
-
LOGOUT
Use LOGOUT from section "Logout" in Add registration, authentication & authorization.You may miss steps before by taking repo (branch "4_logout") with all structure, REMEMBER to check .env for existing PORT=, DB_HOST=, SECRET_KEY=, and make in terminal npm i -
Add AVATAR for user
-
Extract file from request (from special field) and put it to
the temporary folder
- Create temp dir
- npm i multer
- Create middlewares/extractAvatarMDW.js
-
Use middleware in /register route
const { authMDW,const { authMDW, extractAvatarMDW } = require('../middlewares');router.post('/register', extractAvatarMDW, ctrl.registerCTRL);
- Create request in POSTMAN ( Look at point in POST requests guide Request for file sending > B) )
-
Move file from temporary directory to the "upload" or unlink
it (delete file from "temp" in case if file could not be
moved to "upload")
- Create "upload" folder
- Create full "CTRL"
-
Extract file from request (from special field) and put it to
the temporary folder
-
Create IMAGE GALLERY for site