パート 8 – ファクトリー

Mirage には、Mirage サーバーに現実的なリレーショナルデータをシードするプロセスを簡素化するためのファクトリーレイヤーが含まれています。

現在、リマインダーを作成したい場合、seeds() フック内で次のような処理をする必要があります。

seeds(server) {
  server.create("reminder", { text: "Walk the dog" });
}

作成するすべてのモデルですべての属性を常に指定する必要があるため、特にテスト中にコードに多くのボイラープレートが追加される可能性があります。データが有効であるためにリレーションシップが必要な場合は、さらに複雑になります。

ファクトリーは、データの制約をエンコードするのに最適な場所であり、有効なデータグラフをすばやく作成しやすくします。どのように機能するか見てみましょう。

このアプリでは、リマインダーには常に text プロパティがあります。これをエンコードするリマインダーファクトリーを定義しましょう。

import {
  createServer,
  Model,
  hasMany,
  belongsTo,
  RestSerializer,
  Factory,
} from "miragejs"

export default function () {
  createServer({
    models: {
      list: Model.extend({
        reminders: hasMany(),
      }),

      reminder: Model.extend({
        list: belongsTo(),
      }),
    },

    factories: {
      reminder: Factory.extend({
        text: "Reminder text",
      }),
    },

    // ...rest of server
  })
}

まず、Factory をインポートし、サーバーの新しい factories キーを使用してリマインダーファクトリーを定義します。Factory.extend(config) を使用して config オブジェクトを渡すことができます。config オブジェクトのキーはモデルのプロパティに対応します。

これで、seeds() を更新して、他の何も渡さずに server.create('reminder') を呼び出すだけでよくなります。

seeds(server) {
  server.create("reminder");
  server.create("reminder");
  server.create("reminder");
}

このシードデータにより、アプリは次のようになります。

Failing request

有効ですが、あまり現実的ではありません。関数プロパティを使用して、これをもう少し動的にすることができます。

factories: {
  reminder: Factory.extend({
    text(i) {
      return `Reminder ${i}`
    }
  }),
},

これで、各リマインダーに独自のテキストが含まれます。

Dyanamic attr

faker.js のようなライブラリも、関数プロパティでうまく機能し、さらに忠実度の高いデータを作成できます。

server.createList と組み合わせることで、ファクトリー定義を使用して多くのリマインダーを簡単に作成できます。

seeds(server) {
  server.createList("reminder", 100);
}

これにより、大きなデータセットをすばやく取得できます。

Dyanamic list

ただし、ファクトリーで定義した特定のプロパティをオーバーライドしたい場合はどうすればよいでしょうか?server.create() に属性を渡すことで、いつでもそれを行うことができます。これらの属性は、ベースファクトリーで定義されているものをすべてオーバーライドします。

seeds(server) {
  // Create a specific reminder
  server.create('reminder', { text: 'Walk the dog' })

  // Create 5 more generic reminders
  server.createList("reminder", 5);
}

結果は次のとおりです。

Mixing static and dynamic attrs

リストモデルに移りましょう。まず、そのためのファクトリーを定義します。

factories: {
  list: Factory.extend({
    name(i) {
      return `List ${i}`;
    },
  }),

  reminder: Factory.extend({
    text(i) {
      return `Reminder ${i}`;
    },
  }),
},

これで、汎用リストとリマインダーを作成したい場合は、属性を指定する必要はありません。

seeds(server) {
  server.create("list", {
    reminders: server.createList("reminder", 5),
  });
}

ご覧のとおり、作成時にリストにリマインダーを渡すことで、リレーショナルデータの有効なグラフを作成できます。

Lists

たくさんのリマインダーを含むリストをさらに簡単に作成したい場合はどうすればよいでしょうか?リストファクトリーの afterCreate フックを使用し、新しく作成されたリストを、作成する新しいリマインダーに渡すことができます。

factories: {
  list: Factory.extend({
    name(i) {
      return `List ${i}`;
    },

    afterCreate(list, server) {
      server.createList('reminder', 5, { list })
    }
  }),

  reminder: Factory.extend({
    text(i) {
      return `Reminder ${i}`;
    },
  }),
},

これで、server.create('list') だけで、以前のように 5 つのリマインダーモデルを持つ有効なリストを作成できます。

seeds(server) {
  server.create("list")
}

ただし、特定の内容をテストしているため、または開発中にジェネリックではないデータが必要なため、より厳選された現実的なデータの一部を復元したい場合はどうすればよいでしょうか?

