Serializers are responsible for formatting your route handler’s response.
The application serializer (/mirage/serializers/application.js
) will apply to every response. To make specific customizations, define per-model serializers (e.g. /mirage/serializers/blog-post.js
).
Any Model or Collection returned from a route handler will pass through the serializer layer. Highest priority will be given to a model-specific serializer, then the application serializer, then the default serializer.
Mirage ships with three named serializers:
JSONAPISerializer, to simulate JSON:API compliant servers:
// mirage/serializers/application.js
import { JSONAPISerializer } from 'ember-cli-mirage';
export default JSONAPISerializer;
ActiveModelSerializer, to fake Rails backends that use AMS-style responses:
// mirage/serializers/application.js
import { ActiveModelSerializer } from 'ember-cli-mirage';
export default ActiveModelSerializer;
RestSerializer, to fake backends that match Ember Data’s RestSerializer expected response format:
// mirage/serializers/application.js
import { RestSerializer } from 'ember-cli-mirage';
export default RestSerializer;
Additionally, Mirage has a basic Serializer class which you can customize using the hooks documented below:
// mirage/serializers/application.js
import { Serializer } from 'ember-cli-mirage';
export default Serializer;
When writing model-specific serializers, remember to extend from your application serializer:
// mirage/serializers/blog-post.js
import ApplicationSerializer from './application';
export default ApplicationSerializer.extend({
include: ['comments']
});
Override this method to implement your own custom serialize function. response is whatever was returned from your route handler, and request is the Pretender request object.
Returns a plain JavaScript object or array, which Mirage uses as the response data to your Ember app’s XHR request.
You can also override this method, call super, and manipulate the data before Mirage responds with it. This is a great place to add metadata, or for one-off operations that don’t fit neatly into any of Mirage’s other abstractions:
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;
}
This method is used by the POST and PUT shorthands. These shorthands expect a valid JSON:API document as part of the request, so that they know how to create or update the appropriate resouce. The normalize method allows you to transform your request body into a JSON:API document, which lets you take advantage of the shorthands when you otherwise may not be able to.
Note that this method is a noop if you’re using JSON:API already, since request payloads sent along with POST and PUT requests will already be in the correct format.
Take a look at the included ActiveModelSerializer’s normalize method for an example.
Use this property on a model serializer to whitelist attributes that will be used in your JSON payload.
For example, if you had a blog-post
model in your database that looked like
{
id: 1,
title: 'Lorem ipsum',
created_at: '2014-01-01 10:00:00',
updated_at: '2014-01-03 11:42:12'
}
and you just wanted id
and title
, you could write
// mirage/serializers/blog-post.js
export default Serializer.extend({
attrs: ['id', 'title']
});
and the payload would look like
{
id: 1,
title: 'Lorem ipsum'
}
Use this property on a model serializer to specify related models you’d like to include in your JSON payload.
For example, if you had an author
with many blog-post
s:
// mirage/models/author.js
export default Model.extend({
blogPosts: hasMany()
});
and you wanted to sideload these, specify so in the include
key:
// mirage/serializers/author.js
export default Serializer.extend({
include: ['blogPosts']
});
Now a response to a request for an author would look like this:
GET /authors/1
{
author: {
id: 1,
name: 'Link',
blogPostIds: [1, 2]
},
blogPosts: [
{id: 1, authorId: 1, title: 'Lorem'},
{id: 2, authorId: 1, title: 'Ipsum'}
]
}
You can also define include
as a function so it can be determined dynamically:
// mirage/serializers/author.js
export default Serializer.extend({
include: function(request) {
if (request.queryParams.posts) {
return ['blogPosts'];
} else {
return [];
}
}
});
Note: This is only available when using the JSONAPISerializer.
The JSONAPISerializer supports the use of include
query parameter to return compound documents.
Prior to Ember Data 2.5, you will need to add 'ds-finder-include': true
to your app FEATURES object:
// config/environment.js
var ENV = {
EmberENV: {
FEATURES: {
'ds-finder-include': true
}
}
};
To tell Mirage to sideload blogPosts when we find all authors we can do something like the following:
// routes/authors.js
export default Ember.Route.extend({
model() {
return this.store.findAll('author', {include: 'blogPosts'});
}
}
The above will make a GET request to /api/authors?include=blogPosts
, and then the appropriate Mirage route handler will be invoked. When it comes time to serialize the response, the JSONAPISerializer will inspect the query params of the request, see that the blogPosts relationship is present, and then proceed as if this relationship was specified directly in the include: [] array on the serializer itself.
Note that, in accordance with the spec, Mirage gives precedence to an ?include query param over a default include: [] array that you might have specified directly on the serializer. Default includes will still be in effect, however, if a request does not have an ?include query param.
default true
Set whether your JSON response should have a root key in it.
By default it does, so a request for an author looks like:
GET /authors/1
{
author: {
id: 1,
name: 'Link'
}
}
Setting root
to false disables this:
// mirage/serializers/application.js
export default Serializer.extend({
root: false
});
Now the response looks like:
GET /authors/1
{
id: 1,
name: 'Link'
}
default false
Set whether related models should be embedded or sideloaded.
By default this false, so relationships are sideloaded:
GET /authors/1
{
author: {
id: 1,
name: 'Link',
blogPostIds: [1, 2]
},
blogPosts: [
{id: 1, authorId: 1, title: 'Lorem'},
{id: 2, authorId: 1, title: 'Ipsum'}
]
}
Setting embed
to true will embed related records:
// mirage/serializers/application.js
export default Serializer.extend({
embed: true
});
Now the response looks like:
GET /authors/1
{
author: {
id: 1,
name: 'Link',
blogPosts: [
{id: 1, authorId: 1, title: 'Lorem'},
{id: 2, authorId: 1, title: 'Ipsum'}
]
}
}
Note: this feature was added in 0.2.2.
Use this to define how your serializer handles serializing relationship keys. It can take one of three values:
included
, which is the default, will serialize the ids of a relationship if that relationship is included (sideloaded) along with the model or collection in the responsealways
will always serialize the ids of all relationships for the model or collection in the responsenever
will never serialize the ids of relationships for the model or collection in the responseUsed to define a custom key when serializing a primary model of modelName modelName. For example, the default Serializer will return something like the following:
GET /blogPosts/1
{
blogPost: {
id: 1,
title: 'Lorem ipsum'
}
}
If your API uses hyphenated keys, you could overwrite keyForModel
:
// serializers/application.js
export default Serializer.extend({
keyForModel(modelName) {
return Ember.String.dasherize(modelName);
}
});
Now the response will look like
{
'blog-post': {
id: 1,
title: 'Lorem ipsum'
}
}
Used to customize the key when serializing a primary collection. By default this pluralizes the return value of keyForModel
.
For example, by default the following request may look like:
GET /blogPosts
{
blogPosts: [
{
id: 1,
title: 'Lorem ipsum'
},
...
]
}
If your API hyphenates keys, you could overwrite keyForCollection
:
// serializers/application.js
const { dasherize, pluralize } = Ember.String;
export default Serializer.extend({
keyForCollection(modelName) {
return pluralize(dasherize(modelName));
}
});
Now the response would look like:
{
'blog-posts': [
{
id: 1,
title: 'Lorem ipsum'
},
...
]
}
Used to customize how a model’s attribute is formatted in your JSON payload.
By default, model attributes are camelCase:
GET /authors/1
{
author: {
firstName: 'Link',
lastName: 'The WoodElf'
}
}
If your API expects snake case, you could write the following:
// serializers/application.js
const { underscore } = Ember.String;
export default Serializer.extend({
keyForAttribute(attr) {
return underscore(attr);
}
});
Now the response would look like:
{
author: {
first_name: 'Link',
last_name: 'The WoodElf'
}
}
Use this hook to format the key for collections related to this model. relationship is the named parameter for the relationship.
For example, if you’re serializing an author
that
sideloads many blogPosts
, the default response will look like:
{
author: {...},
blogPosts: [...]
}
Overwrite keyForRelationship
to format this key:
// serializers/application.js
const { underscore } = Ember.String;
export default Serializer.extend({
keyForRelationship(relationship) {
return underscore(relationship);
}
});
Now the response will look like this:
{
author: {...},
blog_posts: [...]
}
Use this hook to format the key for relationship ids in this model’s JSON representation.
For example, if you’re serializing an author
that
sideloads many blogPosts
, your author
JSON would include a blogPostIds
key:
{
author: {
id: 1,
blogPostIds: [1, 2, 3]
},
blogPosts: [...]
}
Overwrite keyForRelationshipIds
to format this key:
// serializers/application.js
const { underscore } = Ember.String;
export default Serializer.extend({
keyForRelationshipIds(relationship) {
return underscore(relationship) + '_ids';
}
});
Now the response will look like:
{
author: {
id: 1,
blog_post_ids: [1, 2, 3]
},
blogPosts: [...]
}
This hook is only available on the JSONAPISerializer.
Use this hook to override the generated type
for the JSON:API resource object. By default, type
will be the plural and dasherized form of the model name.
This hook is only available on the JSONAPISerializer.
Use this hook to add top-level links
data to JSON:API resource objects. The argument is the model being serialized.
// serializers/author.js
import { JSONAPISerializer } from 'ember-cli-mirage';
export default JSONAPISerializer.extend({
links(author) {
return {
'posts': {
related: `/api/authors/${author.id}/posts`
}
};
}
});