MERN - quick guide (for experts)

  1. npm init -y
  2. Create in root of the proj .prettierrc.json
  3. Add script --- "start:dev": "nodemon app.js" --- to package.json for starting backend
  4. create app.js
  5. npm i express cors dotenv mongoose
    and
    npm i nodemon -D
  6. 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
  7. 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
  8. 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/ )

  9. 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
  10. 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;

    • Reexport functions from controllers folder by making controllers/products/index.js file
      • controllers/products/index.js

        const getAllProductsCTRL = require('./getAllProductsCTRL'); module.exports = {getAllProductsCTRL};

    • Import all product controllers from controllers/products folder to controllers/index.js
      • controllers/index.js

        const productsControllers = require('./products'); module.exports = { productsControllers };

    • 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
  11. 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

  12. 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).
  13. 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.)
  14. 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};

    • Import all product services from services/products folder to services/index.js
      • services/index.js

        const productServices = require('./products'); module.exports = { productServices };

    • Refactor controllers/products/addProductCTRL.js

      See the Pen 61__refactored addProductCTRL due to services by Andrii (@imitator) on CodePen.

  15. Refactor getAllProductsCTRL.js to the new organize folders (means services)
  16. 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);
    • 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 findUserSRV
      User.findOne(filter);
      in loginCTRL. So we find user by e-mail filed like
      const user = await service.findUser({ email: req.body.email });
  17. PUT
  18. DELETE
    • Create services/products/deleteProductSRV.js

      See the Pen 68__ by Andrii (@imitator) on CodePen.

    • Create deleteProductCTRL.js

      See the Pen 69__ by Andrii (@imitator) on CodePen.

    • Add route to
      • routes\products.routes.js
        router.delete('/:id', ctrl.deleteProductCTRL);
    • p.s. Remember about reexports
  19. Add "Not Found" middleware for looking unexpected route after all middlewares.
  20. Create user schema & model
    & use schema in
    P.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
  21. User REGISTRATION

    • Main 2 steps in register
      1. 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.js
          const findUser = require('./findUserSRV');
          module.exports = { findUser };
          And from services\index.js
          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');
        • 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.js
          const auth = require('./auth.routes');
        • Use auth routes in app.js
          app.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',
      2. Add user.
  22. 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.js
      P.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.js
      router.post('/login', ctrl.loginCTRL);
      And check request
      http://localhost:5555/api/v1/auth/login
      with necessary login and password
    • Generate token and return it in response
      • npm i jsonwebtoken
      • .env - add some kind of SECRET_KEY=someString
      • See the Pen 74__ by Andrii (@imitator) on CodePen.

      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

  23. 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
  24. 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
  25. Add AVATAR for user

    1. Extract file from request (from special field) and put it to the temporary folder So, in this step a file will be uploaded to "temp" folder
    2. 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")
  26. Create IMAGE GALLERY for site