Mirage JS 및 Vue.js로 API 모의 설정

게시 됨: 2022-03-10
빠른 요약 ↬ 이 기사에서는 백엔드 API 또는 서비스에 의존하지 않고도 작동하는 완전한 JavaScript 애플리케이션을 빌드, 테스트 및 공유할 수 있는 API 모의 라이브러리인 Mirage JS를 소개합니다. 또한 프로그레시브 프런트 엔드 프레임워크인 Vue.js를 사용하여 Mirage JS를 설정하는 방법도 배우게 됩니다.

SPA와 JAMstack의 시대에는 API와 프론트엔드 개발 사이에 항상 관심사가 분리되어 있었습니다. 야생에서 찾을 수 있는 거의 모든 JavaScript 프로젝트는 웹 서비스 또는 API와 상호 작용하고 이를 인증에 사용하거나 사용자 관련 데이터를 가져옵니다.

따라서 프로젝트에서 작업 중이고 필요한 API가 백엔드 팀에서 아직 구현되지 않았거나 기능을 빠르게 테스트해야 할 때마다 다음 옵션 중 일부가 있습니다.

  • 대부분의 경우 프론트 엔드 개발자로서 가질 수 없는 실제 백엔드의 로컬 실행 버전으로 프록시할 수 있습니다.
  • 실제 요청을 주석 처리하고 모의 데이터로 바꿀 수 있습니다. (이것은 괜찮지만 프로덕션에 도달하기 위해 실행 취소해야 하고 네트워크 상태 및 대기 시간을 처리하지 못할 수 있으므로 그다지 좋지는 않습니다.)

API 조롱이란 무엇입니까?

API mocking은 실제 API의 모방 또는 시뮬레이션입니다. 이는 대부분 실제 백엔드 API에 대한 요청을 가로채기 위해 수행되지만 이 조롱은 프론트엔드에 존재합니다.

API 모의가 중요한 이유

API 조롱은 여러 면에서 상당히 중요합니다.

  1. 기능을 구축하기 전에 프로덕션 API에 의존하지 않는 매우 우수한 프론트 엔드 개발 경험을 제공합니다.
  2. 전체 프론트엔드를 공유할 수 있으며 실제 백엔드 API에 의존하지 않고 작동합니다.
점프 후 더! 아래에서 계속 읽기 ↓

Mirage JS란 무엇입니까?

Mirage JS는 5년 전에 만들어졌으며 Sam Selikoff가 2020년 1월 24일 Twitter에서 공식적으로 출시를 발표하기 전에 Ember 커뮤니티에서 거의 사용되었습니다.

Mirage JS는 이러한 API에 의존하지 않고 백엔드 API를 테스트할 때의 문제점을 해결합니다. 프로덕션 API를 조롱하여 원활한 프론트 엔드 개발 경험을 제공합니다.

Mirage JS는 Vue.js, React, Angular 및 Ember 프레임워크용 API 모의 라이브러리입니다.

Mirage JS가 더 나은 선택이 되는 이유는 무엇입니까?

API 조롱을 위한 다른 옵션(예: Axios 인터셉터, Typicode의 JSON 서버 등)이 있지만 Mirage에 대해 꽤 흥미롭게 생각하는 것은 개발 프로세스에 방해가 되지 않는다는 것입니다. 잠시 후에 Vue로 설정할 때). 가벼우면서도 강력합니다.

기본 제공되는 배터리와 함께 제공되어 타이밍 옵션으로 느린 네트워크 시뮬레이션과 같은 실제 프로덕션 API 소비 시나리오를 복제할 수 있습니다.

Mirage JS 및 Vue.js 시작하기

이제 Mirage JS가 무엇이고 프런트 엔드 개발 워크플로에 중요한 이유를 알았으므로 프로그레시브 웹 프레임워크인 Vue.js로 설정하는 방법을 살펴보겠습니다.

Green-Field(새로 설치) Vue 프로젝트 만들기

Vue CLI를 사용하여 프로젝트를 생성하고 터미널에서 실행하려는 디렉토리로 이동하여 새로운 Vue.js 프로젝트를 생성합니다.

 vue create miragejs-demo-vue

위의 명령은 이제 yarn serve 또는 cd npm run serve 중 하나를 실행하고 실행할 수 있는 새 Vue 프로젝트를 설정합니다.

# Mirage JS 설치

이제 다음 명령을 실행하여 Vue.js 프로젝트에서 Mirage JS를 개발 종속성으로 설치해 보겠습니다.

 yarn add -D miragejs

또는 NPM을 사용하는 경우 다음을 실행합니다.

 npm install --save-dev miragejs

그리고 그게 다야! 이제 Vue.js 프로젝트에 Mirage JS가 설치되었습니다.

