Mirage JS Deep Dive:工場、備品、シリアライザーを理解する(パート2)
公開: 2022-03-10このシリーズの前回の記事では、ミラージュに関連するモデルとアソシエーションについて説明しました。 モデルを使用すると、Mirageがモックエンドポイントにリクエストを送信するときにアプリケーションに提供する動的なモックデータを作成できることを説明しました。 この記事では、さらに高速なAPIモックを可能にする他の3つのMirage機能について説明します。 さっそく飛び込みましょう!
注:ここで説明する内容をしっかりと理解していない場合は、最初の2つの記事を読むことを強くお勧めします。 ただし、必要に応じて、以前の記事をフォローして参照することもできます。
- MirageJSとVueを使用したAPIモックの設定
- MirageJSモデルとアソシエーション
工場
前回の記事では、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万)の新しい製品レコードを作成することは実用的ではありません。 したがって、工場の必要性。
工場の説明
工場は、新しいデータベースレコードを作成するためのより高速な方法です。 これらを使用すると、MirageJSデータベースに保存するバリエーションを含む特定のモデルの複数のレコードをすばやく作成できます。
ファクトリは、データを個別にシードすることなく、リアルなデータを簡単に生成できるようにするオブジェクトでもあります。 工場は、モデルからレコードを作成するためのレシピまたは青写真です。
工場の作成
ファクトリを作成して調べてみましょう。 私たちが作成する工場は、MirageJSデータベースで新製品を作成するための青写真として使用されます。
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
モデル。 上記のスニペットは、MirageJSでファクトリを作成するときに従うパターンを示しています。
product
モデルのファクトリはありますが、実際にはプロパティを追加していません。 ファクトリのプロパティは、文字列、ブール値、数値などの単純な型、または以下の新製品ファクトリの完全な実装で見られるように動的データを返す関数にすることができます。
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
を介してjavascriptロジックを指定し、ファクトリを使用して新しい製品レコードを作成するたびに動的データを作成しています。 これは、工場の強さと柔軟性を示しています。
上で定義したファクトリを利用して製品を作成しましょう。 これを行うには、 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
ファクトリを配置すると、サーバーオブジェクトでcreateList
という別のメソッドを使用できます。 この方法では、モデル名と作成するレコード数を渡すことで、特定のモデルの複数のレコードを作成できます。 以下はその使用法です:
server.createList("product", 10)
または
server.createList("product", 1000)
ご覧のとおり、上記のcreateList
メソッドは、文字列としてのモデル名と、作成するレコードの数を表すゼロ以外の正の整数の2つの引数を取ります。 以上のことから、500件の商品レコードを作成しました。 このパターンは、このシリーズの今後の記事で説明するように、UIテストに役立ちます。
備品
ソフトウェアテストでは、テストフィクスチャまたはフィクスチャは、テストを実行するためのベースラインとして機能するオブジェクトのセットまたはコレクションの状態です。 フィクスチャの主な目的は、結果を再現可能にするために、テスト環境がよく知られていることを確認することです。
Mirageを使用すると、フィクスチャを作成し、それらを使用してデータベースに初期データをシードできます。
注:モックの保守性が向上するため、10回のうち9回はファクトリを使用することをお勧めします。
フィクスチャの作成
データベースにデータをロードするための簡単なフィクスチャを作成しましょう。
fixtures: { products: [ { id: 1, name: 'T-shirts' }, { id: 2, name: 'Work Jeans' }, ], },
上記のデータは、Mirageの初期データとしてデータベースに自動的にロードされます。 ただし、シード関数が定義されている場合、Mirageは、フィクスチャがオーバーライドされることを想定してフィクスチャを無視し、代わりにファクトリを使用してデータをシードします。
工場と連携した備品
Mirageは、ファクトリと一緒にフィクスチャを使用できるように準備しています。 これは、 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配列をfixturesオブジェクトのproducts
プロパティに割り当てるために、ES6プロパティの省略形を使用しています。
server.loadFixtures()
を使用して明示的に指示しない限り、テスト中にMirageJSによってフィクスチャが無視されることは言及する価値があります。
工場対備品
私の意見では、フィクスチャが工場よりも適している特定のユースケースがある場合を除いて、フィクスチャの使用を控えるべきです。 工場はより速く、より少ないキーストロークを必要としますが、備品はより冗長になる傾向があります。
シリアライザー
フロントエンド、つまりシリアライザーに期待されるJSONペイロードを返すことが重要です。
シリアライザーは、ルートハンドラーから返された**モデル**または**コレクション**を、フロントエンドアプリが期待する方法でフォーマットされた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" } }
MirageJSビルトインシリアライザー
Mirage JSシリアライザーを使用するには、最初にどの組み込みシリアライザーを選択する必要があります。 この決定は、バックエンドが最終的にフロントエンドアプリケーションに送信するJSONのタイプに影響されます。 Mirageには、次のシリアライザーが含まれています。
-
JSONAPISerializer
このシリアライザーは、JSON:API仕様に従います。 -
ActiveModelSerializer
このシリアライザーは、active_model_serializergemで構築されたRailsAPIに似たAPIを模倣することを目的としています。 -
RestSerializer
RestSerializer
は、他の一般的なAPI用のMirageJSの「キャッチオール」シリアライザーです。
シリアライザーの定義
シリアライズを定義するには、次のようにRestSerializer
からmiragejs
などの適切なシリアライザーをインポートします。
import { Server, RestSerializer } from "miragejs"
次に、 Server
インスタンスで:
new Server({ serializers: { application: RestSerializer, }, })
RestSerializer
は、デフォルトでMirageJSによって使用されます。 したがって、明示的に設定するのは冗長です。 上記のスニペットは例示を目的としています。
上で定義したのと同じルートハンドラーでのJSONAPISerializer
とActiveModelSerializer
の両方の出力を見てみましょう。
JSONAPISerializer
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
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エコシステムのproductCategory
に準拠する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:MirageJSモデルとアソシエーションを理解する
- パート2:工場、備品、シリアライザーを理解する
- パート3:タイミング、応答、パススルーを理解する
- パート4:UIテストにMirageJSとCypressを使用する