똑같은 삽질은 2번 하지 말자

Vue Web API 디자인 패턴 (Repository Pattern) ver.2 본문

카테고리 없음

Vue Web API 디자인 패턴 (Repository Pattern) ver.2

곽빵 2022. 6. 12. 16:38

Repository Pattren 이란?

비지니스 로직과 API로 데이터를 취득하는 부분을 분리 시키기 위한 디자인 패턴이다.

그리고 서버와의 통신(api request)을 하기위해 개발할 때 고민해야 할 사항들을 해결해 줄 수 있다.

  • api 재사용? 매번 URL을 다시 적어야 하나? 
  • 엔드포인트가 바뀌었을 때는 어떻게 됩니까?
  • 다른 프로젝트에서 API 호출 처리를 재사용하고 싶은 경우는 어떻게 됩니까?
  • 코드를 리팩터하거나 Vux의 actions로 이동하는 경우는 어떻게 됩니까?
  • 여러 개의 리소스가 있는데, 네 개의 다른 엔드포인트를 정의해야 합니까?
  • 테스트를 mock의 엔드포인트를 어떻게 다룰 수 있습니까?

기존에 썼던 repository pattern에서 조금 더 수정해서 더 좋은 pratice가 나올 수 있는 방법을 적어보고자 한다.

 

 

repositories/posts/index.ts

posts의 Repository를 작성한다($axios는 나중에 plugin에서 주입받을것이다.)

import { NuxtAxiosInstance } from '@nuxtjs/axios';

const resource = '/posts';

export const PostsRepository = ($axios: NuxtAxiosInstance) => ({
	get() {
		return $axios.get(`${resource}?lastId=1&limit=10`);
	},
});

 

 

 

repositories/index.ts

위에서 작성한 repo를 plugins에서 쉽게 주입받기 위해서 Factory를 작성해준다.

import { PostsRepository } from './posts';

export interface Repositories {
	posts: typeof PostsRepository;
}

const repositories: Repositories = {
	posts: PostsRepository,
};

export const RepositoryFactory = {
	get: (key: keyof Repositories) => repositories[key],
};

 

plugins/axios.ts

이번 주제에서 조금 벗어나지만 axios의 기본설정은 이 플러그인에서 작성하면 좋을꺼 같다.

import { Plugin } from '@nuxt/types';

const baseURL = 'http://localhost:5000';

const initAxios: Plugin = ({ $axios }) => {
	$axios.setBaseURL(baseURL);

	$axios.onRequest(config => {
		console.log(config);
	});

	$axios.onResponse(config => {
		console.log(config);
	});

	$axios.onError(e => {
		console.log(e.response);
	});
};

export default initAxios;

plugins/repositories.ts

커스텀 플러그인이기 때문에 type을 declare merge로 정의해주고

해당하는 도메인의 repositories가 불리는 시점에서 repo를 생성해서 반환해주는 플러그인이다.

import { Plugin } from '@nuxt/types';

import { RepositoryFactory, Repositories } from '@/repositories';

declare module '@nuxt/types' {
	interface NuxtAppOptions {
		// root or this 부분
		$repositories: Repositories;
	}
	interface Context {
		// context 부분
		$repositories: Repositories;
	}
}
const initRepositories: Plugin = ({ $axios }, inject) => {
	const repositories = (name: keyof Repositories) => {
		return RepositoryFactory.get(name)($axios);
	};

	inject('repositories', repositories);
};

export default initRepositories;

nuxt.config.js

export default {
	...
	// Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins
	plugins: ['~/plugins/repositories', '~/plugins/axios'],
	
	// axios
	modules: ['@nuxtjs/axios'],
    
	...
};

 

usage

components/sample.vue

export default defineComponent({
  setup() {
    const { $repositories } = useContext()
    onMounted(async () => {
      const result = await $repositories('posts').get()
      console.log(result)
    })
  },
})

store/action.js

// Test
export const actions = {
  async get_selections({ commit }) {
    const res = await this.$repositories('posts').get()
    console.log('action', res)
  },
}

 

소감

또또, store에서 쓸 때 타입이 문제가 될꺼 같다.

vuex-module-decorator를 쓰는 사람들에게는 이전의 방법이 조금더 쉽게 타입스크립트를 쓸 수 있지 않을까 라는 생각이 든다.

https://heewon26.tistory.com/343

 

Vue Web API 디자인 패턴 (Repository Pattern)

Repository Pattren 이란? 비지니스 로직과 API로 데이터를 취득하는 부분을 분리 시키기 위한 디자인 패턴이다. 그리고 서버와의 통신(api request)을 하기위해 개발할 때 고민해야 할 사항들을 해결해

heewon26.tistory.com

 

참고한 곳

https://medium.com/js-dojo/consuming-apis-in-nuxt-using-the-repository-pattern-8a13ea57d520

Comments