Coding With Fun
Home Docker Django Node.js Articles Python pip guide FAQ Policy

Ember custom serial number


May 09, 2021 Ember.js Reference documents


Table of contents


In an Ember app, the serializer formats the data that interacts with the background, including the data sent and received. T he JSON API serializes the data by default. If your back end uses a different format, Ember Data allows you to customize the serializer or define a completely different serializer.

Ember Data has three serializers built in. r is the default serializer used with the back-end JSON API. r is a simple serializer that is used to work with a single JSON object or an array of records. RESTSerializer is a complex serializer that supports side loading and was the default serializer before Ember Data 2.0.

JSON APISerializer specification

When you request data from the server, JSONSerializer considers the data returned by the server to be JSON data that conforms to the following specifications.

Note: Especially if the project is using a custom adapter, the data format returned in the background must comply with the JSOP API specification, otherwise the CRUD operation of the data cannot be implemented, Ember will not be able to parse the data, the knowledge of the custom adapter can be seen in the previous Ember.js Getting Started Guide 44 custom adapter, in the article there is a detailed description of the custom adapter and custom serializer is closely related.

1, JSON API documentation

JSONSerializer expects a JSON document that complies with the JSON API specifications and conventions returned in the background. For example, the following JSON data, the format of these data is like this:

  1. Type specifies the name of the model
  2. Property names are separated by middle dashes

For example, /people/123 response data is as follows:

  1. {
  2. "data": {
  3. "type": "people",
  4. "id": "123",
  5. "attributes": {
  6. "first-name": "Jeff",
  7. "last-name": "Atwood"
  8. }
  9. }
  10. }

If there are multiple datas in the data will be returned as an array.

  1. {
  2. "data": [
  3. {
  4. "type": "people",
  5. "id": "123",
  6. "attributes": {
  7. "first-name": "Jeff",
  8. "last-name": "Atwood"
  9. }
  10. },{
  11. "type": "people",
  12. "id": "124",
  13. "attributes": {
  14. "first-name": "chen",
  15. "last-name": "ubuntuvim"
  16. }
  17. }
  18. ]
  19. }

2, copy the data

Data is sometimes not the subject of a request if the data is linked. Linked relationships are placed included

  1. {
  2. "data": {
  3. "type": "articles",
  4. "id": "1",
  5. "attributes": {
  6. "title": "JSON API paints my bikeshed!"
  7. },
  8. "links": {
  9. "self": "http://example.com/articles/1"
  10. },
  11. "relationships": {
  12. "comments": {
  13. "data": [
  14. { "type": "comments", "id": "5" },
  15. { "type": "comments", "id": "12" }
  16. ]
  17. }
  18. }
  19. }],
  20. "included": [{
  21. "type": "comments",
  22. "id": "5",
  23. "attributes": {
  24. "body": "First!"
  25. },
  26. "links": {
  27. "self": "http://example.com/comments/5"
  28. }
  29. }, {
  30. "type": "comments",
  31. "id": "12",
  32. "attributes": {
  33. "body": "I like XML better"
  34. },
  35. "links": {
  36. "self": "http://example.com/comments/12"
  37. }
  38. }]
  39. }

As you can see from the id the comment link with comment 5 "self": http://example.com/comments/5 T he comment link with comment id 12 "self": http://example.com/comments/12 And these links are placed included

3, custom serializer

Ember Data's default serializer is JSON APISerializer, but you can also customize the serializer to override the default serializer.

To customize the serializer, first define an entry application the application serializer.

Build directly with commands: ember g serializer application

  1. // app/serializers/application.js
  2. import DS from 'ember-data';
  3. export default DS.JSONSerializer.extend({
  4. });

You can even define a serializer for a model. For example, the following code defines a specialized serializer for post which is related to how to customize an adapter for a model in the previous custom adapter.

  1. // app/serializers/post.js
  2. import DS from ember-data’;
  3. export default DS.JSONSerializer.extend({
  4. });