뭔가를 조롱하자

Mirage JS가 설치된 상태에서 Vue와 통신하고 기본 todos(할 일 목록을 반환하는 API) API를 조롱하도록 구성하는 방법을 살펴보겠습니다.

서버 정의

시작하려면 Vue.js 프로젝트의 /src 디렉토리에 server.js 파일을 만들어야 합니다. 그 후 다음을 추가합니다.

 import { Server, Model } from 'miragejs' export function makeServer({ environment = "development" } = {}) { let server = new Server({ environment, models: { todo: Model, }, seeds(server) { server.create("todo", { content: "Learn Mirage JS" }) server.create("todo", { content: "Integrate With Vue.js" }) }, routes() { this.namespace = "api" this.get("/todos", schema => { return schema.todos.all() }) }, }) return server }

코드 설명

첫째, server.js 파일은 정의한 경로와 일치하는 앱에서 수행하는 모든 API 호출을 가로챌 모의(가짜) 서버의 새 인스턴스를 생성하도록 Mirage JS를 설정하는 방법입니다.

이제 위의 내용이 처음에는 압도적일 수 있다는 데 동의하지만 여기서 무슨 일이 일어나고 있는지 자세히 살펴보겠습니다.

 import { Server, Model } from 'miragejs'

위의 코드 조각에서 miragejs 에서 ServerModel 을 가져옵니다.

  • Server
    이것은 Mirage에서 제공하는 클래스로 Mirage JS 서버의 새 인스턴스를 인스턴스화하여 가짜 서버로 "제공"하는 데 도움이 됩니다.
  • Model
    Mirage의 ORM으로 구동되는 모델(모델이 Mirage JS 데이터베이스 항목의 구조를 결정함)을 생성하는 데 도움을 주기 위해 Mirage에서 제공하는 또 다른 클래스입니다.
 export function makeServer({ environment = "development" } = {}) {}

위의 내용은 기본적으로 src/server.js 에서 makeServer 라는 함수를 내보냅니다. 또한 환경 매개변수를 전달하고 Mirage의 환경 모드를 development 로 설정하고 있음을 알 수 있습니다(이 기사 뒷부분에서 테스트 환경을 통과하는 것을 볼 수 있음).

makeServer 의 본체

이제 makeServer 본문에서 몇 가지 작업을 수행합니다. 한 번 보자:

 let server = new Server({})

Server 클래스의 새 인스턴스를 인스턴스화하고 구성 옵션을 전달합니다. 구성 옵션의 내용은 Mirage를 설정하는 데 도움이 됩니다.

 { environment, models: { todo: Model, }, seeds(server) { server.create("todo", { content: "Learn Mirage JS" }) server.create("todo", { content: "Integrate With Vue.js" }) }, routes() { this.namespace = "api" this.get("/todos", schema => { return schema.todos.all() }) }, }

먼저 함수 정의에서 초기화한 environment 매개변수를 전달합니다.

 models: { todo: Model, },

models 옵션인 다음 옵션은 Mirage가 조롱하기를 원하는 다양한 모델의 객체를 취합니다.

위에서 우리는 Model 클래스에서 인스턴스화하는 todo 모델을 원합니다.

 seeds(server) { server.create("todo", { content: "Learn Mirage JS" }) server.create("todo", { content: "Integrate With Vue.js" }) },

다음 옵션은 server 라는 매개변수를 받는 seed 메소드입니다. 시드 방법은 모델에 대한 시드(시드는 초기 데이터 또는 Mirage 데이터베이스의 항목임)를 생성하는 데 도움이 됩니다. 우리의 경우 할 일 모델의 시드를 생성하기 위해 다음을 수행합니다.

 server.create("todo", { content: "Learn Mirage JS" }) server.create("todo", { content: "Integrate With Vue.js" })

따라서 서버에는 모델의 이름에 해당하는 문자열을 첫 번째 인수로 예상하는 create 메소드가 있고, 그 다음에는 특정 시드의 속성이나 속성을 포함할 객체가 있습니다.

 routes() { this.namespace = "api" this.get("/todos", schema => { return schema.todos.all() }) },

마지막으로 Mirage JS가 조롱할 다양한 라우트(라우트는 모의 API 엔드포인트임)를 정의하는 route 메소드가 있습니다. 메서드의 본문을 살펴보겠습니다.

 this.namespace = "api"

이 줄은 모든 경로에 대한 네임스페이스를 설정합니다. 즉, 이제 /api/todos에서 todo 경로에 액세스할 수 있습니다.

 this.get("/todos", schema => { return schema.todos.all() })

