이전 포스트에서 context api를 통해 충분히 깔끔한 코드로 리팩토링 했지만,
youtube.js
와 fakeYoutube.js
에서의 코드 중복은 어떻게 해결할 수 있을까?
방법은, DI(Dependency Injection)을 하는 것이다!
실제 api를 호출하는 client, mock data를 호출하는 client를 각각 따로 만들어서 각각 다른 client를 사용하는 youtube class로 만들어주면 된다.
우선 youtube.js를 복사해서 youtubeClient.js로 바꿔주고, fakeYoutube.js를 복사해서 fakeYoutubeClient.js로 바꿔준다.
그럼 client가 두개 생성되는 것이다.
이제 youtube.js에서 client를 내부적으로 만드는 것이 아니라, 외부로부터 받아오게 한다. 이 말은 즉 필요한 dependency를 주입 받는다는 의미이다. 그리고 이것이 바로 DI!
// youtube.js
export default class Youtube {
constructor(apiClient) {
this.apiClient = apiClient;
}
async search(keyword) {
return keyword ? this.#searchByKeyword(keyword) : this.#mostPopular();
}
async #searchByKeyword(keyword) {
return this.apiClient
.search({
params: {
part: "snippet",
maxResults: 25,
type: "video",
q: keyword,
},
})
.then((res) => res.data.items)
.then((items) => items.map((item) => ({ ...item, id: item.id.videoId })));
}
async #mostPopular() {
return this.apiClient
.videos({
params: {
part: "snippet",
maxResults: 25,
chart: "mostPopular",
regionCode: "KR",
},
})
.then((res) => res.data.items);
}
}
이렇게 기존의 코드를 수정해준다!
// youtubeClient.js
import axios from "axios";
export default class YoutubeClient {
constructor() {
this.httpClient = axios.create({
baseURL: "https://www.googleapis.com/youtube/v3",
params: { key: process.env.REACT_APP_API_KEY },
});
}
async search(params) {
return this.httpClient.get("search", params);
}
async videos(params) {
return this.httpClient.get("videos", params);
}
}
이렇게 params
를 전달받으면 this.httpClient
에 get
요청을 해주고, search
인지 videos
인지에 따라 key
를 붙여주고 전달받은 params
를 전달해서 axios
를 사용하도록 만든다.
fakeYoutubeClient.js
도 같은 방식으로 만든다.
// fakeYoutubeClient.js
import axios from "axios";
export default class FakeYoutubeClient {
async search() {
return axios.get("/data/search.json");
}
async videos() {
return axios.get("/data/popular.json");
}
}
fake에서는 constructor
가 필요없고 search
인지 videos
인지에 따라 json
파일만 get
하면 된다.
마지막으로 context파일에서
// YoutubeApiContext.jsx
const client = new FakeYoutubeClient();
// const client = new YoutubeClient();
const youtube = new Youtube(client);
client 인스턴스를 각각 만들어서 상황에 맞게 사용해주면 된다!
이전 방법까진 이해가 어느정도 됐는데 의존성 주입이라는 개념이 더해지니 아직까진 생소하게 느껴진다..ㅠ 개념에 대해서 더 공부 해야겠다..!