Node.js 프로젝트 생성
$ npm init -y
패키지 설치
$ npm install express firebase dotenv cors
Express 프레임워크, Firebase 패키지, dotenv 라이브러리, cors 설치.
$ npm install nodemon --save-dev
PM2와 비슷하게 파일 변동 시 Node.js 서버를 자동으로 재시작해주는 nodemon 설치.
--save-dev 옵션은 설치 후 devDependencies에 추가하는 옵션.
"scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "nodemon index.js" },
설치 후 package.json
파일의 "scripts"
부분에 "start": "nodemon index.js"
를 추가해 주자.
나중에 npm start
명령어만으로 nodemon을 실행시킬 수 있도록 하기 위함.
아니면 그냥 pm2 써도 된다.
$ npm install body-parser
post 방식의 request 데이터에서 body에 담긴 파라미터들을 쉽게 추출할 수 있도록 해주는 패키지.
** 주의 **
firebase 패키지를 사용하면 서버가 안 켜지는 경우가 있다. (나는 그랬다.)
그러므로.. firebase-admin 패키지를 이용하도록 하겠음..
$ npm install firebase-admin
파일 구조 생성
프로젝트 파일 아래에
.env
config.js
db.js
index.js
파일 생성.
controllers
models
routes
폴더 생성.
물론 이름은 달라도 상관없으나 아래 코드는 알아서 수정하면서 따라오시면 됩니다 :D
환경 변수(SDK), Firebase DB 생성
- Firebase 프로젝트 생성.
- Web-app 추가(등록).
- Web-app Register 과정에서 Add Firebase SDK 부분을 확인.
놓치고 지나갔다면
프로젝트 설정 - 일반 - 내 앱 에서 다시 확인할 수 있다.
.env
파일에 입력.
#express server config PORT=8080 HOST=localhost HOST_URL=http://localhost:8080 #firebase database config /* 여기에 Add Firebase SDK 부분에 있는 것들을 복사하여 입력 */ API_KEY= AUTH_DOMAIN= DATABASE_URL= PROJECT_ID= STORAGE_BUCKET= MESSAGING_SENDER_ID= APP_ID=
apiKey: "AIzaenf6asdf3fJSDF734rsoJasdjkfhYY", 같이 되어 있으면
API_KEY=AIzaenf6asdf3fJSDF734rsoJasdjkfhYY
처럼 입력해주면 됨. 쉼표 없어도 됩니다~
config.js
파일에 입력.
"use strict"; const dotenv = require("dotenv"); const assert = require("assert"); dotenv.config(); const { PORT, HOST, HOST_URL, API_KEY, AUTH_DOMAIN, DATABASE_URL, PROJECT_ID, STORAGE_BUCKET, MESSAGING_SENDER_ID, APP_ID, } = process.env; assert(PORT, "PORT is required"); assert(HOST, "HOST is required"); module.exports = { port: PORT, host: HOST, url: HOST_URL, firebaseConfig: { apiKey: API_KEY, authDomain: AUTH_DOMAIN, databaseURL: DATABASE_URL, projectId: PROJECT_ID, storageBucket: STORAGE_BUCKET, messagingSenderId: MESSAGING_SENDER_ID, appId: APP_ID, }, };
dotenv
로 .env
파일에 입력한 환경변수를 관리해주는 것이다.
assert
는 Node.js 테스트용 모듈로, 정상적으로 작동하는지 확인해 주는 역할.
- Firestore 데이터베이스를 미리 생성해 줍시다.
Express.js 서버 생성
index.js
파일에 입력.
"use strict"; const express = require("express"); const cors = require("cors"); const bodyParser = require("body-parser"); const config = require("./config"); const app = express(); app.use(express.json()); app.use(cors()); app.use(bodyParser.json()); app.listen(config.port, () => console.log("App is Listening on url http://localhost:" + config.port) );
Firebase Firestore DB와 연결
db.js
파일에 입력.
const firebase = require("firebase-admin"); const config = require("./config"); const db = firebase.initializeApp(config.firebaseConfig); module.exports = db;
line 1 에서 firebase-admin을 사용했다.
const firebase = require("firebase");
처럼 firebase 패키지를 이용해도 되지만,에러가 날 시에는 firebase-admin으로 시도해 보길.
CRUD
Create
models
폴더에user.js
생성 후 입력.
class User { constructor(name, age) { this.name = name; this.age = age; } }
user 객체 생성 틀.
controllers
폴더에userController.js
생성 후 입력.
"use strict"; const firebase = require("../db"); const User = require("../models/user"); const firestore = firebase.firestore(); const addUser = async (req, res, next) => { try { const data = req.body; const user = await firestore.collection("CRUD_TEST").doc().set(data); res.send("Record saved successfully"); } catch (error) { res.status(400).send(error.message); } }; module.exports = { addUser, };
routes
폴더에user-routes.js
생성 후 입력
const express = require("express"); const { addUser } = require("../controllers/userController"); const router = express.Router(); router.post("/user", addUser); module.exports = { routes: route };
index.js
에 추가 입력. (line 6, line 14)
"use strict"; const express = require("express"); const cors = require("cors"); const bodyParser = require("body-parser"); const config = require("./config"); const userRoutes = require("./routes/user-routes"); const app = express(); app.use(express.json()); app.use(cors()); app.use(bodyParser.json()); app.use("/api", userRoutes.routes); app.listen(config.port, () => console.log("App is Listening on url http://localhost:" + config.port) );
- nodemon 또는 pm2로 서버를 켜준다.
nodemon이라면 아까 설정한 대로
$ npm start
pm2라면
$ pm2 start index.js --watch
- postman으로 post 데이터 날려보기.
Postman 사용법은 알아서 찾아서 해보세용.
Post 형식으로 해서 URL에 http://localhost:8080/api/user
입력 후
Body - raw 로 설정하고 JSON 형식으로 설정한 후에
{ "name": "Kim", "age": "50" }
대충 이런 데이터 한 번 보내봅시다. 물론 형식은 models
의 user.js
에서 정한대로..^^
여기서 오류가 난다면
데이터를 전송했는데 Record saved successfully가 안 뜨고 오류가 난다면 다음을 시도해 보자. 필자는 이렇게 성공함.
- firebase-service-key를 가져와서 파일에 JSON 형태로 저장.
- db.js 수정 ( line 4 추가, firebase.initializeApp() 수정. )
const firebase = require("firebase-admin"); const config = require("./config"); const serviceAccount = require("./firebase_service_key.json"); const db = firebase.initializeApp({ credential: firebase.credential.cert(serviceAccount), databaseURL: "https://(이름 알아서 찾아서 넣어보삼)-default-rtdb.firebaseio.com", }); module.exports = db;
- postman으로 post데이터 날렸을 때 밑에 Record saved successfully 가 뜨고, Firestore DB 에서 추가된 것을 확인하면 성공!!
Read
userController.js
에 Read하는 함수 추가(getAllUser
), 그 함수 exports로 내보내기
( line 17~34, line 38 )
"use strict"; const firebase = require("../db"); const User = require("../models/user"); const firestore = firebase.firestore(); const addUser = async (req, res, next) => { try { const data = req.body; await firestore.collection("CRUD_TEST").doc().set(data); res.send("Record saved successfully"); } catch (error) { res.status(400).send(error.message); } }; const getAllUser = async (req, res, next) => { try { const snapshot = await firestore.collection("CRUD_TEST").get(); const data = snapshot; const usersArray = []; if (data.empty) { res.status(404).send("No User Record found"); } else { snapshot.forEach((doc) => { const user_data = new User(doc.data().name, doc.data().age); usersArray.push(user_data); }); } res.send(usersArray); } catch (error) { res.status(400).send(error.message); } }; module.exports = { addUser, getAllUser, };
userController.js
에서 import해 사용할User
Class를user.js
에서 export해주기
( line 8 )
class User { constructor(name, age) { this.name = name; this.age = age; } } module.exports = User;
user-routes.js
에getAllUser
함수로 Read 할 route 설정해 주기
( line 7 )
const express = require("express"); const { addUser, getAllUser } = require("../controllers/userController"); const router = express.Router(); router.post("/user", addUser); router.get("/users", getAllUser); module.exports = { routes: router, };
- postman으로 get 요청 보내보기
http://localhost:8080/api/users 주소에 get 요청을 보내면 밑에 데이터가 쫘라락 뜰 것이다.
안 뜨면 에러메시지 보고 함수 고쳐보시길.
Update
userController.js
에 Update 함수 추가(updateUser
)
마찬가지로 module.export
에 updateUser
추가!
const updateUser = async (req, res, next) => { try { const newUserData = req.body; const userID = req.params.id; const userSnapshot = await firestore.collection("CRUD_TEST").doc(userID); const userData = await userSnapshot.get(); if (!userData.exists) { res.status(404).send("User with given ID not found"); } else { userSnapshot.update(newUserData); res.send(`Update Successfully\n Updated User ID : ${userID}\n new User Data : { name : ${req.body.name}, age : ${req.body.age} } `); } } catch (error) { res.status(400).send(error.message); } };
user-routes.js
에도 마찬가지로 route 추가. ( line 5, line 12 )
const express = require("express"); const { addUser, getAllUser, updateUser, } = require("../controllers/userController"); const router = express.Router(); router.post("/user", addUser); router.get("/users", getAllUser); router.post("/updateUser/:id", updateUser); module.exports = { routes: router, };
- postman에서 테스트! post 형식으로 데이터 보내기.
문서명은 URL에서 파라미터 형식으로 입력!
( http://localhost:8080/api/updateUser/"Document명" 처럼 )
{ "name" : "JAEWON", "age" : "500" }
같이 데이터를 입력해주고, send버튼 누르면 잘 작동하는 것을 볼 수 있다!
Delete
이제 남은 건 delete인데.. 하던 대로 똑같이 구현하면 어렵지 않게 구현할 수 있다.
userController.js
에 Delete 함수 추가(deleteUser
)
마찬가지로 밑의 module.export
에 deleteUser
추가!
const deleteUser = async (req, res, next) => { try { const userID = req.params.id; const userSnapshot = await firestore.collection("CRUD_TEST").doc(userID); const userData = await userSnapshot.get(); if (!userData.exists) { res.status(404).send("User with given ID not found"); } else { res.send(`Delete Successfully! Deleted User ID : ${userID} Deleted User Data : { name : ${userData.data().name}, age : ${userData.data().age} } `); userSnapshot.delete(); } } catch (error) { res.status(400).send(error.message); } };
user-routes.js
에도 마찬가지로 route 추가. ( line 6, line 14 )
const express = require("express"); const { addUser, getAllUser, updateUser, deleteUser, } = require("../controllers/userController"); const router = express.Router(); router.post("/user", addUser); router.get("/users", getAllUser); router.post("/updateUser/:id", updateUser); router.get("/deleteUser/:id", deleteUser); module.exports = { routes: router, };
- postman에 get 방식으로 데이터 보내보면 정상적으로 지워질 User 데이터가 출력되고, Firestore에서 지워지는 것을 확인할 수 있음.
지울 Document명(문서명)은 파라미터로 입력.
(http://localhost:8080/api/deleteUser/"문서명")
이렇게 성공적으로 Express.js로 서버를 열어 Firebase Firestore DB와 연동하고 CRUD까지 마쳤다. ^ㅁ^