위는 get 경로를 만들고 this.get() 메서드를 사용하는 핸들러입니다. get() 메소드는 경로(예: "/todos")와 schema 를 인수로 취하는 핸들러 함수를 예상합니다. 스키마 개체는 Mirage JS 인메모리 데이터베이스에서 제공하는 Mirage의 ORM과 상호 작용하는 방법입니다.

마침내:

 return schema.todos.all()

Mirage의 ORM으로 가능해진 스키마 개체를 사용하여 모든 할일 목록을 반환합니다.

src/main.js

그래서 우리는 src/server.js 설정을 완료했지만 Vue는 그것에 대해 알지 못합니다(적어도 아직까지는). 따라서 다음과 같이 main.js 파일에서 가져오겠습니다.

 import { makeServer } from "./server"

그런 다음 다음과 같이 makeServer 함수를 호출합니다.

 if (process.env.NODE_ENV === "development") { makeServer() }

위의 조건부 조건은 신기루 if 개발 중에만 실행되도록 하는 가드입니다.

설정 완료!

이제 Vue로 Miragejs를 설정했습니다. 행동으로 봅시다. App.vue 파일에서 콘텐츠를 지우고 아래 스니펫으로 대체합니다.

 <template> <ul> <li v-for="todo in todos" v-bind:key="todo.id">{{ todo.content }}</li> </ul> </template> <script> export default { name: 'app', data() { return { todos: [] } }, created() { fetch("/api/todos") .then(res => res.json()) .then(json => { this.todos = json.todos }) } } </script>

Vue.js에 익숙하다면 위의 내용이 새롭지는 않겠지만 총체적으로 우리가 하는 일은 App.vue 구성 요소가 생성될 때 fetch 를 사용하여 API 요청을 만든 다음 반환된 데이터를 전달하는 것입니다. 구성 요소 상태의 todos 배열에. 그 후 v-for를 사용하여 todo 배열을 반복하고 각 todo의 content 속성을 표시합니다.

Mirage JS 부품은 어디에 있습니까?

App.vue 구성 요소에서 Mirage와 관련된 작업은 수행하지 않았으며 평소와 같이 API 호출을 수행하고 있습니다. Mirage의 이 기능은 내부적으로 DX 원인에 정말 훌륭합니다. Mirage는 개발 중인 동안 src/server.js에 정의된 경로와 일치하는 모든 요청을 가로챕니다.

이는 경로가 프로덕션 API 엔드포인트와 일치하는 경우 프로덕션 환경에 있을 때 실제 프로덕션 서버로 전환하는 데 작업이 필요하지 않기 때문에 매우 편리합니다.

따라서 Mirage JS를 테스트하려면 yarn serve 를 통해 Vue 개발 서버를 다시 시작하세요.

두 개의 할 일 목록이 표시되어야 합니다. 매우 흥미로운 점은 Vue.js 애플리케이션의 일부로 실행하여 오버헤드를 제거하기 때문에 Mirage를 시작하기 위해 터미널 명령을 실행할 필요가 없다는 것입니다.

Mirage JS 및 Vue 테스트 유틸리티

Vue 애플리케이션에서 이미 Vue Test-utils를 사용하고 있다면 Mirage가 네트워크 요청을 모의하기 위해 쉽게 사용할 수 있다는 사실이 흥미로울 것입니다. 할 일 애플리케이션을 사용하여 설정한 예를 살펴보겠습니다.

우리는 단위 테스트를 위해 Jest를 사용할 것입니다. 따라서 따라하는 경우 Vue CLI를 사용하여 다음과 같이 @vue/unit-jest 플러그인을 설치할 수 있습니다.

 vue add @vue/unit-jest

위의 내용은 @vue/cli-plugin-unit-jest@vue/test-utils 개발 종속성을 설치하는 동시에 tests 디렉토리와 jest.config.js 파일을 생성합니다. 또한 package.json scripts 섹션에 다음 명령을 추가합니다(꽤 깔끔함).

 "test:unit": "vue-cli-service test:unit"

테스트하자!

App.vue 를 다음과 같이 업데이트합니다.

 <!-- src/App.vue --> <template> <div v-if="serverError" data-test> {{ serverError }} </div> <div v-else-if="todos.length === 0" data-test> No todos! </div> <div v-else> <ul> <li v-for="todo in todos" v-bind:key="todo.id" :data-test > {{ todo.content }} </li> </ul> </div> </template> <script> export default { name: "app", data() { return { todos: [], serverError: null, } }, created() { fetch("/api/todos") .then(res => res.json()) .then(json => { if (json.error) { this.serverError = json.error } else { this.todos = json.todos } }) }, } </script>

위의 스 니펫에서 실제로 서사시가 진행되지는 않습니다. 우리는 단위 테스트로 구현할 네트워크 테스트를 허용하도록 구성하고 있습니다.