If you want to change the JSON data format sent to the back end, you just serialize callback and format the data in the callback.

For example, the data format sent by the front end is the following structure,

  1. {
  2. "data": {
  3. "attributes": {
  4. "id": "1",
  5. "name": "My Product",
  6. "amount": 100,
  7. "currency": "SEK"
  8. },
  9. "type": "product"
  10. }
  11. }

But the data structure accepted by the server is the following:

  1. {
  2. "data": {
  3. "attributes": {
  4. "id": "1",
  5. "name": "My Product",
  6. "cost": {
  7. "amount": 100,
  8. "currency": "SEK"
  9. }
  10. },
  11. "type": "product"
  12. }
  13. }

At this point you can serialize callback.

  1. // app/serializers/application.js
  2. import DS from 'ember-data';
  3. export default DS.JSONSerializer.extend({
  4. serialize: function(snapshot, options) {
  5. var json = this._super(...arguments); // ??
  6. json.data.attributes.cost = {
  7. amount: json.data.attributes.amount,
  8. currency: json.data.attributes.currency
  9. };
  10. delete json.data.attributes.amount;
  11. delete json.data.attributes.currency;
  12. return json;
  13. }
  14. });

So what if it's the other way around? If the data returned by the backend is in the following format:

  1. {
  2. "data": {
  3. "attributes": {
  4. "id": "1",
  5. "name": "My Product",
  6. "cost": {
  7. "amount": 100,
  8. "currency": "SEK"
  9. }
  10. },
  11. "type": "product"
  12. }
  13. }

However, the format required by the front end is:

  1. {
  2. "data": {
  3. "attributes": {
  4. "id": "1",
  5. "name": "My Product",
  6. "amount": 100,
  7. "currency": "SEK"
  8. },
  9. "type": "product"
  10. }
  11. }

At this point, you can override the callback method normalizeResponse normalize to format the data in the method:

  1. // app/serializers/application.js
  2. import DS from 'ember-data';
  3. export default DS.JSONSerializer.extend({
  4. normalizeResponse: function(store, primaryModelClass, payload, id, requestType) {
  5. payload.data.attributes.amount = payload.data.attributes.cost.amount;
  6. payload.data.attributes.currency = payload.data.attributes.cost.currency;
  7. delete payload.data.attributes.cost;
  8. return this._super(...arguments);
  9. }
  10. });

4, data ID properties

Each data has a unique value as the ID and by default Ember adds a property id each model. If you want to change to a different name, you can specify it in the serializer.

  1. // app/serializers/application.js
  2. import DS from 'ember-data';
  3. export default DS.JSONSerializer.extend({
  4. primatyKey: '__id'
  5. });

Change the data primary key name __id .

5, property name

The property names agreed upon by Ember Data are hump-like naming, but the serializer expects a middle-line-separated naming method, although Ember converts automatically and does not require manual designation by the developer. H owever, if you want to modify this default method, you can simply use the keyForAttributes the serializer to specify the separation you prefer. For example, the following code changes the property name of the serial number to the following dashed separation:

  1. // app/serializers/application.js
  2. import DS from 'ember-data';
  3. export default DS.JSONSerializer.extend({
  4. keyForAttributes: function(attr) {
  5. return Ember.String.underscore(attr);
  6. }
  7. });

6, specifies the alias of the property name

If you want to specify an alias for a model property when the model data is serialized and deserated, specify it attrs property.

  1. // app/models/person.js
  2. export default DS.Model.extend({
  3. lastName: DS.attr(‘string’)
  4. });

Specify serialized, anti-serialized property alias:

  1. // app/serializers/application.js
  2. import DS from 'ember-data';
  3. export default DS.JSONSerializer.extend({
  4. attrs: {
  5. lastName: lastNameOfPerson
  6. }
  7. });

Specify the model property lastNameOfPerson

