序列化器

序列化器负责格式化你的路由处理程序的响应。

应用程序序列化器将应用于每个响应。要进行特定自定义,请定义每个模型序列化器。

import { Server, RestSerializer } from 'miragejs';

new Server({
  serializers: {
    application: RestSerializer,
    user: RestSerializer.extend({
      // user-specific customizations
    })
  }
})

从路由处理程序返回的任何模型或集合都将通过序列化器层。模型特定序列化器将具有最高优先级,然后是应用程序序列化器,最后是默认序列化器。

Mirage 附带了三个命名序列化器

  • 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 还有一个基本的序列化器类,你可以使用下面记录的钩子对其进行自定义

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: 对象

对 schema 实例的引用。

它有助于引用注册的 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'
}

并且你只想使用 idtitle,你可以写

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-postauthor,并且你想侧加载它们,请在 include 键中指定

new Server({
  models: {
    author: Model.extend({
      blogPosts: hasMany()
    })
  },
  serializers: {
    author: Serializer.extend({
      include: ['blogPosts']
    });
  }
})

现在对作者请求的响应将看起来像这样

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,因此对作者的请求看起来像

GET /authors/1

{
  author: {
    id: 1,
    name: 'Link'
  }
}

root 设置为 false 将禁用它

Serializer.extend({
  root: false
});

现在响应看起来像

GET /authors/1

{
  id: 1,
  name: 'Link'
}

serializeIds: 任何

使用它来定义你的序列化器如何处理序列化关系键。它可以取三个值之一

  • included 是默认值,如果关系与模型或集合一起包含(侧加载)在响应中,它将序列化关系的 ID
  • always 将始终序列化响应中模型或集合的所有关系的 ID
  • never 永远不会序列化模型或集合中关系的 ID

方法

keyForAttribute(attr: 任何): 任何

用于自定义在你的 JSON 负载中格式化模型属性的方式。

默认情况下,模型属性为 camelCase

GET /authors/1

{
  author: {
    firstName: 'Link',
    lastName: 'The WoodElf'
  }
}

如果你的 API 期望蛇形大小写,你可以写下以下内容

// serializers/application.js
export default Serializer.extend({
  keyForAttribute(attr) {
    return underscore(attr);
  }
});

现在响应将看起来像

{
  author: {
    first_name: 'Link',
    last_name: 'The WoodElf'
  }
}

keyForCollection(modelName: 任何): 任何

用于在序列化主集合时自定义键。默认情况下,这会将 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: 任何): 任何

keyForRelationship 类似,但用于嵌入式关系。

keyForForeignKey(relationshipName: any): any

类似于 keyForRelationshipIds,但适用于 belongsTo 关系。

例如,如果您要序列化一个包含一个 authorblogPost,您的 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 的主模型时定义自定义键。例如,默认序列化器将返回类似以下内容

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 })
});

默认序列化器将生成

{
  comment: {
    id: 1,
    commentableType: 'post',
    commentableId: '1'
  }
}

此钩子控制如何序列化 id 字段(在上面的示例中为 commentableId)。默认情况下,它会将关系转换为驼峰式命名并添加 Id 作为后缀。

keyForPolymorphicForeignKeyType(relationshipName: String): String

多态关系使用类型-ID 对表示。

给定以下模型

Model.extend({
  commentable: belongsTo({ polymorphic: true })
});

默认序列化器将生成

{
  comment: {
    id: 1,
    commentableType: 'post',
    commentableId: '1'
  }
}

此钩子控制如何序列化 type 字段(在上面的示例中为 commentableType)。默认情况下,它会将关系转换为驼峰式命名并添加 Type 作为后缀。

keyForRelationship(modelName: any): any

使用此钩子来格式化与该模型相关的集合的键。 modelName 是关系的命名参数。

例如,如果您要序列化一个包含多个 blogPostsauthor,默认响应将类似于

{
  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 的键。

例如,如果您要序列化一个包含多个 blogPostsauthor,默认情况下,您的 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,此方法将不起作用,因为与 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](https://backbone.npmjs.net.cn/#Model-extend)
  let json = Serializer.prototype.serialize.apply(this, arguments);

  // Add metadata, sort parts of the response, etc.

  return json;
}