π· μΈνΈλ‘
SOPT νμμ΄λΌλ©΄ λꡬλ μ°Έμ¬νκ³ μΆμ μ컀ν€!
λ°€μ μ컀ν€μ λ§μΉκ³ μ§μ λμμ μ΅λν μμν κΈ°μ΅μΌλ‘ νκΈ°λ₯Ό μμ±ν΄λ³΄λ € νλ€.
μ½λ‘λ 거리λκΈ° μ νμ΄ ν΄μ λ¨μ λ°λΌ μ΄λ² ν΄μ»€ν€μ μ 체 μ€νλΌμΈμΌλ‘ μ§νλμλ€.
μΈμ μ μ νμ΄ μμ΄μ ννΈ λ³ μ μ°©μμΌλ‘ μ μ²μ λ°μλλ° λ€ννλ μ μ²μ μ±κ³΅νλ€.
λ€μν ν μ£Όμ OB λΆλ€ κ°μ¬ν©λλ€.. π·
π» μ£Όμ

μ΄λ² 30κΈ° μ컀ν€μ μ£Όμ λ μΌμμ΄μλ€.
μλ ν¬κ΄μ μΈ μ£Όμ λΌ λ€μν μμ΄λμ΄λ€μ΄ λμ€κ² λ€λ μκ°μ νκ³ μ°λ¦¬ νμ κ³§λ°λ‘ μμ΄λ°μ΄μ μ λ€μ΄κ°λ€.
μ°λ¦¬ νμ νμ ν΄μΈ Notionμ νμ©ν΄μ μμ΄λ°μ΄μ μ μ§ννλλ°, λΈλ μΈμ€ν λ°μ νλ―μ΄ μμ λ‘κ² μμ΄λμ΄λ₯Ό μ μ΄λκ°λ©° λ°μ°νλ κ³Όμ μ κ±°μΉκ³ , μμ΄λμ΄λ₯Ό μΆλ¦¬λ μλ ΄, μ΅μ’ μ μΈ μμ΄λμ΄ νμ , λλ²¨λ‘ μμλ‘ μ§ννλ€.
λ€μν μκ²¬λ€ μ€ μ°λ¦¬ νμ μΌμ μ κ³ λ§κ³ λ―Έμν λ§μμ μμ λ‘κ² κΈ°λ‘ν μ μλ μλΉμ€λ₯Ό ꡬμνκ² λμλ€.
π«ΆπΌ μλΉμ€ μκ°

κ³ΌμΌμ λνλ΄λ λ¨μ΄μΈ fruitμ μ΄μ©ν΄ 'νΈλ¦νΈλ¦ν λ무λ₯Ό μ΄λ§€λ‘ κΎΈλ―Έλ μλΉμ€' νΈλ¦νΈλ¦ μλΉμ€λ€.
μλΉμ€μ ν΅μ¬ κΈ°λ₯ 4κ°μ§λ μ΄λ§€λ₯Ό λ§€λ¬κ³ , λ§€λ¨ μ΄λ§€λ₯Ό μννκ³ , μ΅λͺ μ μ΄λ§€λ€μ ν΅ν΄ νλ§νκ³ , 곡κ°λλ μ΄λ§€μ λ무μ λ¬Όμ μ£Όλ κ²μ΄λ€. νΈλ¦νΈλ¦ μλΉμ€μμ μ΄λ§€λ κ²μκΈμ μλ―Ένκ³ κ°μ¬νλ κΈμ κ° μ΄λ§€κ° λ§€λ¬λ¦¬κ³ μ¬κ³Όνλ κΈμ μ¬κ³Ό μ΄λ§€κ° λ§€λ¬λ¦°λ€. λ¬Όμ μ£Όλ κ²μ κΈμ κ³΅κ° νμλ₯Ό νλ€λ μλ―Έμ΄λ€.
π€ μλ² ννΈ μμ
μμ΄λμ΄κ° νμ λ ν κΈ°ν ννΈ νμλ€μ΄ ꡬ체μ μΈ μμ΄μ΄νλ μ μμ μ λ€μ΄κ°κ³ λμμ΄λ, κ°λ°μμ μν΅μ ν΅ν΄ μλΉμ€μ flowλ₯Ό νμ μ§μλ€. λλ₯Ό ν¬ν¨ν μλ²ννΈλ κ³§λ°λ‘ λ°μ΄ν°λ² μ΄μ€λ₯Ό μν 컬λ μ μ€κ³μ λ€μ΄κ°λ€. λ¬΄λ° 2μΌ 16μκ° λμ μ§νλλ μ§§μ κΈ°κ°μ ν΄μ»€ν€μ΄μκΈ° λλ¬Έμ κΈ°λ₯μ΄ κ°μν΄μ 컬λ μ μ λ κ°μ§λ‘ μΆ©λΆνλ€.
User Collection
import mongoose from "mongoose";
import { UserInfo } from "../interfaces/user/UserInfo";
const UserSchema = new mongoose.Schema({
userNickname: {
type: String,
required: true
},
userProfileImageUrl: {
type: String,
required: true
}
});
export default mongoose.model<UserInfo & mongoose.Document>("User", UserSchema);
Fruit Collection
import mongoose, { Mongoose } from "mongoose";
import { FruitInfo } from "../interfaces/fruit/FruitInfo";
const FruitSchema = new mongoose.Schema({
type: {
type: Number,
required: true
},
contents: {
type: String,
required: true
},
wateringCount: {
type: Number,
required: true
},
userId: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: "User"
},
onTree: {
type: Boolean,
required: true
}
},
{
timestamps: true
});
export default mongoose.model<FruitInfo & mongoose.Document>("Fruit", FruitSchema);
컬λ μ μ€κ³λ₯Ό λ§μΉκ³ νμν APIλ€μ νμ νλ©° ν΄λΌμ΄μΈνΈ ννΈ νμλ€μ μνν μμ μ μν΄ API λͺ μΈμλ₯Ό μμ±νκΈ° μμνλ€. λ Έμ μ μ΄μ©ν΄μ μμ±νμκ³ λͺ μΈμλ₯Ό λͺ¨λ μμ±ν νμλ ν΄λΌμ΄μΈνΈ νμκ³Ό νμλ₯Ό ν΅ν΄ μ΄λλ‘ μ§νν΄λ μ’μμ§ νμΈμ λ§μ³€λ€.

