シリアライザー
シリアライザーは、ルートハンドラーのレスポンスのフォーマットを担当します。
アプリケーションシリアライザーは、すべてのレスポンスに適用されます。特定のカスタマイズを行うには、モデルごとのシリアライザーを定義します。
import { Server, RestSerializer } from 'miragejs';
new Server({
serializers: {
application: RestSerializer,
user: RestSerializer.extend({
// user-specific customizations
})
}
})
ルートハンドラーから返されるすべてのモデルまたはコレクションは、シリアライザーレイヤーを通過します。最も高い優先度はモデル固有のシリアライザーに与えられ、次にアプリケーションシリアライザー、最後にデフォルトのシリアライザーとなります。
Mirageには、3つの名前付きシリアライザーが用意されています。
JSONAPISerializer は、JSON:API準拠のAPIサーバーをシミュレートします。
import { Server, JSONAPISerializer } from 'miragejs'; new Server({ serializers: { application: JSONAPISerializer } })
ActiveModelSerializer は、AMSスタイルのレスポンスを使用するRails APIをモックします。
import { Server, ActiveModelSerializer } from 'miragejs'; new Server({ serializers: { application: ActiveModelSerializer } })
RestSerializer は、多くの一般的なREST APIの出発点として適しています。
import { Server, RestSerializer } from 'miragejs'; new Server({ serializers: { application: RestSerializer } })
さらに、Mirageには基本的なSerializerクラスがあり、以下に記載されているフックを使用してカスタマイズできます。
import { Server, Serializer } from 'miragejs';
new Server({
serializers: {
application: Serializer
}
})
モデル固有のシリアライザーを作成する際には、共有ロジックがモデル固有のクラスで使用されるように、アプリケーションシリアライザーから拡張することを忘れないでください。
import { Server, Serializer } from 'miragejs';
const ApplicationSerializer = Serializer.extend()
new Server({
serializers: {
application: ApplicationSerializer,
blogPost: ApplicationSerializer.extend({
include: ['comments']
})
}
})
プロパティ
schema: オブジェクト
スキーマインスタンスへの参照。
登録されたスキーマ情報を参照するのに役立ちます。たとえば、シリアライザーの`include`フックで、リソースのすべての関連付けを含める場合などです。
Serializer.extend({
include(request, resource) {
return Object.keys(this.schema.associationsFor(resource.modelName));
}
})
attrs: 任意
モデルシリアライザーで、JSONペイロードで使用される属性をホワイトリストするために使用します。
たとえば、データベースに次の様なblog-post
モデルがあるとします。
{
id: 1,
title: 'Lorem ipsum',
createdAt: '2014-01-01 10:00:00',
updatedAt: '2014-01-03 11:42:12'
}
そして、id
とtitle
だけが必要な場合は、次のように記述できます。
Serializer.extend({
attrs: ['id', 'title']
});
すると、ペイロードは次のようになります。
{
id: 1,
title: 'Lorem ipsum'
}
embed: 任意
関連モデルを埋め込むか、サイドロードするかどうかを設定します。
JSONAPISerializerには適用されません。
デフォルトではfalseなので、リレーションシップはサイドロードされます。
GET /authors/1
{
author: {
id: 1,
name: 'Link',
blogPostIds: [1, 2]
},
blogPosts: [
{ id: 1, authorId: 1, title: 'Lorem' },
{ id: 2, authorId: 1, title: 'Ipsum' }
]
}
embed
をtrueに設定すると、関連レコードが埋め込まれます。
Serializer.extend({
embed: true
});
レスポンスは次のようになります。
GET /authors/1
{
author: {
id: 1,
name: 'Link',
blogPosts: [
{ id: 1, authorId: 1, title: 'Lorem' },
{ id: 2, authorId: 1, title: 'Ipsum' }
]
}
}
include: 任意
モデルシリアライザーで、JSONペイロードに含めたい関連モデルを指定するために使用します。(これらは、デフォルトのサーバーサイドインクルードと見なすことができます。)
たとえば、多くのblog-post
を持つauthor
があり、これらをサイドロードしたい場合は、include
キーで指定します。
new Server({
models: {
author: Model.extend({
blogPosts: hasMany()
})
},
serializers: {
author: Serializer.extend({
include: ['blogPosts']
});
}
})
すると、authorのリクエストに対するレスポンスは次のようになります。
GET /authors/1
{
author: {
id: 1,
name: 'Link',
blogPostIds: [1, 2]
},
blogPosts: [
{id: 1, authorId: 1, title: 'Lorem'},
{id: 2, authorId: 1, title: 'Ipsum'}
]
}
include
を関数として定義して、動的に決定することもできます。
たとえば、include
クエリパラメーターに基づいて、条件付きでリレーションシップを含めることができます。
// Include blog posts for a GET to /authors/1?include=blogPosts
Serializer.extend({
include: function(request) {
if (request.queryParams.include === "blogPosts") {
return ['blogPosts'];
} else {
return [];
}
}
});
JSONAPISerializerのクエリパラメーターインクルード
JSONAPISerializerは、include
クエリパラメーターを使用して、すぐに複合ドキュメントを返すことをサポートしています。
たとえば、アプリが次のリクエストを行う場合
GET /api/authors?include=blogPosts
JSONAPISerializer
はリクエストのクエリパラメーターを検査し、blogPostsリレーションシップが存在することを確認し、このリレーションシップがシリアライザー自体の`include: []`配列に直接指定されているかのように処理を続けます。
仕様に従って、Mirageは、シリアライザーに直接指定されている可能性のあるデフォルトの`include: []`配列よりも、`?include`クエリパラメーターを優先します。ただし、リクエストに`?include`クエリパラメーターがない場合は、デフォルトのインクルードが有効なままです。
また、include: []
配列で指定されたデフォルトのインクルードは、単一のモデルのみを受け入れることができ、ネストされたリレーションシップへのドット区切りのパスを受け入れることはできません。
リソースのデフォルトのドット区切り(ネストされた)インクルードパスを設定する場合は、request.queryParams
のデフォルト値を設定することで、ルートレベルで行う必要があります。
this.get('/users', function(schema, request) => {
request.queryParams = request.queryParams || {};
if (!request.queryParams.include) {
request.queryParams.include = 'blog-posts.comments';
}
// rest of route handler logic
});
root: 任意
JSONレスポンスにルートキーを含めるかどうかを設定します。
JSONAPISerializerには適用されません。
デフォルトはtrueなので、authorのリクエストは次のようになります。
GET /authors/1
{
author: {
id: 1,
name: 'Link'
}
}
root
をfalseに設定すると、これが無効になります。
Serializer.extend({
root: false
});
レスポンスは次のようになります。
GET /authors/1
{
id: 1,
name: 'Link'
}
serializeIds: 任意
シリアライザーがリレーションシップキーのシリアライズをどのように処理するかを定義するために使用します。3つの値のいずれかを取ることができます。
included
(デフォルト)は、リレーションシップがモデルまたはコレクションと共にレスポンスに含まれている場合(サイドロードされている場合)、そのリレーションシップのIDをシリアライズします。always
は、レスポンス内のモデルまたはコレクションのすべてのリレーションシップのIDを常にシリアライズします。never
は、レスポンス内のモデルまたはコレクションのリレーションシップのIDをシリアライズしません。
メソッド
keyForAttribute(attr: 任意): 任意
モデルの属性がJSONペイロードでどのようにフォーマットされるかをカスタマイズするために使用します。
デフォルトでは、モデル属性はcamelCaseです。
GET /authors/1
{
author: {
firstName: 'Link',
lastName: 'The WoodElf'
}
}
APIがsnake_caseを期待する場合は、次のように記述できます。
// serializers/application.js
export default Serializer.extend({
keyForAttribute(attr) {
return underscore(attr);
}
});
レスポンスは以下のようになります。
{
author: {
first_name: 'Link',
last_name: 'The WoodElf'
}
}
keyForCollection(modelName: any): any
プライマリコレクションをシリアライズする際のキーをカスタマイズするために使用します。デフォルトでは、keyForModel
の戻り値の複数形になります。
例えば、デフォルトでは以下のリクエストのようになります。
GET /blogPosts
{
blogPosts: [
{
id: 1,
title: 'Lorem ipsum'
},
...
]
}
APIがキーにハイフンを使用する場合、keyForCollection
をオーバーライドできます。
// serializers/application.js
export default Serializer.extend({
keyForCollection(modelName) {
return this._container.inflector.pluralize(dasherize(modelName));
}
});
レスポンスは以下のようになります。
{
'blog-posts': [
{
id: 1,
title: 'Lorem ipsum'
},
...
]
}
keyForEmbeddedRelationship(attributeName: any): any
keyForRelationship
と同様ですが、埋め込み関係の場合です。
keyForForeignKey(relationshipName: any): any
keyForRelationshipIds
と同様ですが、belongsTo
関係の場合です。
例えば、blogPost
をシリアライズしていて、1つのauthor
をサイドロードする場合、blogPost
のJSONにはauthorId
キーが含まれます。
{
blogPost: {
id: 1,
authorId: 1
},
author: ...
}
keyForForeignKey
をオーバーライドして、このキーのフォーマットを変更します。
// serializers/application.js
export default Serializer.extend({
keyForForeignKey(relationshipName) {
return underscore(relationshipName) + '_id';
}
});
レスポンスは以下のようになります。
{
blogPost: {
id: 1,
author_id: 1
},
author: ...
}
keyForModel(modelName: any): any
modelName modelNameのプライマリモデルをシリアライズする際のキーをカスタマイズするために使用します。例えば、デフォルトのSerializerは以下のようになります。
GET /blogPosts/1
{
blogPost: {
id: 1,
title: 'Lorem ipsum'
}
}
APIがハイフン付きキーを使用する場合、keyForModel
をオーバーライドできます。
// serializers/application.js
export default Serializer.extend({
keyForModel(modelName) {
return hyphenate(modelName);
}
});
レスポンスは以下のようになります。
{
'blog-post': {
id: 1,
title: 'Lorem ipsum'
}
}
keyForPolymorphicForeignKeyId(relationshipName: String): String
ポリモーフィックなリレーションシップは、タイプとIDのペアで表現されます。
以下のモデルの場合
Model.extend({
commentable: belongsTo({ polymorphic: true })
});
デフォルトのSerializerは以下のようになります。
{
comment: {
id: 1,
commentableType: 'post',
commentableId: '1'
}
}
このフックは、id
フィールド(上記の例ではcommentableId
)のシリアライズ方法を制御します。デフォルトでは、リレーションシップをキャメルケースに変換し、Id
をサフィックスとして追加します。
keyForPolymorphicForeignKeyType(relationshipName: String): String
ポリモーフィックなリレーションシップは、タイプとIDのペアで表現されます。
以下のモデルの場合
Model.extend({
commentable: belongsTo({ polymorphic: true })
});
デフォルトのSerializerは以下のようになります。
{
comment: {
id: 1,
commentableType: 'post',
commentableId: '1'
}
}
このフックは、type
フィールド(上記の例ではcommentableType
)のシリアライズ方法を制御します。デフォルトでは、リレーションシップをキャメルケースに変換し、Type
をサフィックスとして追加します。
keyForRelationship(modelName: any): any
このモデルに関連するコレクションのキーのフォーマットを変更するために使用します。modelNameは、リレーションシップの名前付きパラメーターです。
例えば、多くのblogPosts
をサイドロードするauthor
をシリアライズする場合、デフォルトのレスポンスは以下のようになります。
{
author: {...},
blogPosts: [...]
}
keyForRelationship
をオーバーライドして、このキーのフォーマットを変更します。
// serializers/application.js
export default Serializer.extend({
keyForRelationship(modelName) {
return underscore(modelName);
}
});
レスポンスは以下のようになります。
{
author: {...},
blog_posts: [...]
}
keyForRelationshipIds(modelName: any): any
このモデルのJSON表現におけるhasMany
関係のIDのキーのフォーマットを変更するために使用します。
例えば、多くのblogPosts
をサイドロードするauthor
をシリアライズする場合、デフォルトではauthor
のJSONにはblogPostIds
キーが含まれます。
{
author: {
id: 1,
blogPostIds: [1, 2, 3]
},
blogPosts: [...]
}
keyForRelationshipIds
をオーバーライドして、このキーのフォーマットを変更します。
// serializers/application.js
export default Serializer.extend({
keyForRelationshipIds(relationship) {
return underscore(relationship) + '_ids';
}
});
レスポンスは以下のようになります。
{
author: {
id: 1,
blog_post_ids: [1, 2, 3]
},
blogPosts: [...]
}
normalize(json: any): any
このメソッドは、POSTおよびPUTショートハンドで使用されます。これらのショートハンドは、適切なリソースの作成または更新方法を知るために、リクエストの一部として有効なJSON:APIドキュメントを期待します。normalizeメソッドを使用すると、リクエストボディをJSON:APIドキュメントに変換できるため、それ以外では使用できないショートハンドを利用できます。
JSON:APIを既に使用している場合は、このメソッドはnoopになります。POSTおよびPUTリクエストと共に送信されたリクエストペイロードは、既に正しい形式になっているためです。
例として、含まれているActiveModelSerializer
のnormalizeメソッドを参照してください。
serialize(primaryResource: any, request: any): Object
独自の カスタムシリアライズ関数を実装するには、このメソッドをオーバーライドします。responseは、ルートハンドラーから返されたものであり、requestはPretenderのリクエストオブジェクトです。
プレーンなJavaScriptオブジェクトまたは配列を返し、MirageはこれをアプリのXHRリクエストへのレスポンスデータとして使用します。
このメソッドをオーバーライドし、superを呼び出して、Mirageが応答する前にデータを操作することもできます。これは、メタデータの追加や、Mirageの他の抽象化にうまく適合しない一括処理に最適な場所です。
serialize(object, request) {
// This is how to call super, as Mirage borrows [Backbone's implementation of extend](http://backbonejs.org/#Model-extend)
let json = Serializer.prototype.serialize.apply(this, arguments);
// Add metadata, sort parts of the response, etc.
return json;
}