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.
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: ... }.