Skip to content

Commit aa605bb

Browse files
committed
Serializers section
1 parent 4524c1e commit aa605bb

File tree

7 files changed

+167
-0
lines changed

7 files changed

+167
-0
lines changed

app/routes/application.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,16 @@ export default class ApplicationRoute extends Route {
7676
},
7777
],
7878
},
79+
{
80+
id: 'serializers',
81+
subsections: [
82+
{
83+
id: 'general',
84+
classicFiles: ['old.js'],
85+
octaneFiles: ['utils.js', 'app-code.js', 'handler.js'],
86+
},
87+
],
88+
},
7989
];
8090
}
8191
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// File: my-app/components/my-component.js
2+
3+
import { serializeResource } from "my-app/utils/serialization";
4+
import { recordIdentifierFor } from '@ember-data/store';
5+
import { createRecord } from "@ember-data/json-api/request"
6+
7+
// ...
8+
let record = store.createRecord('blog-post', {
9+
title: "My first blog post",
10+
body: "This is the body of my blog post",
11+
createdAt: new Date(),
12+
user: currentUser,
13+
});
14+
15+
const request = createRecord(record);
16+
request.body = JSON.stringify(
17+
serializeResource(
18+
store.cache,
19+
recordIdentifierFor(record)
20+
)
21+
);
22+
23+
await this.store.request(request);
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// File: my-app/utils/my-custom-rest-handler.js
2+
3+
import { normalizeResource } from 'my-app/utils/serialization';
4+
5+
const MyCustomRESTHandler = {
6+
async request(context, next) {
7+
const { content, request } = await next(context.request);
8+
// convert to JSON:API, because EmberData expect it by default (using the JSON:API Cache)
9+
return normalizeResource(content, request.store.schema);
10+
},
11+
};
12+
13+
export default MyCustomRESTHandler;

snippets/serializers/general/old.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import JSONAPISerializer from '@ember-data/serializer/json-api';
2+
3+
export default class ApplicationSerializer extends JSONAPISerializer {
4+
primaryKey = '_id';
5+
6+
keyForAttribute(attr) {
7+
return attr.replace(/_/g, '-'); // blog_post_comment becomes blog-post-comment
8+
}
9+
10+
keyForRelationship(key, relationship) {
11+
return key + 'Ids';
12+
}
13+
14+
serialize(snapshot, options) {
15+
let json = super.serialize(...arguments);
16+
17+
json.data.attributes.cost = {
18+
amount: json.data.attributes.amount,
19+
currency: json.data.attributes.currency,
20+
};
21+
22+
delete json.data.attributes.amount;
23+
delete json.data.attributes.currency;
24+
25+
return json;
26+
}
27+
28+
normalizeResponse(store, primaryModelClass, payload, id, requestType) {
29+
payload.data.attributes.amount = payload.data.attributes.cost.amount;
30+
payload.data.attributes.currency = payload.data.attributes.cost.currency;
31+
32+
delete payload.data.attributes.cost;
33+
34+
return super.normalizeResponse(...arguments);
35+
}
36+
}

snippets/serializers/general/utils.js

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// File: my-app/utils/serialization.js
2+
3+
const keyForAttribute = (attr) => {
4+
return attr.replace(/_/g, '-'); // blog_post_comment becomes blog-post-comment
5+
}
6+
7+
const keyForRelationship = (relationship) => {
8+
return relationship + 'Ids';
9+
}
10+
11+
const serializeResource = (cache, identifier) => {
12+
const body = { _id: identifier.id, type: identifier.type };
13+
14+
if (cache.hasChangedAttrs(identifier)) {
15+
const attrsChanges = cache.changedAttrs(identifier);
16+
17+
Object.keys(attrsChanges).forEach((attr) => {
18+
const change = attrsChanges[attr][1];
19+
body[keyForAttribute(attr)] = change === undefined ? null : change;
20+
});
21+
}
22+
23+
if (cache.hasChangedRelationships(identifier)) {
24+
const relationshipsChanged = cache.changedRelationships(identifier);
25+
if (relationshipsChanged.size) {
26+
relationshipsChanged.forEach((diff, key) => {
27+
body[keyForRelationship(key)] = diff.localState.id;
28+
});
29+
}
30+
}
31+
32+
return body;
33+
};
34+
35+
const normalizeResource = (item, schema) => {
36+
// destructuring and renaming primaryKey from _id to id
37+
const { _id: id, type } = item;
38+
39+
const attributesDefined = schema.attributesDefinitionFor({ type });
40+
const relationshipsDefined = schema.relationshipsDefinitionFor({ type });
41+
42+
const data = { id, type, attributes: {} };
43+
44+
for (const attr of Object.values(attributesDefined)) {
45+
data.attributes[attr.name] = item[attr.name];
46+
}
47+
48+
data.attributes.amount = item.data.attributes.cost.amount;
49+
data.attributes.currency = item.data.attributes.cost.currency;
50+
51+
for (const rel of Object.values(relationshipsDefined)) {
52+
if (Object.hasOwnProperty.call(item, rel.name)) {
53+
data.relationships ??= {};
54+
data.relationships[rel.name] = {
55+
data: {
56+
id: item[rel.name],
57+
type: rel.type,
58+
},
59+
};
60+
}
61+
}
62+
63+
return data;
64+
};
65+
66+
export {
67+
normalizeResource,
68+
serializeResource,
69+
}

translations/serializers/en-us.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
title: Serializers
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
title: Serializers in general
2+
description: |
3+
In order to provide migration support for Adapters and Serializers, a '<code>'LegacyNetworkHandler'</code>' is provided. This handler takes a request and converts it into the older form, calling the appropriate Adapter and Serializer methods. If no serializer exists for the type (including no application serializer), this handler calls '<code>'next'</code>'. In this manner an app can incrementally migrate request-handling to this new paradigm on a per-type basis as desired.
4+
<br />
5+
The package '<code>'ember-data'</code>' automatically configures this handler. If not using the '<code>'ember-data'</code>' package, this configuration needs to be done explicitly.
6+
<br />
7+
We intend to support this handler through at least the 5.x series -- not deprecating its usage before 6.0.
8+
<br />
9+
Similarly, the methods '<code>'adapterFor'</code>' and '<code>'serializerFor'</code>' will not be deprecated until at least 6.0; however, it should no longer be assumed that an application has an adapter or serializer at all.
10+
<br />
11+
Serializers previously was used to accomplish two main things: serialization and normalization.
12+
<br />
13+
Normalization is now done in handlers, before returning the response.
14+
<br />
15+
Serialization can be done in handler, but we encourage application developers to do it in request builder.

0 commit comments

Comments
 (0)