How to use adapters, serializers, models and other tools in Ember more effectively?

I have an app based on Ember Data . I would like to figure out how to make the code more compact. My application looks like this:: there are several endpoints that from the Express server. In the Ember application, each endpoint corresponds to: adapter, serializer, model, route, template . Everything works fine, but the code is too cumbersome. I’m new to Ember, and maybe there is a way to use adapters and other tools more universally. Here are some parts of my application that illustrate how it works.

localhost:5000/api/cars

localhost:5000/api/vehicles

Adapter “cars”:

import RESTAdapter from '@ember-data/adapter/rest';
export default RESTAdapter.extend({
  host: http://localhost:5000/api,
  pathForType() {
    return "cars";
  }
});

Adapter “vehicles”:

import RESTAdapter from '@ember-data/adapter/rest';
export default RESTAdapter.extend({
  host: http://localhost:5000/api,
  pathForType() {
    return "vehicles";
  }
});

Serializer “cars”:

import RESTSerializer from '@ember-data/serializer/rest';
export default RESTSerializer.extend({
  normalizeResponse(store, primaryModelClass, payload, id, requestType) {
    payload = {
      cars: payload
    };
    return this._super(store, primaryModelClass, payload, id, requestType);
  },
  primaryKey: '_id'
});

Serializer “vehicles”:

import RESTSerializer from '@ember-data/serializer/rest';
export default RESTSerializer.extend({
  normalizeResponse(store, primaryModelClass, payload, id, requestType) {
    payload = {
      vehicles: payload
    };
    return this._super(store, primaryModelClass, payload, id, requestType);
  },
  primaryKey: '_id'
});

Car model:

import DS from 'ember-data';
const { attr } = DS;
export default DS.Model.extend({
  name: attr("string"),
  body: attr("array"),
  date: attr('date')
});

Vehicle model (the same as car!):

import DS from 'ember-data';
const { attr } = DS;
export default DS.Model.extend({
  name: attr("string"),
  body: attr("array"),
  date: attr('date')
});

Cars index route:

import Route from '@ember/routing/route';
export default class CarsIndexRoute extends Route {
  model() {
    return this.store.findAll("car");
  }
}

Vehicles index route:

import Route from '@ember/routing/route';
export default class VehiclesIndexRoute extends Route {
  model() {
    return this.store.findAll("vehicle");
  }
}

Hbs templates are completely similar. cars/index.hbs (and vehicles/index.hbs):

{{#each @model as |item|}}
<h3>{{item.name}}</h3>
<p>{{item.body}}</p>
{{/each}}

The code clearly shows that the structure is the same, and the differences are only in one parameter, which corresponds to the model name and the “end” of the api endpoint. Can someone tell me how to organize everything more correctly, in the tradition of Ember? Thanks!

The first thing that jumps to mind is that you probably don’t need all three adapters. I think your “path for type” is actually the default so if you just have one application adapter with the host prop set it should cover this.

For the serializers… I guess it depends on your API response a little more, and i’m a little rusty, but you may be able to extend the json serializer (@ember-data/serializers/json) instead and not have to override normalizeResponse anymore. Then you could use an application serializer instead of per-model serializers and just set the primaryKey prop.

The models… you could probably use a “base” model and inheritance if you wanted but I’m not sure I’d recommend that as a great pattern unless you’re sure they will always be exactly the same.

The routes look fine and I wouldn’t bother trying to consolidate any of that code. Honestly none of what you posted above is really that bad, but I get that you don’t want to repeat yourself a lot so you could definitely trim some of it down.

1 Like