firebase는 서버(backend)의 역할을 대신 수행해주어 serverless를 가능하게 해주는 유용한 application입니다. 그런 firebase에 crud를 수행하기위해 어떤 api를 요청해야 하는지를 다뤄보겠습니다.
문서에 유의미한 ID를 두지 않고 Cloud Firestore에서 자동으로 ID를 생성하도록 하는 것이 편리할 수도 있습니다. 아래와 같은 방식으로 add()를 호출합니다.
// firebase api 문서의 예제 코드
// Add a new document with a generated id.
db.collection("cities").add({
name: "Tokyo",
country: "Japan"
})
.then((docRef) => {
console.log("Document written with ID: ", docRef.id);
})
.catch((error) => {
console.error("Error adding document: ", error);
});
const onSubmit = async (e) => {
e.preventDefault();
await dbService.collection('messages').add({
text: message,
createdAt: Date.now(),
creatorId: userObj.uid, // userObj: props로 넘겨준 login한 user 정보
});
setMessage('');
};
문서를 수신 대기할 수 있는 방법으로 사용자가 제공하는 callback이 최초 호출 시 단일 문서의 현재 콘텐츠로 문서 스냅샷이 즉시 생성됩니다. 콘텐츠가 변경될 때마다 callback이 호출되어 문서 스냅샷을 업데이트 합니다.
// firebase api 문서의 예제 코드
db.collection("cities").doc("SF")
.onSnapshot((doc) => {
console.log("Current data: ", doc.data());
});
쿼리 조회시 default로
문서 ID
에 따라 오름차순으로 검색합니다. orderBy()를 사옹하면 데이터의 정렬 순서를 지정하고limit()
를 사용하여 검색된 문서 수를 제한할 수 있습니다.
// firebase api 문서의 예제 코드
citiesRef.orderBy("name").limit(3);
useEffect(() => {
dbService // dbService = firebase.firestore();
.collection('messages')
.orderBy('createdAt', 'desc') // 생성일(createdAt) 역순으로 order
.onSnapshot((snapshot) => {
const messageArray = snapshot.docs.map((doc) => ({
id: doc.id,
...doc.data(),
}));
setMessages(messageArray);
});
}, []);
문서의 일부
필드
를 업데이트를 하기위해 update() 메서드를 사용합니다.
// firebase api 문서의 예제 코드
var washingtonRef = db.collection("cities").doc("DC");
// Set the "capital" field of the city 'DC'
return washingtonRef.update({
capital: true
})
.then(() => {
console.log("Document successfully updated!");
})
.catch((error) => {
// The document probably doesn't exist.
console.error("Error updating document: ", error);
});
// 작성 코드
const [isEditing, setIsEditing] = useState(false);
const [newMessage, setNewMessage] = useState(messageObj.text);
const toggleIsEditing = () => setIsEditing((prev) => !prev);
const onEditChange = (e) => {
const { value } = e.target;
setNewMessage(value);
};
const onEditMessageSubmit = async (e) => {
e.preventDefault();
await dbService.doc(`messages/${messageObj.id}`).update({
text: newMessage,
});
setIsEditing(false);
};
문서를 삭제하기위해 delete() 메서드를 사용합니다.
// firebase api 문서의 예제 코드
db.collection("cities").doc("DC").delete().then(() => {
console.log("Document successfully deleted!");
}).catch((error) => {
console.error("Error removing document: ", error);
});
// 작성 코드
const [isEditing, setIsEditing] = useState(false);
const [newMessage, setNewMessage] = useState(messageObj.text);
const toggleIsEditing = () => setIsEditing((prev) => !prev);
const onEditChange = (e) => {
const { value } = e.target;
setNewMessage(value);
};
const onDeleteClick = async () => {
const ok = window.confirm('메세지를 삭제하시겠습니까?');
if (ok) {
await dbService.collection('messages').doc(`${messageObj.id}`).delete();
}
};
Firestore 에는
컬렉션
, 컬렉션 그룹에서 검색할문서
를 지정할 수 있는 강력한 쿼리 기능을 제공하고 있습니다. ex)get()
,addSnapshotListener()
쿼리객체
를 만든 후 get()함수를 사용하여 결과를 검색합니다.
where() 메서드는필터링할 필드
,비교 연산자
,값
의 3가지 매개변수를 사용합니다.
// firebase api 문서의 예제 코드
db.collection("cities").where("capital", "==", true)
.get()
.then((querySnapshot) => {
querySnapshot.forEach((doc) => {
// doc.data() is never undefined for query doc snapshots
console.log(doc.id, " => ", doc.data());
});
})
.catch((error) => {
console.log("Error getting documents: ", error);
});
const getMyMessages = async () => {
await dbService
.collection('messages')
.where('creatorId', '==', userObj.uid)
.orderBy('createdAt')
.get();
};
Cloud Sotrage에 파일을 업로드하기위해 먼저
파일 이름
,파일 전체경로
를 가르키는 참조를 만듭니다.
// firebase api 문서의 예제 코드
// Create a root reference
var storageRef = firebase.storage().ref();
// Create a reference to 'images/mountains.jpg'
var mountainImagesRef = storageRef.child('images/mountains.jpg');
Blob
,File
또는Unit8Array
를 사용할 수 없으면putString()
메서드를 사용하여원시 문자열
,base64
,base64url
또는 data_url로 인코딩된 문자열을 Cloud Sotrage에 추가할 수 있습니다.
// firebase api 문서의 예제 코드
// Raw string is the default if no format is provided
var message = 'This is my message.';
ref.putString(message).then(function(snapshot) {
console.log('Uploaded a raw string!');
});
// Data URL string
var message = 'data:text/plain;base64,5b6p5Y+344GX44G+44blahblah';
ref.putString(message, 'data_url').then(function(snapshot) {
console.log('Uploaded a data_url string!');
});
스토리지 참조에 대하여
getDonwloadURL()
메서드를 호출하여 파일의 다운로드 URL을 가져옵니다.
// firebase api 문서의 예제 코드
// Create a reference to the file we want to download
var starsRef = storageRef.child('images/stars.jpg');
// Get the download URL
starsRef.getDownloadURL().then(function(url) {
// Insert url into an <img> tag to "download"
}).catch(function(error) {
...
}
});
const [attachment, setAttachment] = useState('');
const onFileChange = (e) => {
const { files } = e.target;
const theFile = files[0];
// FileReader의 Instance 생성
const reader = new FileReader();
// eventListener
reader.onloadend = (e) => {
const { result } = e.currentTarget;
// attachment state를 data_url형식의 string값으로 업데이트
setAttachment(result);
};
reader.readAsDataURL(theFile);
};
const onSubmit = async (e) => {
e.preventDefault();
let attachmentUrl = '';
// 사진 첨부를 안할 수도 있기 때문에 조건문
if (attachment !== '') {
// uuid library 사용
const fileRef = storageService.ref().child(`${userObj.uid}/${uuidv4()}`);
// putString method로 file 업로드
const response = await fileRef.putString(attachment, 'data_url');
// getDownloadURL method로 file 다운로드
attachmentUrl = await response.ref.getDownloadURL();
}
const messageObj = {
text: message,
createdAt: Date.now(),
creatorId: userObj.uid,
attachmentUrl,
};
await dbService.collection('messages').add(messageObj);
setMessage('');
setAttachment('');
};
파일을 삭제하기위해 파일을 가르키는
참조(reference doc link)
를 먼저 만듭니다. delete()를 사용하여 파일을 삭제하며 정상적으로 처리 되었을 경우Promise
가 반환됩니다.
- refFromURL - Returns a reference for the given absolute URL.
- refFromURL (url : string) - Reference
// firebase api 문서의 예제 코드
// Create a reference to the file to delete
var desertRef = storageRef.child('images/desert.jpg');
// Delete the file
desertRef.delete().then(function() {
// File deleted successfully
}).catch(function(error) {
// Uh-oh, an error occurred!
});
const onDeleteClick = async () => {
const imgUrl = messageObj.attachmentUrl;
const ok = window.confirm('메세지를 삭제하시겠습니까?');
if (ok) {
newMessage &&
(await dbService
.collection('messages')
.doc(`${messageObj.id}`)
.delete());
imgUrl &&
(await storageService.refFromURL(messageObj.attachmentUrl).delete());
}
};
firebase 미니 프로젝트를 만들기 전에 여러가지 기능들에 대하여 정리해 보았습니다. 개인적인 생각으로 아직까진 serverLess로서 완벽하게 구현이 가능하진 않겠지만 어느정도 소규모 프로젝트나 crud가 메인인 프로젝트인 경우에는 firebase만으로 충분히 좋은 서비스를 구현 가능할 것 같습니다.