7, the association between models

One model refers ID model by ID. For example, there are two models with a one-to-many relationship:

  1. // app/models/post.js
  2. export default DS.Model.extend({
  3. comments: DS.hasMany(‘comment’, { async: true });
  4. });

The serialized JSON data format is as follows, where the association is implemented through ID property values.

  1. {
  2. "data": {
  3. "type": "posts",
  4. "id": "1",
  5. "relationships": {
  6. "comments": {
  7. "data": [
  8. { "type": "comments", "id": "5" },
  9. { "type": "comments", "id": "12" }
  10. ]
  11. }
  12. }
  13. }
  14. }

As you can see, there are two comment associated with post post. In belongsTo relationship, the JSON structure is not much different from the hadMany relationship. hadMany

  1. {
  2. "data": {
  3. "type": "comment",
  4. "id": "1",
  5. "relationships": {
  6. "original-post": {
  7. "data": { "type": "post", "id": "5" },
  8. }
  9. }
  10. }
  11. }

id an id comment 1 is associated with a post with an ID of 5 post

8, custom conversion rules

In some cases, Ember's built-in property types string number boolean date are still not sufficient. For example, when the server returns a non-standard data format.

Ember Data can register the new JSON converter to deform the data and create it directly using ember g transform coordinate-point

  1. // app/transforms/coordinate-point.js
  2. import DS from 'ember-data';
  3. export default DS.Transform.extend({
  4. deserialize: function(v) {
  5. return [v.get('x'), v.get('y')];
  6. },
  7. serialize: function(v) {
  8. return Ember.create({ x: v[0], y: v[1]});
  9. }
  10. });

Defines a compound property type, which consists of two properties that form a coordinate.

  1. // app/models/curor.js
  2. import DS from 'ember-data';
  3. export default DS.Model.extend({
  4. position: DS.attr(‘coordinate-point’)
  5. });

Custom property types are used in the same way as normal types and are used directly attr method. Finally, when we accept the data returned by the service, the data is shown in the following code:

  1. {
  2. cursor: {
  3. position: [4, 9]
  4. }
  5. }

The model instance is still loaded as a normal object when it is loaded. Y ou can still . The action gets the property value.

  1. var cursor = this.store.findRecord(‘cursor’, 1);
  2. cursor.get(‘position.x’); // => 4
  3. cursor.get(‘position.y’); // => 9

9,JSONSerializer

Not all APIs follow the JSON APISerializer convention through data namespaces and copy relationship records. F or example, the system legacy problem, the original API returned only a simple JSON format is not the JSON APISerializer convention format, at this time you can customize the serializer to adapt to the old interface. And it can also be compatible with the use of RESTAdapter to serial number these simple JSON data.

  1. // app/serializer/application.js
  2. export default DS.JSONSerializer.extend({
  3. // ...
  4. });

10,EMBEDDEDRECORDMIXIN

Although Ember Data encourages you to copy model associations, sometimes when working with legacy APIs, you will find that other model associations are embedded in the JSON that you need to work with. But EmbeddedRecordsMixin you solve this problem.

For post contains an author record.

  1. {
  2. "id": "1",
  3. "title": "Rails is omakase",
  4. "tag": "rails",
  5. "authors": [
  6. {
  7. "id": "2",
  8. "name": "Steve"
  9. }
  10. ]
  11. }

The model associations you can define in are as follows:

  1. // app/serializers/post.js
  2. export default DS.JSONSerialier.extend(DS.EmbeddedRecordsMixin, {
  3. attrs: {
  4. author: {
  5. serialize: records’,
  6. deserialize: records
  7. }
  8. }
  9. });

If you occur the relationship between the object itself needs to be serialized and deserated embedding, you can use the embedded

  1. // app/serializers/post.js
  2. export default DS.JSONSerialier.extend(DS.EmbeddedRecordsMixin, {
  3. attrs: {
  4. author: { embedded: always }
  5. }
  6. });

