gitbook을 사용해서 api 명세서를 정리해보았다.
https://seryeongs-organization.gitbook.io/api-docs/
GET
데이터를 서버에서 받아올 때 사용하는 메소드이다.
POST
데이터를 수정 및 생성할 때 사용하는 메소드이다.
보통 request body를 담아서 보낸다.
PUT
데이터를 수정 및 생성할 때 사용한다.
post와 마찬가지로 request body에 수정 내용을 담아 보낸다.
PATCH
데이터를 수정할 때 사용하는 메소드이다.
수정 데이터를 request body에 수정 내용을 담아 보낸다.
put, post와 다르게 자원의 일부분을 업데이트한다.
DELETE
데이터를 삭제할 때 사용하는 메소드이다.
url에 index를 지정하거나 header에 pk를 넣어 지정하지만, 최근에는 테이블에 status속성을 지정하여 삭제 상태로 업데이트한다.
아이콘과 styled-component를 사용하여 직접 UI를 구현해보기 위해 사용하기 쉬운 react icons을 사용하기로 했다.
npm install react-icons --save
yarn add react-icons --save
import { IoHomeSharp } from "react-icons/io5";
<IoHomeSharp IoIosClose size="24" />
<IoHomeSharp color="#fff" />
집 모양 아이콘을 누르면 Home으로 돌아갈 수 있도록 구현했고, 컴포넌트 분리를 위해 영역만 분리 해두었다.
like를 별도의 문서로 관리해서 postId를 외래키로 사용하여 참조하는 방식으로 구현하는 것을 배웠다.
export const fetchPosts = createAsyncThunk(
`${name}/fetchPosts`,
async (_, thunkAPI) => {
try {
const postsRef = collection(db, "posts");
const querySnapshot = await getDocs(postsRef);
const postPromises = querySnapshot.docs.map(async (document) => {
const likesCollectionRef = collection(db, "likes");
const q = query(likesCollectionRef, where("postId", "==", document.id));
const likesDocSnapShot = await getDocs(q);
const likesCount = likesDocSnapShot.size;
return {
id: document.id,
likes: likesCount,
...document.data(),
};
});
const posts = await Promise.all(postPromises);
return thunkAPI.fulfillWithValue(posts);
} catch (error) {
return thunkAPI.rejectWithValue(error);
}
}
);
export const likePost = createAsyncThunk(
`${name}/likePost`,
async (postId, thunkAPI) => {
try {
const currentUserId = thunkAPI.getState().userReducer.currentUser.uid;
const likesCollectionRef = collection(db, "likes");
const q = query(
likesCollectionRef,
where("uid", "==", currentUserId),
where("postId", "==", postId)
);
const querySnapshot = await getDocs(q);
const likeDocSnapShot = querySnapshot.docs[0];
if (likeDocSnapShot?.exists()) {
await deleteDoc(likeDocSnapShot.ref);
return thunkAPI.fulfillWithValue({ postId, isLike: false });
} else {
await addDoc(likesCollectionRef, { uid: currentUserId, postId });
return thunkAPI.fulfillWithValue({ postId, isLike: true });
}
} catch (error) {
return thunkAPI.rejectWithValue(error);
}
}
);
const postSlice = createSlice({
name,
initialState,
reducers: {},
extraReducers: (builder) => {
builder
.addCase(fetchPosts.pending, (state) => {
state.loading = true;
state.error = null;
})
.addCase(fetchPosts.fulfilled, (state, action) => {
state.loading = false;
state.posts = action.payload;
})
.addCase(fetchPosts.rejected, (state, action) => {
state.loading = false;
state.error = action.error.message;
})
.addCase(addPost.pending, (state) => {
state.loading = true;
state.error = null;
})
.addCase(addPost.fulfilled, (state, action) => {
state.loading = false;
state.posts.push(action.payload);
})
.addCase(addPost.rejected, (state, action) => {
state.loading = false;
state.error = action.error.message;
})
.addCase(deletePost.pending, (state) => {
state.loading = true;
state.error = null;
})
.addCase(deletePost.fulfilled, (state, action) => {
state.loading = false;
state.posts = state.posts.filter((post) => post.id !== action.payload);
})
.addCase(deletePost.rejected, (state, action) => {
state.loading = false;
state.error = action.error.message;
})
.addCase(likePost.pending, (state) => {
state.loading = true;
state.error = null;
})
.addCase(likePost.fulfilled, (state, action) => {
state.loading = false;
state.posts = state.posts.map((post) => {
if (post.id === action.payload.postId) {
if (action.payload.isLike) {
post.likes += 1;
} else {
post.likes -= 1;
}
}
return post;
});
})
.addCase(likePost.rejected, (state, action) => {
state.loading = false;
state.error = action.error.message;
});
},
});
이번에 API명세서를 다시 작성해보면서 url을 역할에 알맞게 적용하려고 해봤다. 반복하여 작성하다보니 늘고 있는 것 같다.
firebase를 다시 사용하려니 헷갈리는 것도 있었고, thunk를 하루만 공부하고 적용하려니 정리해둔 것을 보면서 작업해야 했다.
firebase에는 query 관련해서 where문이 있다는 것도 처음 알았다.. 문서를 봤다고 생각했는데 아니였다.
firebase 문서
https://firebase.google.com/docs/firestore/query-data/get-data?hl=ko&authuser=0
where 뿐만 아니라 limit으로 검색된 문서 수를 제한할 수 있는 등 다양한 기능이 있다.