π Update Date: 2024-05-27
μ΄ λ¦¬ν¬μ§ν 리λ μ€ννλΌ νλ‘μ νΈ μλ² κ΅¬νμ μν΄ λ Έλ ₯ν κ³Όμ κ³Ό μ½λλ₯Ό μ 곡ν©λλ€.
- Node.js μ€μΉ ν npm νκ²½ λ³μ λ±λ‘
- MongoDB Atlas μ Organization, Project, Cluster μμ±
- MongoDB Compass λ° mongosh μ€μΉ
- μλ² μ½λλ₯Ό μ μ₯ν ν΄λλ₯Ό μμ± ν VS Code ν°λ―Έλ μ€ν
- npm λͺ¨λ μ€μΉ: express, mongoose, nodemon, axios
npm init -y
npm i express mongoose axios
npm i -D nodemon
- MongoDB Atlas: MongoDB μμ μ 곡νλ ν΄λΌμ°λ λ°μ΄ν°λ² μ΄μ€ μλΉμ€
- MongoDB Compass: λ°μ΄ν°λ² μ΄μ€ κ΄λ¦¬μ GUI νκ²½μ μ 곡νλ νλ‘κ·Έλ¨
- MongoDB Shell (mongosh): ν°λ―Έλμμ λ°μ΄ν°λ² μ΄μ€ κ΄λ¦¬ κΈ°λ₯μ μ 곡νλ νλ‘κ·Έλ¨
- Mongoose: Node.js νκ²½μμ μμ£Ό μ½κ² MongoDB κ°μ²΄ λͺ¨λΈλ§μ μ§μνλ λΌμ΄λΈλ¬λ¦¬. 볡μ‘ν λ°μ΄ν° λͺ¨λΈμ΄λ κ΄κ³ν λͺ¨λΈμ μκ°ν νμ μμ΄ JavaScript νμΌμ μ€ν€λ§ λͺ¨λΈμ μΆκ°νκ³ , μλ² μ½λμμ import νμ¬ μ€ν€λ§μ λ°λΌ Document λ₯Ό μ½κ±°λ μΈ μ μμ΅λλ€.
-
Production νκ²½μ μν ν΄λ¬μ€ν°: ProductionCluster
μ€μ μ΄μμ€μΈ μλ²μλ ProductionCluster λ₯Ό μ¬μ©ν©λλ€.
-
Development νκ²½μ μν ν΄λ¬μ€ν°: DevelopmentCluster
κ°λ° μ€μΈ μλ²μλ DevelopmentCluster λ₯Ό μ¬μ©ν©λλ€.
-
mongoose μν¬νΈ λ° DB μ°κ²°
// CommonJS λ°©μ const mongoose = require('mongoose'); // (1) // ES Module λ°©μ // package.json μ "type": "module" λͺ μ import mongoose from 'mongoose' // (2) // mongoose λ₯Ό μ΄μ©ν΄ DB μ μ°κ²° mongoose.connect("MongoDB Atlasμ DB μ£Όμ");
-
컬λ μ μ μ€ν€λ§ μ€μ
// Users.js import mongoose from 'mongoose'; const { Schema, model } = mongoose; const usersSchema = new Schema({ name: { type: String, required: true, maxlength: 3, }, gender: { type: String, required: true, maxlength: 2, }, email: { type: String, // required: λλ½ νλ©΄ μλλ νλ required: true, maxlength: 50 }, password: { type: String, required: true, }, createdAt: { type: Date, default: () => Date.now(), // immutable: 첫 ν λΉ μ΄ν μμ λΆκ°λ₯ν νλ immutable: true, }, updatedAt: Date, }); // save λ©μλλ₯Ό μ΄μ©νμ λ μλμΌλ‘ updatedAt νλλ₯Ό νμ¬ λ μ§λ‘ κ°±μ νλ λ―Έλ€μ¨μ΄ usersSchema.pre('save', function(next) { this.updatedAt = Date.now(); next(); }); // μΈλΆμμ import νμ λ μ¬μ©ν μ μλ λͺ¨λΈμ΄λ©°, // User λ‘ μ κ·Όμ΄ μ΄ μ€ν€λ§μ μ κ·Όμ΄ κ°λ₯ν¨. const Users = model('Users', usersSchema); export default Users;
-
DB μ ν΅μ
// Document μμ± λ° μ μ₯ // 1λ² λ°©λ²: μΈμ€ν΄μ€ μμ± ν save() const user = new User({ email: 'test@test.com' }); await user.save(); // 2λ² λ°©λ²: μΈμ€ν΄μ€ μμ± λ° μ μ₯μ νκΊΌλ²μ μνν΄μ£Όλ create() const user = await User.create({ email: 'test@test.com' }) // // Update (κ°±μ ) // λ°©λ²: . μΌλ‘ νλλ₯Ό μ§μ μ°Έμ‘°ν΄μ κ° μμ ν save() user.email = "test@test.com" await user.save(); // Find (μ‘°ν) // 1λ² λ°©λ²: findOne(), findMany() const user = await User.findOne({ name: "λΉλ₯΄μΈ " }) const user = await User.findMany({ name: ["그리λ§λ", "μν¬"] }) // 2λ² λ°©λ²: findById() const user = await User.findById("ID λ²νΈ").exec(); // 3λ² λ°©λ²: .where().equals().select() // where μ νλλ₯Ό νν°λ§, select λ 보μ¬μ€ νλ(projection)λ₯Ό κ²°μ const user = await User.where("email").eqauls("test@test.com").select("name"); // Delete (μμ ) // λ°©λ²: deleteOne(), deleteMany() const user = await User.deleteMany({ email: ["test@test.com", "test2@test.com"] });
-
JSON κ°μ²΄ μ²λ¦¬, CORS μ¬μ μμ² μ²λ¦¬λ₯Ό μν λ―Έλ€μ¨μ΄ μ€μ
- JSON κ°μ²΄ μ²λ¦¬: μλ°μ€ν¬λ¦½νΈλ JSON κ°μ²΄λ‘ ν΄λΌμ΄μΈνΈμ μλ²κ° ν΅μ . μλ₯Ό λ€μ΄,
fetch
λλaxios
λ₯Ό μ΄μ©ν μμ²μ μ λΆ JSON κ°μ²΄μ΄λ©°, μ΄λ₯Ό νμ±νμ¬ μλ°μ€ν¬λ¦½νΈ κ°μ²΄λ‘ λ³νν΄μ€ λ―Έλ€μ¨μ΄λ₯Ό μ€μ - CORS μ¬μ μμ² μ²λ¦¬: ν΄λΌμ΄μΈνΈλ μλ²λ‘ μ€μ μμ²μ 보λ΄κΈ° μ΄μ CORS μ¬μ μμ²μ 보λ. μλ²κ° μ΄ μμ²μ νμ©ν΄μΌ ν΄λΌμ΄μΈνΈκ° μ€μ μμ²μ λ³΄λΌ μ μμΌλ―λ‘, CORS μ¬μ μμ²μ νμ©νλλ‘ λ―Έλ€μ¨μ΄λ₯Ό μ€μ
// express.json() λ―Έλ€μ¨μ΄λ₯Ό ν΅ν΄ JSON νμμ μμ² λ³Έλ¬Έμ΄ μμμ νμ±λ¨ app.use(express.json()) import cors from 'cors'; // νμ©ν CORS μ ν€λ, λ©μλ, origin κΉμ§ μ§μ λͺ μν μλ μμΌλ, // μ΄λ κ² μ€μ νλ©΄ λͺ¨λ CORS μ¬μ μμ²μ νμ©ν¨. app.use(cors()) // ν΄λΌμ΄μΈνΈκ° 보λ΄λ μ¬μ μμ²μ OPTION λ©μλμ΄λ©°, // μ΄λ κ² νλ©΄ μλ²μ μ‘΄μ¬νλ λͺ¨λ κ²½λ‘μ λνμ¬ CORS κ° νμ©λ¨ app.options('*', cors());
- JSON κ°μ²΄ μ²λ¦¬: μλ°μ€ν¬λ¦½νΈλ JSON κ°μ²΄λ‘ ν΄λΌμ΄μΈνΈμ μλ²κ° ν΅μ . μλ₯Ό λ€μ΄,
-
λ‘κ·ΈμΈ κΈ°λ₯μ ν΄λΌμ΄μΈνΈλ‘λΆν° μ΄λ©μΌκ³Ό ν¨μ€μλλ₯Ό JSON κ°μ²΄λ‘ λ°μμ, λ―Έλ€μ¨μ΄λ₯Ό ν΅ν΄ νμ±νκ³ , κ°μ²΄μ μ΄λ©μΌ νλμ κ°μ DB μμ μ‘°ννμ¬ μΌμΉνλ μ΄λ©μΌμ΄ μλμ§ νμΈνκ³ , ν¨μ€μλλ μΌμΉνλμ§ νμΈν¨. ν¨μ€μλλ
bcrypt.compare()
ν¨μλ₯Ό μ΄μ©ν΄ μ λ ₯ λ°μ νλ¬Έ ν¨μ€μλλ₯Ό ν΄μνμ¬ DB μ μ μ₯λ ν΄μλ ν¨μ€μλμ λΉκ΅λ₯Ό μνν¨. -
ν΄λΌμ΄μΈνΈλ axios μ POST μμ²
const response = await axios.post( "URL/api/signin", sendData );
-
μλ²λ express μ POST μλ΅
app.post('/api/signin', async (req, res) => { const { email, password } = req.body; try { const user = await User.findOne({ email }); if (!user) { return res.status(401).json({status: 401, message: 'μ΄λ©μΌ νΉμ ν¨μ€μλκ° μΌμΉνμ§ μμ΅λλ€.'}); } const isMatch = await bcrypt.compare(password, user.password); if (!isMatch) { return res.status(401).json({status: 401, message: 'μ΄λ©μΌ νΉμ ν¨μ€μλκ° μΌμΉνμ§ μμ΅λλ€.'}); } return res.status(200).json({ status: 200, message: 'λ‘κ·ΈμΈ μ±κ³΅' }); } catch (err) { return res.status(500).json({ status: 500, message: 'Server error'}); } });
-
ν΄λΌμ΄μΈνΈλ‘λΆν° νμκ°μ νΌμ μ λ ₯λ κ°λ€μ΄ μ μ₯λ JSON κ°μ²΄λ₯Ό λ겨λ°μ, μ΄λ©μΌμ΄ μ€λ³΅λλμ§ κ²μ¬νκ³ , μ€λ³΅λμ§ μμμΌλ©΄ ν¨μ€μλλ₯Ό ν΄μνν λ€ DB μ κ³μ μ μμ±ν¨
-
ν΄λΌμ΄μΈνΈλ axios μ POST μμ²
const response = await axios.post( "URL/api/signup", sendData );
-
μλ²λ express μ POST μλ΅
app.post('/api/signup', async (req, res) => { const { name, gender, email, password } = req.body; try { const user = await Users.findOne({ email }); if (user) { return res.status(409).json({status:409, message: 'μ€λ³΅λ μ΄λ©μΌ'}); } // bcrypt.hash λ₯Ό ν΅ν΄ μ λ¬λ°μ ν¨μ€μλλ₯Ό ν΄μνν¨ // λλ²μ§Έ 맀κ°μΈμμΈ μ«μλ ν΄μ λ 벨μ΄λ©°, // ν΄μ λ 벨μ λμΌ μλ‘ μ²λ¦¬ μλλ λλ €μ§μ§λ§ κ·Έλ§νΌ 볡μ‘ν ν΄μν const hashedPassword = await bcrypt.hash(password, 10); await Users.create({ name: name, gender: gender, email: email, password: hashedPassword, }) res.status(201).send('κ³μ μμ± μ±κ³΅'); } catch (error) { res.status(500).send('κ³μ μμ± μ€ μ€λ₯ λ°μ'); } });
- Heroku κ³μ μμ±
- Heroku CLI μ€μΉ
- Heroku μ ν리μΌμ΄μ μμ±
- μλ°©μ μ°¨μμΌλ‘ package.json μ dependencies λ₯Ό
npm install
λ‘ μ λΆ μ€μΉ
-
Heroku νκ²½ λ³μμ MongoDB Atlas μ Connect μ£Όμλ₯Ό λ±λ‘νκ³ ,
mongoose.connect(process.env.MONGODB_URI);
μ κ°μ΄ νκ²½ λ³μλ₯Ό μ¬μ©νμ¬ DBμ μ°κ²° -
μλ²λ₯Ό μ΄ λλ Heroku μ νκ²½ λ³μμ λ±λ‘λ ν¬νΈ λ²νΈλ₯Ό μ΄μ©
app.listen(process.env.PORT, () β {});
-
package.json μ
βscriptsβ
μΉμ μβstartβ: βnode index.jsβ
μΆκ° -
Procfile νμΌ μμ±
- Heroku λ Procfile μ μ¬μ©νμ¬ μ ν리μΌμ΄μ μ μμν¨
- μ 체 νλ‘μ νΈμ μ΅μμ λλ ν°λ¦¬μ Procfile μ νμ₯μ μμ΄ μμ±νκ³ , μ€νν λͺ λ Ήμ μΆκ°
// Procfile web: node index.js
- Heroku νΈμ€ν μλΉμ€μ IP μ μ κ·Όμ νμ©ν΄μΌ νλλ°, Heroku λ μ λ£ λ²μ μ μ¬μ©νμ§ μμΌλ©΄ λμ μΈ IP μ£Όμλ₯Ό ν λΉνκΈ° λλ¬Έμ μ 체 μ κ·Όμ νμ©νλλ‘ μ€μ
- Heroku μ Deploy λ₯Ό κ°μννκΈ° μν΄, Github 리ν¬μ μλ² μ½λλ₯Ό μ λΆ μ λ‘λνκ³ Heroku μμ Github μ 리ν¬λ₯Ό μ΄μ©ν΄ μλ²λ₯Ό νΈμ€ν νλλ‘ μ€μ
heroku ps:scale web=1
μ€μ νμ¬ μλ² μ€νheroku ps:scale web=0
μλ² μ’ λ£heroku ps:restart
μλ² μ¬μμheroku logs --tail
μλ² λ‘κ·Έ νμΈ