このシーディングロジックをコピーしてください。

seeds(server) {
  server.create("list", {
    name: "Home",
    reminders: [server.create("reminder", { text: "Do taxes" })],
  });

  server.create("list")
}

このロジックを使用すると、afterCreate フックが両方のリストに対してトリガーされ、Home リストには、特定の「税金の申告」リマインダーに加えて、5 つのランダムに生成されたリマインダーが含まれるようになりました。

After create

afterCreate ロジックを更新して、新しく作成されたリストにリマインダーが既に渡されているかどうかを最初に確認し、そうでない場合にのみデフォルトのリマインダーを作成できます。

factories: {
  list: Factory.extend({
    name(i) {
      return `List ${i}`;
    },

    afterCreate(list, server) {
      if (!list.reminders.length) {
        server.createList('reminder', 5, { list })
      }
    }
  }),

  reminder: Factory.extend({
    text(i) {
      return `Reminder ${i}`;
    },
  }),
},

これで、同じシードロジックで、「税金の申告」リマインダーのみを渡した厳選された「ホーム」リストを簡単に作成できるようになり、server.create('list') をプレーンに呼び出すことで、5 つのリマインダーを含むジェネリックリストをすばやく作成できます。

Improved after create

最後のリファクタリングステップとして、必要な場合にのみリストに関連付けられたジェネリックリマインダーを作成するさらに優れたアプローチがあります。それはファクトリートレイトです。

トレイトを使用すると、属性と afterCreate ロジックを名前でグループ化できるため、その名前を使用した場合にのみ呼び出されます。リストファクトリーに withReminders トレイトを追加しましょう。

最初に trait をインポートします。

import {
  createServer,
  Model,
  hasMany,
  belongsTo,
  RestSerializer,
  Factory,
  trait,
} from "miragejs"

次に、afterCreate ロジックをリストファクトリーの withReminders トレイトに移動します。

factories: {
  list: Factory.extend({
    name(i) {
      return `List ${i}`;
    },

    withReminders: trait({
      afterCreate(list, server) {
        server.createList('reminder', 5, { list })
      }
    })
  }),

  reminder: Factory.extend({
    text(i) {
      return `Reminder ${i}`;
    },
  }),
},

このロジックは、トレイトを明示的に呼び出した場合にのみ呼び出されるため、list.reminders.length チェックを削除したことに注意してください。

保存してアプリを確認すると、2 番目のジェネリックリストには関連付けられたリマインダーがなくなっていることがわかります。そのリストに対して新しいトレイトを呼び出すように、seeds フックを更新しましょう。

seeds(server) {
  server.create("list", {
    name: "Home",
    reminders: [server.create("reminder", { text: "Do taxes" })],
  });

  server.create("list", "withReminders")
}

これで、UI は元の状態に戻りました。ただし、基本ケースでは単一のリストモデルのみを作成するため、リストファクトリーがよりわかりやすくなりました。

次のセクションで説明するように、適切なファクトリー定義は、適切なテストを記述するために重要です。

ファクトリーには、データシナリオを作成するための柔軟な方法を提供するさらに多くの機能があるため、開発環境を匿名ユーザーから認証済みユーザーにすばやく切り替えたり、テストに必要なデータのみを設定したりできます。

今のところ、シーディングロジックを厳選されたデータセットに戻しましょう。

seeds(server) {
  server.create("reminder", { text: "Walk the dog" });
  server.create("reminder", { text: "Take out the trash" });
  server.create("reminder", { text: "Work out" });

  server.create("list", {
    name: "Home",
    reminders: [server.create("reminder", { text: "Do taxes" })],
  });

  server.create("list", {
    name: "Work",
    reminders: [server.create("reminder", { text: "Visit bank" })],
  });
}

ファクトリーをうまく使用することは、Mirage のデータレイヤーのすべての機能を活用するための最良の方法の 1 つです。

要点

  • ファクトリーは、リレーショナルデータのグラフを簡単に作成するのに役立つブループリントのようなものです。
  • 静的な値または関数を属性として使用できます。
  • server.create() を呼び出すときはいつでも、ファクトリーのデフォルトをオーバーライドできます。
  • afterCreate フックを使用して、モデルの関連データを自動的に作成するなど、追加のロジックを実行します。
  • 関連する属性とafterCreateロジックをグループ化し、ファクトリを構成可能に保つために、トレイトを使用します。