The serialization and anti-serialization settings have three keywords:

  1. records used to mark that all records are serialized and reserated
  2. ids used to mark ids that are only serialized and deserated records
  3. false used to mark records that do not need to be serialized and reserated

For example, you might find that you want to read an embedded record extract when a JSON payload only includes the identity of the relationship in the serialized record. T his may serialize: ids You can also choose to serialize the relationship serialize: false

  1. export default DS.JSONSerializer.extend(DS.EmbeddedRecordsMixin, {
  2. attrs: {
  3. author: {
  4. serialize: false,
  5. deserialize: 'records'
  6. },
  7. comments: {
  8. deserialize: 'records',
  9. serialize: 'ids'
  10. }
  11. }
  12. });

11, EMBEDDEDRECORDSMIXIN default settings

If you don't attrs to specify the association of the model, EmbeddedRecordsMixin will have the following default behavior:

  1. belongsTo:{serialize: id’, deserialize: id }
  2. hasMany: { serialize: false, deserialize: ids }

12, author the serializer

If your project requires a custom serializer, Ember recommends extending JSONAIPSerializer or JSONSerializer to fulfill your needs. H owever, if you want to completely create a brand new serializer that is different from JSONAIPSerizer and JSONSerializer you can extend DS.Serializer class, but you have to implement three methods:

  1. normalizeResponse
  2. serialize
  3. normalize

Knowing normalized JSON data is important for Ember Data, and these property values will not be automatically updated if the model property names do not conform to the Ember Data specification. I f the returned data is not specified in the model, the data is ignored. For example, as defined this.store.push() method accepts the format shown in the second piece of code.

  1. // app/models/post.js
  2. import DS from 'ember-data';
  3. export default DS.Model.extend({
  4. title: DS.attr(‘string’),
  5. tag: DS.attr(‘string’),
  6. comments: hasMany(‘comment’, { async: true }),
  7. relatedPosts: hasMany(‘post’)
  8. });
  1. {
  2. data: {
  3. id: "1",
  4. type: 'post',
  5. attributes: {
  6. title: "Rails is omakase",
  7. tag: "rails",
  8. },
  9. relationships: {
  10. comments: {
  11. data: [{ id: "1", type: 'comment' },
  12. { id: "2", type: 'comment' }],
  13. },
  14. relatedPosts: {
  15. data: {
  16. related: "/api/v1/posts/1/related-posts/"
  17. }
  18. }
  19. }
  20. }

Each serialized record must be converted correctly to an Ember Data record in this format.
The content of this article is very difficult, belongs to the content of the advanced topic! I f it doesn't matter if you don't understand for a time, you can build your project using firebase, and then look back at this and the 44 custom adapters in the last Ember.js Getting Started Guide, so you don't have to understand! !
By the end of this article, the basics of Ember have been fully covered!!! F rom 2015-08-26 to now just 2 months, the original plan was completed in 3 months, a month ahead of schedule, the reason is that the content behind the difficult, understanding bias! T he quality of the article is also not good, feel the time is relatively hasty, said to save a lot of time! ( This article is rearranged and published, the original version of the blog post was released when Ember or version 2.0, is now 2.5!! /b10>)
Introduction to the intention to introduce APPLICATION CONCERNS and TESTING these two chapters! I t is also possible to change the old Ember todomvc case to Ember 2.0, which is just the right way to practice !!!
Thankfully, the goal: to change the old Ember todomvc case to Ember 2.0, and !!! A nd extended a lot of features about the code situation todos v2, welcome readers to fork to learn! G ive me a star if you think star useful! ! Thank you!!!


The full code of the blog post is placed in Github (the blog post has been modified several times, and the code on the blog post may be different from the github code, but the impact is small!). I f you think the blog post is a bit useful to you, please give me a star on the star project. Yours is definitely the biggest motivation for me!!