Load Ember Data models from a non-REST API

Seldom are our Ember apps perfectly aligned with a RESTful API. Often times we need to make requests to complex non-standard URLs in our backends. For example, a personalized list of tasks for a given user at /api/users/:userId/current.

Where do we start building the URL to invoke the correct API call? And more specifically – what is the proper way to load Ember Data Task models?

JSON into the Store?

When things get hairy with Ember Data, we all know we can appeal to the ultimate request tool: Ember.$.getJSON.

// in some route

model() {
  const user = // get from outer route or service
  return Ember.$.getJSON(`/api/users/${user.id}/current`);
}

And that should be it!

BUUUT… this JSON data will not populate the Store with models!

We would need to insert them into the store like this:

// in some route

model() {
  const user = // get from outer route or service
  return Ember.$.getJSON(`/api/users/${user.id}/current`).then((data) => {
    return this.store.pushPayload('task', data);  // with an appropriate Task serializer
  });
}

There is a more correct and elegant way, though.

Working with Ember Data, not against it

In order to retrieve a specific subset of models, Ember Data provides us with the query function:

// in some route

model() {
  const user = // get from outer route or service
  return this.store.query('task', { userId: user.id });
}

As a great plus, we get all configuration (namespace, custom headers, etc) for free when working with an adapter.

Assuming the API namespace is /api, this query will resolve to an URL like /api/tasks?userId=1. But that is not at all what we need! Our backend endpoint listens at /api/users/:userId/current.

Note: If you need to apply a query-param-based filter to an association instead, read Adding query parameters to a hasMany relationship.

So let’s instruct Ember Data to:

Translating these requirements into code-speak:

// app/adapters/task.js

urlForQuery(query) {
  if (query.userId) {
    return `${this.urlPrefix()}/users/${query.userId}/current`;
  }
  return this._super(...arguments);
}

urlForQuery is the correct place to manipulate the string for a query URL in any way we want.

For a longer article about these kind of customizations, see Fit Any Backend Into Ember with Custom Adapters & Serializers.

Enjoyed this article? Don't miss my next one!

Leave me your e-mail for content that will help you master Ember:

Do you want to master Ember fast?

Leave me your e-mail for helpful updates delivered straight to your inbox.

(A few e-mails per month. No BS. Unsubscribe anytime!)