Serializers

Shape Payloads Into Records

Serializers

A serializer maps your API payload into the internal record format. JSONAPISerializer is default and RESTSerializer handles nested-object APIs.

4 min read Level 3/5 #ember#ember-data#serializers
What you'll learn
  • Subclass per type at app/serializers/post.js
  • Override normalizeResponse for shape changes
  • Use attrs and keyForAttribute for renames

If the adapter is the HTTP layer, the serializer is the translation layer. It converts between the JSON your API speaks and the normalized shape Ember Data stores internally.

The Default

JSONAPISerializer expects responses already in JSON-API form:

{
  "data": {
    "type": "posts",
    "id": "1",
    "attributes": { "title": "Hi", "created-at": "2026-05-13" }
  }
}

Renaming Fields

Use the attrs map to translate keys. Here, the API sends created_at but the model has createdAt:

import JSONAPISerializer from '@ember-data/serializer/json-api';

export default class PostSerializer extends JSONAPISerializer {
  attrs = {
    createdAt: 'created_at',
    authorName: 'author_name',
  };
}

Casing Rules

JSON-API recommends dashes; many backends use camelCase or snake_case. Override keyForAttribute:

keyForAttribute(attr) {
  return attr; // keep camelCase as-is
}

REST-Shaped Backends

For payloads like { post: { id, title } } or { posts: [...] }, extend RESTSerializer instead:

import RESTSerializer from '@ember-data/serializer/rest';

export default class ApplicationSerializer extends RESTSerializer {}

normalizeResponse

For wholesale shape changes, override normalizeResponse:

normalizeResponse(store, primaryModelClass, payload, id, requestType) {
  const data = payload.result ?? payload;
  return super.normalizeResponse(store, primaryModelClass, data, id, requestType);
}

Useful when your API wraps everything in { result: ..., meta: ... }.

JSON-API — The Convention →