λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°
Node.js

[React + Node.js + mongoDB] CRUD app λ§Œλ“€κΈ°

by naahy 2023. 6. 27.
πŸ“Œ bezkoder
https://www.bezkoder.com/react-node-express-mongodb-mern-stack/

 

Node.js + mongoDB

1. 폴더 ν•˜λ‚˜λ₯Ό λ§Œλ“€κ³  ν•΄λ‹Ή μœ„μΉ˜μ—μ„œ vs codeλ₯Ό μ—°λ‹€

 

2. ctrl + ` λˆŒλŸ¬μ„œ ν„°λ―Έ μ—΄κ³  μ•„λž˜ λͺ…λ Ήμ–΄ μž…λ ₯

npm install express mongoose body-parser cors --save

 

3. 루트 ν΄λ”μ—μ„œ server.js 파일 생성 ν›„ μ•„λž˜μ™€ 같이 μ½”λ“œ μž…λ ₯

const express = require("express");
const bodyParser = require("body-parser");
const cors = require("cors");

const app = express();

var corsOptions = {
  origin: "http://localhost:8081"
};

app.use(cors(corsOptions));

// parse requests of content-type - application/json
app.use(bodyParser.json());

// parse requests of content-type - application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: true }));

// simple route
app.get("/", (req, res) => {
  res.json({ message: "Welcome to bezkoder application." });
});

// set port, listen for requests
const PORT = process.env.PORT || 8080;
app.listen(PORT, () => {
  console.log(`Server is running on port ${PORT}.`);
});

 

4. ν„°λ―Έλ„μ—μ„œ node server.js λͺ…λ Ήμ–΄ μ‹€ν–‰

이 λ•Œ Error: listen EADDRINUSE: address already in use :::8080 κ³Ό 같은 μ—λŸ¬κ°€ λ‚  수 μžˆλŠ”λ°, κ·Έλƒ₯ ν•΄λ‹Ή ν¬νŠΈκ°€ μ‚¬μš© μ€‘μ΄λΌλŠ” λ§μ΄λ―€λ‘œ portλ₯Ό μ„ΈνŒ…ν•  λ•Œ 8080 λŒ€μ‹  λ‹€λ₯Έ 숫자λ₯Ό μ‚¬μš©ν•˜λ©΄ λœλ‹€. (ex. 8090)

 

5. app폴더 생성 ν›„ app/config/db.config.js 파일 μž‘μ„±

module.exports = {
  url: "mongodb://localhost:27017/bezkoder_db"
};

이 λ•Œ 버전이 17.x 이상이면 url에 localhost λŒ€μ‹  127.0.0.1을 써야함

 

6. app/models/index.js 파일 생성

const dbConfig = require("../config/db.config.js");

const mongoose = require("mongoose");
mongoose.Promise = global.Promise;

const db = {};
db.mongoose = mongoose;
db.url = dbConfig.url;
db.tutorials = require("./tutorial.model.js")(mongoose);

module.exports = db;

 

6-1. server.js 파일 λ‚΄μ—μ„œ connect() ν•¨μˆ˜ 호좜 (κΈ°μ‘΄ λ‚΄μš©μ— μ•„λž˜ μ½”λ“œλ§Œ 덧뢙이면 됨)

...
const app = express();
app.use(...);

const db = require("./app/models");
db.mongoose
  .connect(db.url, {
    useNewUrlParser: true,
    useUnifiedTopology: true
  })
  .then(() => {
    console.log("Connected to the database!");
  })
  .catch(err => {
    console.log("Cannot connect to the database!", err);
    process.exit();
  });

 

7. app/models/tutorial.model.js 파일 생성

module.exports = mongoose => {
  const Tutorial = mongoose.model(
    "tutorial",
    mongoose.Schema(
      {
        title: String,
        description: String,
        published: Boolean
      },
      { timestamps: true }
    )
  );

  return Tutorial;
};

이 λ•Œ ν”„λ‘ νŠΈμ—”λ“œμ™€ ν•¨κ»˜ 이 앱을 μ‚¬μš©ν•  거라면 _id λŒ€μ‹  idλ₯Ό μ‚¬μš©ν•΄μ•Ό ν•˜λ―€λ‘œ toJSON λ©”μ†Œλ“œ μ˜€λ²„λΌμ΄λ“œ ν•„μš”

module.exports = mongoose => {
  var schema = mongoose.Schema(
    {
      title: String,
      description: String,
      published: Boolean
    },
    { timestamps: true }
  );

  schema.method("toJSON", function() {
    const { __v, _id, ...object } = this.toObject();
    object.id = _id;
    return object;
  });

  const Tutorial = mongoose.model("tutorial", schema);
  return Tutorial;
};

 

8. app/controllers/tutorial.controller.js 파일 생성

const db = require("../models");
const Tutorial = db.tutorials;

// Create and Save a new Tutorial
exports.create = (req, res) => {
  
};

// Retrieve all Tutorials from the database.
exports.findAll = (req, res) => {
  
};

// Find a single Tutorial with an id
exports.findOne = (req, res) => {
  
};

// Update a Tutorial by the id in the request
exports.update = (req, res) => {
  
};

// Delete a Tutorial with the specified id in the request
exports.delete = (req, res) => {
  
};

// Delete all Tutorials from the database.
exports.deleteAll = (req, res) => {
  
};

// Find all published Tutorials
exports.findAllPublished = (req, res) => {
  
};

각 λ©”μ†Œλ“œ λ‚΄μš©μ€ https://www.bezkoder.com/node-express-mongodb-crud-rest-api/ μ°Έμ‘°

(+) νŽ˜μ΄μ§€λ„€μ΄μ…˜ https://www.bezkoder.com/node-js-mongodb-pagination/

 

9. app/routes/tutorial.routes.js 파일 생성

module.exports = app => {
  const tutorials = require("../controllers/tutorial.controller.js");

  var router = require("express").Router();

  // Create a new Tutorial
  router.post("/", tutorials.create);

  // Retrieve all Tutorials
  router.get("/", tutorials.findAll);

  // Retrieve all published Tutorials
  router.get("/published", tutorials.findAllPublished);

  // Retrieve a single Tutorial with id
  router.get("/:id", tutorials.findOne);

  // Update a Tutorial with id
  router.put("/:id", tutorials.update);

  // Delete a Tutorial with id
  router.delete("/:id", tutorials.delete);

  // Delete all Tutorials
  router.delete("/", tutorials.deleteAll);

  app.use('/api/tutorials', router);
};

 

9-1. server.js 파일 λ‚΄μ—μ„œ routes 포함 (app.listen 직전에 μ½”λ“œ μž‘μ„±)

...

require("./app/routes/tutorial.routes")(app);

// set port, listen for requests
const PORT = ...;
app.listen(...);

 

10. ν„°λ―Έλ„μ—μ„œ node server.js λͺ…λ Ήμ–΄ μ‹€ν–‰

μœ„μ™€ 같은 λ¬Έμž₯이 뜨면 잘 μ—°κ²°λœ 것

주의) mongoDB λ‚΄μ—μ„œ λ°μ΄ν„°λ² μ΄μŠ€λ₯Ό μƒμ„±ν•œ ν›„ μ‹€ν–‰ν•΄μ•Ό ν•˜λŠ” 것 μžŠμ§€ 말기

 

11. Postman μ‚¬μš©ν•˜μ—¬ ν…ŒμŠ€νŠΈ (μƒˆ νŠœν† λ¦¬μ–Ό 생성)

mongoDB Collection ν™•μΈν•œ λͺ¨μŠ΅

κ·Έ μ™Έ λ©”μ†Œλ“œλŠ” bezkoder νŽ˜μ΄μ§€ λ‚΄μ—μ„œ 확인할 수 있음

 

React

λ°±μ—”λ“œ μ½”λ“œκ°€ μ €μž₯λ˜μ–΄μžˆλŠ” 폴더 말고 ν”„λ‘ νŠΈμ—”λ“œ μ½”λ“œλ₯Ό 생성할 파일 λ”°λ‘œ 생성

(본인은 ν”„λ‘œμ νŠΈ 폴더 내에 backend 폴더와 frontend 폴더λ₯Ό λ”°λ‘œ λ‘μ—ˆμŒ)

backend 폴더엔 node.js + mongoDB, frontend 폴더엔 React

 

1. ν”„λ‘œμ νŠΈ 폴더 λ‚΄μ—μ„œ μ•„λž˜ λͺ…λ Ήμ–΄ μ‹€ν–‰

npx create-react-app 폴더λͺ…

 

Import Bootstrap

1. ν•΄λ‹Ή ν΄λ”λ‘œ 이동 ν›„ μ•„λž˜ λͺ…λ Ήμ–΄ μ‹€ν–‰

npm install bootstrap

 

2. src/App.js 파일 λ‚΄μ—μ„œ import

import React, { Component } from "react";
import "bootstrap/dist/css/bootstrap.min.css";

 

React Router μΆ”κ°€

1. μ»€λ§¨λ“œ μ‹€ν–‰

npm install react-router-dom

 

2. src/index.js 파일 μ˜€ν”ˆ ν›„ μ•„λž˜ μ½”λ“œλ‘œ λŒ€μ²΄

import React from "react";
import { createRoot } from "react-dom/client";
import { BrowserRouter } from "react-router-dom";

import App from "./App";

const container = document.getElementById("root");
const root = createRoot(container);

root.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>
);

 

Navbar μΆ”κ°€

1. src/App.js 파일 μ˜€ν”ˆ ν›„ render() 내에 μ•„λž˜ μ½”λ“œ μž‘μ„±

import React, { Component } from "react";
...

class App extends Component {
  render() {
    return (
      <div>
        <nav className="navbar navbar-expand navbar-dark bg-dark">
          <a href="/tutorials" className="navbar-brand">
            bezKoder
          </a>
          <div className="navbar-nav mr-auto">
            <li className="nav-item">
              <Link to={"/tutorials"} className="nav-link">
                Tutorials
              </Link>
            </li>
            <li className="nav-item">
              <Link to={"/add"} className="nav-link">
                Add
              </Link>
            </li>
          </div>
        </nav>

        <div className="container mt-3">
          <Routes>
            <Route path="/" element={<TutorialsList/>} />
            <Route path="/tutorials" element={<TutorialsList/>} />
            <Route path="/add" element={<AddTutorial/>} />
            <Route path="/tutorials/:id" element={<Tutorial/>} />
          </Routes>
        </div>
      </div>
    );
  }
}

 

Initialize Axios for React CRUD HTTP Client

1. μ»€λ§¨λ“œ μ‹€ν–‰

npm install axios

 

2. src 폴더 내에 http-common.js 파일 생성 ν›„ μ•„λž˜ μ½”λ“œ μž‘μ„±

import axios from "axios";

export default axios.create({
  baseURL: "http://localhost:8080/api",
  headers: {
    "Content-type": "application/json"
  }
});

이 λ•Œ baseURL은 backend 루트 폴더 λ‚΄ server.js 포트 λ²ˆν˜Έμ™€ κ°™κ²Œ 함

 

Data service 생성

- services/tutorial.service.js

import http from "../http-common";

class TutorialDataService {
  getAll() {
    return http.get("/tutorials");
  }

  get(id) {
    return http.get(`/tutorials/${id}`);
  }

  create(data) {
    return http.post("/tutorials", data);
  }

  update(id, data) {
    return http.put(`/tutorials/${id}`, data);
  }

  delete(id) {
    return http.delete(`/tutorials/${id}`);
  }

  deleteAll() {
    return http.delete(`/tutorials`);
  }

  findByTitle(title) {
    return http.get(`/tutorials?title=${title}`);
  }
}

export default new TutorialDataService();

 

μ»΄ν¬λ„ŒνŠΈ μž‘μ„±

μ•„λž˜ 링크 μ°Έκ³ 

https://www.bezkoder.com/react-crud-web-api/

 

μ‹€ν–‰

λ°±μ—”λ“œ μ‹€ν–‰(node server.js) ν›„ ν”„λ‘ νŠΈμ—”λ“œ μ‹€ν–‰ (npm start)

μ„±κ³΅ν•˜λ©΄ μžλ™μœΌλ‘œ μ•„λž˜μ™€ 같은 νŽ˜μ΄μ§€κ°€ λ‚˜νƒ€λ‚¨

'Node.js' μΉ΄ν…Œκ³ λ¦¬μ˜ λ‹€λ₯Έ κΈ€

[MongoDB/μ—λŸ¬] connect econnrefused ::1:27017  (0) 2023.05.26

λŒ“κΈ€