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까지 마쳤다. ^ㅁ^