Vue CLI가 이미 /tests 폴더를 추가했지만 내 테스트가 테스트 중인 구성 요소 가까이에 배치되면 훨씬 더 나은 경험을 할 수 있습니다. 따라서 src//__tests__ 폴더를 만들고 그 안에 App.spec.js 파일을 만듭니다. (이것도 Jest가 권장하는 접근 방식입니다.)

 // src/__tests__/App.spec.js import { mount } from "@vue/test-utils" import { makeServer } from "../server" import App from "../App.vue" let server beforeEach(() => { server = makeServer({ environment: "test" }) }) afterEach(() => { server.shutdown() })

따라서 단위 테스트를 설정하기 위해 @vue/test-utils 에서 mount 메서드를 가져오고 이전에 만든 Miragejs 서버를 가져오고 마지막으로 App.vue 구성 요소를 가져옵니다.

다음으로 테스트 환경을 통과하면서 Mirage JS 서버를 시작하기 위해 beforeEach 라이프 사이클 함수를 사용하고 있습니다. (기억하세요, 우리는 기본적으로 환경을 development 로 설정했습니다.)

마지막으로 afterEach 라이프사이클 메소드에서 server.shutdown 을 사용하여 서버를 종료합니다.

우리의 테스트

이제 테스트를 구체화하겠습니다(Mirage js 문서의 빠른 시작 섹션을 채택할 것입니다. 따라서 App.spec.js 는 최종적으로 다음과 같이 보일 것입니다.

 // src/__tests__/App.spec.js import { mount } from "@vue/test-utils" import { makeServer } from "./server" import App from "./App.vue" let server beforeEach(() => { server = makeServer({ environment: "test" }) }) it("shows the todos from our server", async () => { server.create("todo", { id: 1, content: "Learn Mirage JS" }) server.create("todo", { id: 2, content: "Integrate with Vue.js" }) const wrapper = mount(App) // let's wait for our vue component to finish loading data // we know it's done when the data-testid enters the dom. await waitFor(wrapper, '[data-test]') await waitFor(wrapper, '[data-test]') expect(wrapper.find('[data-test]').text()).toBe("Learn Mirage JS") expect(wrapper.find('[data-test]').text()).toBe("Integrate with Vue.js") }) it("shows a message if there are no todo", async () => { // Don't create any todos const wrapper = mount(App) await waitFor(wrapper, '[data-test]') expect(wrapper.find('[data-test]').text()).toBe("No todos!") }) // This helper method returns a promise that resolves // once the selector enters the wrapper's dom. const waitFor = function(wrapper, selector) { return new Promise(resolve => { const timer = setInterval(() => { const todoEl = wrapper.findAll(selector) if (todoEl.length > 0) { clearInterval(timer) resolve() } }, 100) }) } afterEach(() => { server.shutdown() })

참고 : 여기에서 도우미를 사용하고 있습니다(Mirage JS 문서에 정의됨). 테스트 중인 요소가 이미 DOM에 언제 있는지 알 수 있는 약속을 반환합니다.

이제 yarn test:unit 을 실행합니다.

모든 테스트는 이 시점에서 통과해야 합니다.

Mirage JS로 다양한 서버 상태 테스트하기

Mirage JS 서버를 변경하여 다양한 서버 상태를 테스트할 수 있습니다. 방법을 봅시다.

 // src/__tests__/App.spec.js import { Response } from "miragejs"

먼저 Mirage에서 Response 클래스를 가져온 다음 다음과 같은 새 테스트 시나리오를 만듭니다.

 it("handles error responses from the server", async () => { // Override Mirage's route handler for /todos, just for this test server.get("/todos", () => { return new Response( 500, {}, { error: "The database is taking a break.", } ) }) const wrapper = mount(App) await waitFor(wrapper, '[data-test]') expect(wrapper.find('[data-test]').text()).toBe( "The database is taking a break." ) })

테스트를 실행하면 모두 통과해야 합니다.

결론

이 기사는 Mirage JS를 소개하고 이것이 어떻게 더 나은 프론트엔드 개발 환경을 만드는지 보여주기 위한 것입니다. Mirage JS가 해결하기 위해 생성한 문제(실제 백엔드 API 없이 프로덕션 준비 프론트엔드 구축)와 Vue.js로 설정하는 방법을 보았습니다.

이 기사가 Mirage JS가 할 수 있는 일의 표면을 긁었지만 시작하기에 충분하다고 생각합니다.

  • 문서를 살펴보고 Mirage JS 디스코드 서버에 가입할 수 있습니다.
  • 이 문서에 대한 지원 리포지토리는 GitHub에서 사용할 수 있습니다.

참고문헌

  • 미라지 문서
  • Mirage Vue 빠른 시작