22
Data – Adapters, Serializers, and Transforms

Applications require data going in and out of the interface. Connecting to a data source is an important aspect of developing an application. Otherwise, you have a complex system of forms, events, and listings with no data to display.

In this chapter, you will learn some of the basics of wiring up a data source in Ember. You will use an API created for this book and create an adapter for your application.

This chapter is a little different from the other chapters in the book. It has more information and less coding. However, this chapter will give you an important real-world view of application development with a server and database that may not be under your control. In the next chapter you will return to your regularly scheduled coding.

As mentioned in Chapter 21, adapters are the translators of your application. When you communicate with a data source, your application will need to request and send data in a variety of ways. Ember Data comes with built-in adapter objects to handle some of the most common data scenarios: JSONAPI and generic “RESTful” APIs.

You are going to use the JSONAPIAdapter object to connect to a data source and return JSONAPI-formatted data. The RESTAdapter object is set of methods to work with data formatted from APIs generated from Rails and ActiveRecord plug-ins for Rails.

The JSONAPI spec was created to give API consumers a predictable and scalable pattern for sending and receiving data from servers. While there are numerous server languages – and API object pattern conventions for each – JSONAPI set out to be a pattern any language could use so that front-end applications were not affected by a change in server technology. You can find out more about JSONAPI at its website, jsonapi.org.

In this chapter, you will also learn about security issues as well as serializers, which are the translation layer in the adapter flow. Finally, you will be introduced to transforms, the tool to coerce your data into the types your models expect. Adapters, serializers, and transforms work together as shown in Figure 22.1.

Figure 22.1  Adapter, serializers, and transforms

Adapter, serializers, and transforms

At the end of this chapter, Tracker will look like Figure 22.2.

Figure 22.2  Tracker at the end of this chapter

Tracker at the end of this chapter

Adapters

The Ember team has built their framework with specific conventions in mind. Adapters are a large part of those conventions. The JSONAPIAdapter will communicate with a REST API for all requests originating from the store. Each request will add the model name and appropriate attribute data to a relative path of the domain.

To generate a specific URL for Ajax requests, the adapter needs the properties host and namespace. The adapter makes Ajax requests and expects the JSON responses to be formed with a particular structure. For example, the JSONAPIAdapter would expect a response for witnesses on a GET request to look like this:

{
"links": {
  "self": "http://bnr-tracker-api.herokuapp.com/api/witnesses"
},
"data": [
  {
    "id": "5556013e89ad2a030066f6e0",
    "type": "witnesses",
    "attributes": {
      "lname": "Gandee",
      "fname": "Todd"
    },
    "links": {
      "self": "/api/witnesses/5556013e89ad2a030066f6e0"
    },
    "relationships": {
      "sightings": {
      "data": [],
      "links": {
        "self":
        "/api/witnesses/5556013e89ad2a030066f6e0/relationships/sightings"
        }
      }
    }
  }
]
}

With each response, for example, the type of each object is expected to be the model name requested, in order to resolve all records for that model type. Also, an id is expected to be the primary key for each individual model object.

Begin by generating an application adapter:

ember g adapter application

Your application will be making requests to the Big Nerd Ranch Tracker API. As we have said, the JSONAPIAdapter property values require a host URL and a namespace, which is added to the end of the host when making an Ajax request for model data. Open app/adapters/application.js and declare the host and namespace.

import JSONAPIAdapter from 'ember-data/adapters/json-api';

export default DS.JSONAPIAdapter.extend({
  host: 'https://bnr-tracker-api.herokuapp.com',
  namespace: 'api'
});

Like other Ember classes, naming patterns also apply to adapters – and adapters can be created to customize any model’s API needs. Irregularities in the data structure on the server can be contained in a single adapter rather than forcing all models to conform to edge cases.

What you have added to app/adapters/application.js is a global setting for all data requests. This is all you need for Tracker, because the API is sending all JSON responses from the same host and namespace. But if the witness model, for example, needed a different namespace or host, you could create an app/adapters/witness.js file and configure that particular adapter for witness requests.

Next, you need to retrieve your data from the API via the store. The API has cryptids and witnesses ready to go.

Open app/routes/witnesses.js. Delete the dummy data and replace it with a call to the retrieval method you learned in Chapter 21.

...
  model(){
    let witnessRecord = this.store.createRecord('witness', {
      fname: "Todd",
      lname: "Gandee",
      email: "[email protected]"
    });
    return [witnessRecord];
    return this.store.findAll('witness');
  }
});

Now, restart your application from the terminal with ember server and point your browser to http://​localhost:4200/​witnesses (Figure 22.3).

Figure 22.3  Witnesses listing

Witnesses listing

Like most lifecycle flows in Ember, adapters have a number of methods that get your data from the API to the store and to your routes, controllers, and templates. The purpose of a specific adapter, like the JSONAPIAdapter, is to handle a broad pattern and deal with an expected input/output for each model. Our example uses a Node.js server backed by a MongoDB database using a json-api node module to have API endpoints that work with JSONAPI-spec’d data.

Working with an API that has a specific pattern to follow (with minor edge cases of irregularity) makes for a happy programmer. You also might need to handle some extra data in your request, like authentication or request headers. Adapters can be customized to deal with any scenario.

Ember previously had built-in adapters for other data source scenarios, like localStorage and fixture data. These adapters, and others, are now addons. They can be added via Ember CLI when your model data needs to sync with other sources.

If you find that you have to hack together an adapter, dive into the documentation to find your answers. Some methods and properties of note are: ajaxOptions, ajaxError, handleResponse, and headers.

At this point, your app is making requests to a server to receive a collection of witnesses. Before you move on to reading about the content security policy, serializers, and transforms, you will use the same method, this.store.findAll, to retrieve all the cryptid records from the API. Because there is no view template for cryptids, you will examine the returned records with the Ember Inspector.

Add the method call to app/routes/cryptids.js:

import Ember from 'ember';

export default Ember.Route.extend({
  model(){
    return this.store.findAll('cryptid');
  }
});

Now that you have the data returning, reload the app in the browser and navigate to http://​localhost:4200/​cryptids. Use the Ember Inspector to examine the returning data: In the DevTools, select the Ember tab and click Data, then cryptid(4) (Figure 22.4).

Figure 22.4  Cryptid data

Cryptid data

Up to this point, there has not been a need to use the Ember Inspector in depth. It is used here to show you how to examine in-memory data. Ember retrieves the data from the API and populates the store with the correct model data. When debugging issues with model data, tracing the path of the request can be tedious. The Ember Inspector should be the first place to look when you have this problem.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.17.140