Mirage JS Deep Dive:工場、備品、シリアライザーを理解する(パート2)

公開: 2022-03-10
クイックサマリー↬ミラージュJSディープダイブシリーズのこの第2部では、ミラージュJSの工場、備品、およびシリアライザーについて説明します。 Mirageを使用して迅速なAPIモックを有効にする方法を見ていきます。

このシリーズの前回の記事では、ミラージュに関連するモデルとアソシエーションについて説明しました。 モデルを使用すると、Mirageがモックエンドポイントにリクエストを送信するときにアプリケーションに提供する動的なモックデータを作成できることを説明しました。 この記事では、さらに高速なAP​​Iモックを可能にする他の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によって使用されます。 したがって、明示的に設定するのは冗長です。 上記のスニペットは例示を目的としています。

上で定義したのと同じルートハンドラーでのJSONAPISerializerActiveModelSerializerの両方の出力を見てみましょう。

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を使用する