API λͺ μΈμλ Notionμ νμ©ν΄μ μμ±νκ³ end point μ μμ±ν λ΄λΆ νμ΄μ§μ λ€μ΄κ°λ©΄ κ° API λ³λ‘ νμν Request Header, Request Param, Request Query, Request Body, Response Body, Response Code λ±μ λͺ¨λ μ 리ν΄λμλ€.
API λͺ μΈμ μμ±μ λ§μΉκ³ 본격μ μΈ μ½λ©μ λ€μ΄κ°κΈ° μ , μλ² ννΈ νμκ³Ό κ°μ λ΄λΉν API, μ½λ 컨벀μ , μ»€λ° λ©μμ§ μ»¨λ²€μ , Git λΈλμΉ μ λ΅μ λν νμλ₯Ό μ§ννλ€. νμ λ°©μμ λͺ¨λ μ νκ³ λμμΌ λ§μΉ¨λ΄ μ½λ©μ μμνλ€.
π« μλ¬ λ°μκ³Ό ν΄κ²°
μμ μ΄ μμ μκ°μ μ€ν 8μλΆν° μ€μ 6μ 30λΆκΉμ§ 10μκ° 30λΆ μ λμλ€. μ΄ κ³Όμ μμ κ³¨μΉ μν μλ¬κ° λ λ² μ λ λ°μνλ€. 첫 λ²μ§Έ μλ¬λ‘ μλ² ννΈ νμκ³Ό κ±°μ 1μκ°μ λκ² λλΉνλ€.
GET /fruit/my API μμ²μ 보λ΄λ©΄ λ°μνλ λ¬Έμ μλλ° μλμ κ°μ μλ¬ λ©μμ§κ° λμλ€.
CastError: Cast to ObjectId failed for value "my" (type string) at path "_id" for model "Fruit"
at model.Query.exec (/Users/orijoon98/Desktop/Workspace/Nangman-Server/node_modules/mongoose/lib/query.js:4719:21)
at model.Query.Query.then (/Users/orijoon98/Desktop/Workspace/Nangman-Server/node_modules/mongoose/lib/query.js:4818:15)
ꡬκΈλ§λ λ§μ΄ ν΄λ³΄κ³ κ΄λ ¨λ μ½λλ₯Ό μ 체μ μΌλ‘ μ΄νΌλ©° λ¬Έμ μ μ μ°Ύμλ³΄λ € νμ§λ§ μ€ν¨νκ³ κ²°κ΅ μλ² ννΈμ₯λμκ² λμμ μμ²νλ€. μλ² ννΈμ₯λμ λμμΌλ‘ μμΈμ μκ² λμλλ° λΌμ°ν°κ° μμΈμ΄λΌλ κ²μ μκ² λμλ€.
μλ¬κ° λ¬λ λΌμ°ν° μ½λ
import { Router } from "express";
import { body } from "express-validator/check";
import { FruitController } from "../controllers";
const router: Router = Router();
router.get("/", FruitController.getFruits);
router.post(
"/",
[body("type").notEmpty(), body("contents").notEmpty()],
FruitController.createFruit
);
router.get("/my/tree", FruitController.getMyFruitsOnTree);
router.get("/:fruitId", FruitController.findFruitById);
router.get("/my", FruitController.getMyFruits);
router.put("/:fruitId/water", FruitController.putWateringCount);
export default router;
μ¬κΈ°μ router.get("/my", FruitController.getMyFruits);
μ΄ λΆλΆμΌλ‘ μμ²μ΄ λμ΄κ°κΈ° μ μ λΌμ°ν°λ μμμ μλλ‘ νμΈνλ©° λμνκΈ° λλ¬Έμ /fruit/my λ‘ λ³΄λΈ μμ²μ΄ router.get("/:fruitId", FruitController.findFruitById);
λΌμ°ν°λ‘ λΌμ°ν
λμ΄ fruitId
Paramμ my
κ° λ€μ΄κ°μ λ°μν μλ¬μλ€.
ν΄κ²°ν μ½λ
import { Router } from "express";
import { body } from "express-validator/check";
import { FruitController } from "../controllers";
const router: Router = Router();
router.get("/", FruitController.getFruits);
router.post(
"/",
[body("type").notEmpty(), body("contents").notEmpty()],
FruitController.createFruit
);
router.get("/my/tree", FruitController.getMyFruitsOnTree);
router.get("/my", FruitController.getMyFruits);
router.get("/:fruitId", FruitController.findFruitById);
router.put("/:fruitId/water", FruitController.putWateringCount);
export default router;
λ λΌμ°ν°μ μμλ₯Ό λ°κΏμ£Όλ κ² λ§μΌλ‘ μλ¬λ₯Ό ν΄κ²°ν μ μμλ€. λΌμ°ν°μ λμ λ°©μμ μ λλ‘ μ΄ν΄νκ³ μμ§ μμμ μ΄λ° λ¬Έμ λ₯Ό νμ νμ§ λͺ»νμλ€λ μκ°μ΄ λ€μκ³ κΈ°μ μ λν μ΄ν΄λ μμ μ€μνλ€λ κ±Έ λ€μ νλ² λμκΈ°κ² λμλ€.
λ λ²μ§Έ λ¬Έμ λ μ¬μν μ€μλ‘ λ°μν μλ¬μλ€. μμ μ λͺ¨λ λ§μΉ ν AWS EC2 μ λ°°ν¬νμ¬ ν μ€νΈλ₯Ό μ§ννλλ° λ‘컬 νΈμ€νΈμμ μ μμ μΌλ‘ μλνλ APIλ€μ΄ μλνμ§ μμλ€. npm, yarn λ±μ λ²μ μ λ‘컬과 λΉκ΅ν΄λ³΄κ³ λ°μ΄ν°λ² μ΄μ€λ₯Ό νμΈν΄λ³΄κ³ λΉλλ λ€μ ν΄λ³΄λ λ± λ€μν μλλ₯Ό ν΄λ³΄μλλ° λ¬Έμ λ ν΄κ²°λμ§ μμλ€. μ£Όλ³ μ¬λλ€μκ² λμμ μμ²νμ§λ§ λͺ¨λλ€ μμΈμ μ°Ύμ§λ λͺ»νλ€. λ§μ°μμ€νλ μμ€ AWS EC2μ μμ±νλ .env νμΌμ λ°μ΄ν°λ² μ΄μ€ μ κ·Ό urlμ λ€λ₯Έ κ°μ 볡μ¬νλ€λ κ²μ λ°κ²¬νκ² λμλ€. λ무λ μ¬μν μ€μμμ§λ§ κ·Έ μ€μ νλλ‘ 1μκ°μ λκ² μ λ¨Ήμ κ±Έ μκ°νλ©΄ ...π₯ μ μ μ°¨λ¦¬κ³ μ½λ©ν΄μΌκ² λ€.
π€ μκ°
λ¬΄λ° 2μΌ λμ μ§νλλ ν΄μ»€ν€μ μ΄λ²μ΄ μΈ λ²μ§Έ κ²½νμ΄μλ€. μ§λ λ λ²μ ν΄μ»€ν€ λ, λ°€ μ νμλ€κ³Ό ν¨κ» κ³ μνλ©° μλΉμ€λ₯Ό λ§λ€μ΄κ°λ κ³Όμ μ΄ μ¦κ±°μμ μ΄λ² ν΄μ»€ν€λ μ μ²νκ² λμλλ° μμλ μ¦κ±°μ λ€. SOPT λμ리 λ΄μμ μ§νν ν΄μ»€ν€μ΄μκΈ°μ μΉν μ¬λλ€λ λ§μμ λμ± λ μ¦κ²κ² νμ¬λ₯Ό μ¦κΈ΄ κ² κ°λ€.
λμμΈ ννΈ, μΉ, μ± κ°λ°μ λΆλ€κ³Ό νμ μ μ§νν΄ λ³Έ κ²½νμ΄ μμ§λ§, κΈ°ν ννΈμμ νμ κ²½νμ μ΄λ²μ΄ μ²μμ΄μλ€. κΈ°ν ννΈ νμλ€μ μμ΄λ°μ΄μ μ£Όλ, μμ΄μ΄νλ μ μμ , νμ, μ€μΌμ€μ κ΄λ¦¬νκ³ λ§λ¬΄λ¦¬ λ°νκΉμ§νλ κ³Όμ μ 보며 κΈ°ν ννΈμ μν μ λν΄μλ λ°°μΈ μ μμλ€.
λν μ§λ ν΄μ»€ν€, 곡λͺ¨μ κ²½νλ€ λͺ¨λ μλ² ννΈλ₯Ό νΌμ λ΄λΉνλ κ²½μ°κ° μ λΆμλλ° μ΄λ² ν΄μ»€ν€μ ν΅ν΄ λ€λ₯Έ μλ² νμλΆκ³Ό νμ νλ κ²½νμ ν μ μμλ€. μ½λ 컨벀μ , κΉ μ»¨λ²€μ , λΈλμΉ μ λ΅, μ΄μ κ΄λ¦¬, νλ‘μ νΈ κ΄λ¦¬, PR μΆ©λ ν΄κ²° λ± νΌμ μμ ν λλ κ²½νν΄λ³΄μ§ λͺ»ν μ λ§μ νμ νλ‘μΈμ€λ₯Ό κ²½νν΄ λ³Ό μ μμκ³ μ΄νμ λ€λ₯Έ μλ² ννΈ νμκ³Όμ νμ λ λ μ ν μ μκ² λ€λ μμ κ°μ μ»κ² λ κ³κΈ°κ° λμλ€.
κ·Έλ¦¬κ³ λͺ¨λ νμ μ΄ κ·Έλ λ― μΈμ λ κ°μ₯ μ€μν κ²μ μν΅κ³Ό λ°°λ €μλ€. μλ‘μ μ견μ κ·λ₯Ό κΈ°μΈμ΄κ³ μμ μν©μ 곡μ νλ©° λ°°λ €νλ λ§μμΌλ‘ λͺ¨λκ° ν¨κ» ν΄μΌ μμ μ΄ μ¦κ²λ€. λ΄κ° μν νμ νμλ€μ λͺ¨λ μν΅κ³Ό λ°°λ €λ₯Ό μ ν΄μ£Όμκ³ κ·Έ λλΆμ μ΄λ² 30κΈ° μ컀ν€μ μ’μ μΆμ΅μΌλ‘ λ¨μ κ² κ°λ€. π
'π€ νκ³ : Retrospect' μΉ΄ν κ³ λ¦¬μ λ€λ₯Έ κΈ
[νκ³ ] SOPT 32κΈ° APPJAM νκΈ° (0) | 2023.07.25 |
---|---|
[νκ³ ] 2023λ μλ°κΈ° λμ보기 (1) | 2023.07.03 |
2023 SSG.COM Tech Rookie : 첫λ²μ§Έ μΈν΄μ μ΅μ’ ν©κ²© νκΈ° (Backend Engineer) (2) | 2023.05.10 |
[νκ³ ] 2022λ μ λ§λ¬΄λ¦¬νλ©° λμ λμ (0) | 2023.01.01 |
[SOPT] 30κΈ° μλ²ννΈ ν©κ²© νκΈ° (0) | 2022.12.31 |