Class JSONAPIAdapter

public

The JSONAPIAdapter is the default adapter used by Ember Data. It is responsible for transforming the store's requests into HTTP requests that follow the JSON API format.

JSON API Conventions

The JSONAPIAdapter uses JSON API conventions for building the URL for a record and selecting the HTTP verb to use with a request. The actions you can take on a record map onto the following URLs in the JSON API adapter:

Action HTTP Verb URL
`store.findRecord('post', 123)` GET /posts/123
`store.findAll('post')` GET /posts
Update `postRecord.save()` PATCH /posts/123
Create `store.createRecord('post').save()` POST /posts
Delete `postRecord.destroyRecord()` DELETE /posts/123

Success and failure

The JSONAPIAdapter will consider a success any response with a status code of the 2xx family ("Success"), as well as 304 ("Not Modified"). Any other status code will be considered a failure.

On success, the request promise will be resolved with the full response payload.

Failed responses with status code 422 ("Unprocessable Entity") will be considered "invalid". The response will be discarded, except for the errors key. The request promise will be rejected with a InvalidError. This error object will encapsulate the saved errors value.

Any other status codes will be treated as an adapter error. The request promise will be rejected, similarly to the invalid case, but with an instance of AdapterError instead.

Endpoint path customization

Endpoint paths can be prefixed with a namespace by setting the namespace property on the adapter:

app/adapters/application.js
import JSONAPIAdapter from '@ember-data/adapter/json-api';

export default class ApplicationAdapter extends JSONAPIAdapter {
  namespace = 'api/1';
}

Requests for the person model would now target /api/1/people/1.

Host customization

An adapter can target other hosts by setting the host property.

app/adapters/application.js
import JSONAPIAdapter from '@ember-data/adapter/json-api';

export default class ApplicationAdapter extends JSONAPIAdapter {
  host = 'https://api.example.com';
}

Requests for the person model would now target https://api.example.com/people/1.

Show:

By default the JSONAPIAdapter will send each find request coming from a store.find or from accessing a relationship separately to the server. If your server supports passing ids as a query string, you can set coalesceFindRequests to true to coalesce all find requests within a single runloop.

For example, if you have an initial payload of:

{
  data: {
    id: 1,
    type: 'post',
    relationship: {
      comments: {
        data: [
          { id: 1, type: 'comment' },
          { id: 2, type: 'comment' }
        ]
      }
    }
  }
}

By default calling post.get('comments') will trigger the following requests(assuming the comments haven't been loaded before):

GET /comments/1
GET /comments/2

If you set coalesceFindRequests to true it will instead trigger the following request:

GET /comments?filter[id]=1,2

Setting coalesceFindRequests to true also works for store.find requests and belongsTo relationships accessed within the same runloop. If you set coalesceFindRequests: true

store.findRecord('comment', 1);
store.findRecord('comment', 2);

will also send a request to: GET /comments?filter[id]=1,2

Note: Requests coalescing rely on URL building strategy. So if you override buildURL in your app groupRecordsForFindMany more likely should be overridden as well in order for coalescing to work.

By default the store will try to coalesce all fetchRecord calls within the same runloop into as few requests as possible by calling groupRecordsForFindMany and passing it into a findMany call. You can opt out of this behaviour by either not implementing the findMany hook or by setting coalesceFindRequests to false.

Some APIs require HTTP headers, e.g. to provide an API key. Arbitrary headers can be set as key/value pairs on the RESTAdapter's headers object and Ember Data will send them along with each ajax request. For dynamic headers see headers customization.

app/adapters/application.js
import RESTAdapter from '@ember-data/adapter/rest';
import { computed } from '@ember/object';

export default class ApplicationAdapter extends RESTAdapter {
  headers: computed(function() {
    return {
      'API_KEY': 'secret key',
      'ANOTHER_HEADER': 'Some header value'
    };
  })
}

An adapter can target other hosts by setting the host property.

app/adapters/application.js
import RESTAdapter from '@ember-data/adapter/rest';

export default class ApplicationAdapter extends RESTAdapter {
  host = 'https://api.example.com';
}

Requests for the Post model would now target https://api.example.com/post/.

Endpoint paths can be prefixed with a namespace by setting the namespace property on the adapter:

app/adapters/application.js
import RESTAdapter from '@ember-data/adapter/rest';

export default class ApplicationAdapter extends RESTAdapter {
  namespace = 'api/1';
}

Requests for the Post model would now target /api/1/post/.

If jQuery or nAjax are installed, this property allows fetch to still be used instead when true.