I'm a bit confused about serializers

#1

I have a data source that returns JSON in something of a mix between what the documentation describes as the JSONSerializer and JSONAPISerializer.

The return has a root attribute but no type information:

{"data":[
	{"id":1,"name":"Blue"},
	{"id":4,"name":"Red"},
	{"id":5,"name":"Green"},
	{"id":3,"name":"Yellow"},
	{"id":2,"name":"Purple"}
	]
}

This obviously produces a problem with either of the serializers because it has a root (which the same across all models - it is always data) but no type information. The root causes it to error for the other serializer because it doesn’t expect one to be there.

Changing the data source isn’t really an option for me but the only way I can see forward is having to make a custom serializer for each model in the application to account for the root and lack of type. I really don’t want to do that!

Any advice appreciated

#2

I don’t have specifics, but with that kind of data, you’d need to make either make a serializer/adapter per-model that sets the type, or derive the type from the URL or model class.

You’d want to use the JSONSerializer, as the JSONAPISerializer is for jsonapi.org formatted json payloads.

If you haven’t seen this yet, it’s very useful: https://guides.emberjs.com/release/models/customizing-serializers/#toc_customizing-serializers

Note that ember-data uses jsonapi.org -formatted data internally, so when you translate your data from your API, you’ll be building a jsonapi.org Document.

1 Like
#3

Yes, serializers are unfortunately described in a confusing way and have a lot of API surface that I would honestly prefer to deprecate. There is a very clear and simple way to understand and use serializers, but it’s hard to see from looking at the docs and guides.

The rules are simple:

  1. Always extend from JSONAPISerializer. It’s quite irrelevant what the shape of your backend data is, just always use JSONAPISerializer. The reason I say this is that there is no spec describing what constitutes the format(s) JSONSerializer supports, so it’s hard to be sure you’re doing things right. Whereas the JSONAPI spec is very clear.

  2. The only methods you truly need to understand and possibly implement are:

    • normalizeResponse: receives whatever your server sends, and must return a standard JSON:API document.
    • serialize: receives a standard JSON:API document, and must return the format you want to actually send to your server.

Using serializers in this way, your job is clear: write a function that converts your custom server output into a JSON:API compliant format.

4 Likes
#4

Thanks for that, putting serializers in context like that was really helpful.

In the end it was much simpler to bypass the root object and return payload.data in the args of normalizeResponse:

    normalizeResponse(store, primaryModelClass, payload, id, requestType) {      
         return this._super(store, primaryModelClass, payload.data, id, requestType);
    }

At least at this early, scaffolding phase of my project.