Mirage JS 심층 분석: 공장, 설비 및 직렬 변환기 이해(2부)
게시 됨: 2022-03-10이 시리즈의 이전 기사에서 우리는 Mirage와 관련된 모델 및 연결을 이해했습니다. Models를 사용하면 Mirage가 모의 엔드포인트에 요청할 때 애플리케이션에 제공할 동적 모의 데이터를 생성할 수 있다고 설명했습니다. 이 기사에서는 더 빠른 API 조롱을 가능하게 하는 세 가지 다른 Mirage 기능을 살펴보겠습니다. 바로 뛰어들자!
참고 : 여기에서 논의할 내용을 제대로 이해하지 못한 경우 처음 두 기사를 읽는 것이 좋습니다. 그러나 필요한 경우 이전 기사를 계속 따르고 참조할 수 있습니다.
- Mirage JS 및 Vue로 API 모의 설정
- Mirage JS 모델 및 연결
공장
이전 기사에서 Mirage JS를 사용하여 백엔드 API를 모의하는 방법에 대해 설명했습니다. 이제 Mirage에서 제품 리소스를 모의한다고 가정하겠습니다. 이를 달성하기 위해 특정 엔드포인트에 대한 요청을 가로채는 역할을 하는 경로 핸들러 를 생성합니다. 이 경우 엔드포인트는 api/products
입니다. 우리가 만든 경로 처리기는 모든 제품을 반환합니다. 다음은 Mirage에서 이를 수행하는 코드입니다.
import { Server, Model } from 'miragejs'; new Server({ models: { product: Model, }, routes() { this.namespace = "api"; this.get('products', (schema, request) => { return schema.products.all() }) } }); },
위의 출력은 다음과 같습니다.
{ "products": [] }
위의 출력에서 제품 리소스가 비어 있음을 알 수 있습니다. 그러나 이는 아직 레코드를 생성하지 않았기 때문에 예상되는 결과입니다.
전문가 팁 : Mirage는 기존 API 엔드포인트에 필요한 축약형을 제공합니다. 따라서 위의 경로 처리기는 this.get('/products')
와 같이 짧을 수도 있습니다.
Server
인스턴스에서 seeds
메서드를 사용하여 Mirage 데이터베이스에 저장할 product
모델의 레코드를 생성해 보겠습니다.
seeds(server) { server.create('product', { name: 'Gemini Jacket' }) server.create('product', { name: 'Hansel Jeans' }) },
출력:
{ "products": [ { "name": "Gemini Jacket", "id": "1" }, { "name": "Hansel Jeans", "id": "2" } ] }
위에서 볼 수 있듯이 프론트엔드 애플리케이션이 /api/products
에 요청하면 seeds
메서드에 정의된 대로 제품 컬렉션을 반환합니다.
seeds
방법을 사용하여 Mirage의 데이터베이스를 시드하는 것은 각 항목을 개체로 수동으로 생성해야 하는 단계입니다. 그러나 위의 패턴을 사용하여 1000(또는 100만) 개의 새 제품 레코드를 만드는 것은 실용적이지 않습니다. 따라서 공장 이 필요합니다.
공장 설명
팩토리는 새로운 데이터베이스 레코드를 생성하는 더 빠른 방법입니다. 이를 통해 Mirage JS 데이터베이스에 저장할 변형이 있는 특정 모델의 여러 레코드를 빠르게 생성할 수 있습니다.
팩토리는 또한 데이터를 개별적으로 시드할 필요 없이 사실적인 데이터를 쉽게 생성할 수 있도록 하는 객체입니다. 공장은 모델에서 기록을 생성하기 위한 레시피 또는 청사진 에 가깝습니다.
공장 만들기
Factory를 생성하여 살펴보겠습니다. 우리가 만들 공장은 Mirage JS 데이터베이스에서 새로운 제품을 만들기 위한 청사진으로 사용됩니다.
import { Factory } from 'miragejs' new Server({ // including the model definition for a better understanding of what's going on models: { product: Model }, factories: { product: Factory.extend({}) } })
위에서 우리가 Server
인스턴스에 factories
속성을 추가한 것을 볼 수 있을 것이고 그 안에 규칙에 따라 우리가 팩토리를 생성하고자 하는 모델과 같은 이름을 가지는 또 다른 속성을 정의할 수 있을 것입니다. 이 경우, 그 모델은 product
모델. 위의 스니펫은 Mirage JS에서 팩토리를 생성할 때 따라야 하는 패턴을 보여줍니다.
product
모델에 대한 공장이 있지만 실제로 속성을 추가하지 않았습니다. 팩토리의 속성은 string , booleans 또는 numbers 와 같은 간단한 유형이거나 아래의 새 제품 팩토리의 전체 구현에서 볼 수 있는 동적 데이터를 반환하는 함수일 수 있습니다.
import { Server, Model, Factory } from 'miragejs' new Server({ models: { product: Model }, factories: { product: Factory.extend({ name(i) { // i is the index of the record which will be auto incremented by Mirage JS return `Awesome Product ${i}`; // Awesome Product 1, Awesome Product 2, etc. }, price() { let minPrice = 20; let maxPrice = 2000; let randomPrice = Math.floor(Math.random() * (maxPrice - minPrice + 1)) + minPrice; return `$ ${randomPrice}`; }, category() { let categories = [ 'Electronics', 'Computing', 'Fashion', 'Gaming', 'Baby Products', ]; let randomCategoryIndex = Math.floor( Math.random() * categories.length ); let randomCategory = categories[randomCategoryIndex]; return randomCategory; }, rating() { let minRating = 0 let maxRating = 5 return Math.floor(Math.random() * (maxRating - minRating + 1)) + minRating; }, }), }, })
위의 코드 스니펫에서 Math.random
을 통해 일부 자바스크립트 로직을 지정하여 팩토리를 사용하여 새 제품 레코드를 생성할 때마다 동적 데이터를 생성합니다. 이것은 Factory의 강점과 유연성을 보여줍니다.
위에서 정의한 공장을 활용하여 제품을 만들어 봅시다. 이를 위해 server.create
를 호출하고 모델 이름( product
)을 문자열로 전달합니다. 그런 다음 Mirage는 우리가 정의한 제품 공장을 사용하여 제품의 새 기록을 생성합니다. 이를 위해 필요한 코드는 다음과 같습니다.
new Server({ seeds(server) { server.create("product") } })
전문가 팁 : console.log(server.db.dump())
를 실행하여 Mirage 데이터베이스의 레코드를 볼 수 있습니다.
아래와 유사한 새 레코드가 생성되어 Mirage 데이터베이스에 저장되었습니다.
{ "products": [ { "rating": 3, "category": "Computing", "price": "$739", "name": "Awesome Product 0", "id": "1" } ] }
오버라이드 팩토리
다음과 같이 명시적으로 전달하여 팩토리에서 제공하는 값 중 일부 이상을 재정의할 수 있습니다.
server.create("product", {name: "Yet Another Product", rating: 5, category: "Fashion" })
결과 레코드는 다음과 유사합니다.
{ "products": [ { "rating": 5, "category": "Fashion", "price": "$782", "name": "Yet Another Product", "id": "1" } ] }
목록 작성
공장이 제자리에 있으면 createList
라는 서버 객체에 다른 메서드를 사용할 수 있습니다. 이 방법을 사용하면 모델 이름과 생성하려는 레코드 수를 전달하여 특정 모델의 여러 레코드를 생성할 수 있습니다. 아래는 사용법입니다.
server.createList("product", 10)
또는
server.createList("product", 1000)
보시다시피 위의 createList
메서드는 두 개의 인수를 사용합니다. 모델 이름은 문자열이고, 다른 하나는 생성할 레코드 수를 나타내는 0이 아닌 양의 정수입니다. 그래서 위에서 우리는 500개의 제품 레코드를 만들었습니다! 이 패턴은 이 시리즈의 이후 기사에서 볼 수 있듯이 UI 테스트에 유용합니다.
비품
소프트웨어 테스트에서 테스트 픽스처 또는 픽스처 는 테스트 실행을 위한 기준선 역할을 하는 개체 집합 또는 컬렉션의 상태입니다. 픽스처의 주요 목적은 결과를 반복 가능하게 만들기 위해 테스트 환경이 잘 알려져 있는지 확인하는 것입니다.
Mirage를 사용하면 고정 장치를 만들고 이를 사용하여 초기 데이터로 데이터베이스를 시드할 수 있습니다.
참고 : 팩토리를 10번 중 9번 사용하는 것이 좋습니다. 팩토리를 사용하면 모형을 유지 관리하기 쉽게 만들 수 있기 때문입니다.
설비 만들기
데이터베이스에 데이터를 로드하는 간단한 고정 장치를 만들어 보겠습니다.
fixtures: { products: [ { id: 1, name: 'T-shirts' }, { id: 2, name: 'Work Jeans' }, ], },
위의 데이터는 Mirage의 초기 데이터로 데이터베이스에 자동으로 로드됩니다. 그러나 시드 함수가 정의된 경우 Mirage는 재정의하려는 가정으로 고정 장치를 무시하고 대신 팩토리를 사용하여 데이터를 시드합니다.
공장과 관련된 설비
Mirage는 Factory와 함께 Fixtures를 사용할 수 있도록 제공합니다. server.loadFixtures()
를 호출하여 이를 달성할 수 있습니다. 예를 들어:
fixtures: { products: [ { id: 1, name: "iPhone 7" }, { id: 2, name: "Smart TV" }, { id: 3, name: "Pressing Iron" }, ], }, seeds(server) { // Permits both fixtures and factories to live side by side server.loadFixtures() server.create("product") },
고정 파일
이상적으로는 server.js
와 별도의 파일에 조명기를 만들고 가져오기를 원할 것입니다. 예를 들어, fixtures
라는 디렉토리를 생성하고 그 안에 products.js
를 생성할 수 있습니다. products.js
에 다음을 추가합니다.
// <PROJECT-ROOT>/fixtures/products.js export default [ { id: 1, name: 'iPhone 7' }, { id: 2, name: 'Smart TV' }, { id: 3, name: 'Pressing Iron' }, ];
그런 다음 server.js
에서 다음과 같이 제품 고정 장치를 가져오고 사용합니다.
import products from './fixtures/products'; fixtures: { products, },
나는 조명기 객체의 products
속성에 가져온 제품 배열을 할당하기 위해 ES6 속성 속기를 사용하고 있습니다.
server.loadFixtures()
를 사용하여 명시적으로 지시하지 않는 한 테스트 중에 Mirage JS가 고정 장치를 무시한다는 점은 언급할 가치가 있습니다.
공장 대 비품
제 생각에는 공장보다 더 적합한 특정 사용 사례가 있는 경우를 제외하고는 고정 장치를 사용하지 않는 것이 좋습니다. 설비는 더 장황한 경향이 있는 반면 공장은 더 빠르고 키 입력이 더 적습니다.
직렬 변환기
프론트엔드에 예상되는 JSON 페이로드를 반환하는 것이 중요하므로 serializers 입니다.
직렬 변환기는 경로 처리기에서 반환된 **Model** 또는 **Collection**을 프런트엔드 앱이 예상하는 형식의 JSON 페이로드로 변환하는 역할을 하는 개체입니다.
미라지 문서
이 경로 처리기를 예로 들어 보겠습니다.
this.get('products/:id', (schema, request) => { return schema.products.find(request.params.id); });
직렬 변환기는 응답을 다음과 같이 변환합니다.
{ "product": { "rating": 0, "category": "Baby Products", "price": "$654", "name": "Awesome Product 1", "id": "2" } }
Mirage JS 내장 직렬 변환기
Mirage JS 직렬 변환기를 사용하려면 시작할 기본 제공 직렬 변환기를 선택해야 합니다. 이 결정은 백엔드가 결국 프론트엔드 애플리케이션으로 보낼 JSON 유형의 영향을 받습니다. Mirage는 다음 직렬 변환기와 함께 제공됩니다.
-
JSONAPISerializer
이 직렬 변환기는 JSON:API 사양을 따릅니다. -
ActiveModelSerializer
이 직렬 변환기는 active_model_serializer gem으로 빌드된 Rails API와 유사한 API를 모방하기 위한 것입니다. -
RestSerializer
RestSerializer
는 다른 공통 API에 대한 Mirage JS "catch all" 직렬 변환기입니다.
직렬 변환기 정의
직렬화를 정의하려면 다음과 같이 RestSerializer
에서 miragejs
와 같은 적절한 직렬 변환기를 가져옵니다.
import { Server, RestSerializer } from "miragejs"
그런 다음 Server
인스턴스에서:
new Server({ serializers: { application: RestSerializer, }, })
RestSerializer
는 기본적으로 Mirage JS에서 사용됩니다. 따라서 명시적으로 설정하는 것은 불필요합니다. 위의 스니펫은 예시를 위한 것입니다.
위에서 정의한 것과 동일한 경로 핸들러에서 JSONAPISerializer
와 ActiveModelSerializer
의 출력을 살펴보겠습니다.
JSONAPI 직렬 변환기
import { Server, JSONAPISerializer } from "miragejs" new Server({ serializers: { application: JSONAPISerializer, }, })
출력:
{ "data": { "type": "products", "id": "2", "attributes": { "rating": 3, "category": "Electronics", "price": "$1711", "name": "Awesome Product 1" } } }
활성 모델 직렬 변환기
작동 중인 ActiveModelSerializer를 보려면 제품 팩토리의 category
선언을 다음과 같이 수정합니다.
productCategory() { let categories = [ 'Electronics', 'Computing', 'Fashion', 'Gaming', 'Baby Products', ]; let randomCategoryIndex = Math.floor( Math.random() * categories.length ); let randomCategory = categories[randomCategoryIndex]; return randomCategory; },
내가 한 일은 직렬 변환기가 이를 처리하는 방법을 보여주기 위해 속성 이름을 productCategory
로 변경하는 것뿐이었습니다.
그런 다음 ActiveModelSerializer
직렬 변환기를 다음과 같이 정의합니다.
import { Server, ActiveModelSerializer } from "miragejs" new Server({ serializers: { application: ActiveModelSerializer, }, })
직렬 변환기는 반환된 JSON을 다음과 같이 변환합니다.
{ "rating": 2, "product_category": "Computing", "price": "$64", "name": "Awesome Product 4", "id": "5" }
productCategory
가 Ruby 생태계의 active_model_serializer gem을 준수하는 product_category
로 변환되었음을 알 수 있습니다.
직렬 변환기 사용자 정의
Mirage는 직렬 변환기를 사용자 지정하는 기능을 제공합니다. 애플리케이션에서 속성 이름을 카멜케이스로 처리해야 한다고 가정해 보겠습니다. 이를 달성하기 위해 RestSerializer
를 재정의할 수 있습니다. 우리는 lodash
유틸리티 라이브러리를 사용할 것입니다:
import { RestSerializer } from 'miragejs'; import { camelCase, upperFirst } from 'lodash'; serializers: { application: RestSerializer.extend({ keyForAttribute(attr) { return upperFirst(camelCase(attr)); }, }), },
그러면 다음 형식의 JSON이 생성되어야 합니다.
{ "Rating": 5, "ProductCategory": "Fashion", "Price": "$1386", "Name": "Awesome Product 4", "Id": "5" }
마무리
네가 해냈어! 이 기사를 통해 Mirage에 대해 더 깊이 이해하고 팩토리, 픽스처 및 직렬 변환기를 활용하여 Mirage를 사용하여 보다 프로덕션과 유사한 API 모형을 생성할 수 있는 방법도 확인하셨기를 바랍니다.
- 1부: Mirage JS 모델 및 연결 이해
- 2부: 공장, 설비 및 직렬 변환기 이해
- 3부: 타이밍, 응답 및 통과 이해
- 4부: UI 테스트에 Mirage JS 및 Cypress 사용