Ember CLI - RESTAdapter for a third-party API

I can get the data in my application with ic.ajax, but it looks like I should use a RESTAdapter. The explanations are so simplified that I'm not sure what to do in different cases. This is what I think should work: (and does it with lights, local express server and http-mocks)

I am going to use tumblr as an example - since it has always been a friendly API in general.

router.js

import Ember from 'ember'; import config from './config/environment'; var Router = Ember.Router.extend({ location: config.locationType }); Router.map(function() { // tumblr posts this.resource('posts', { path: '/tumblr' }); }); export default Router; 

routes /post.js

 import Ember from 'ember'; export default Ember.Route.extend({ model: function() { return this.store.find('post'); } }); 

So, as far as I can tell - find() is some kind of magical ajax call ... but what if I want to specify jsonp or something like that?

adapters /post.js

 import DS from 'ember-data'; var tumblrBlogName = 'feministlibraryonwheels'; // friends site var tumblrApiKey = 'UbB4p0GxqNa6wUa8VwpIdqtywjIiA6vljZXyI9wkx9hnQnAFyk'; var tumblrRequestUrl = 'http://api.tumblr.com/v2/blog/' + tumblrBlogName + '.tumblr.com' + '/posts?api_key=' + tumblrApiKey; export default DS.RESTAdapter.extend({ host: tumblrRequestUrl }); 

This is a bit strange because the long tumblr endpoint thing is so hopeless - I feel it should only be http://api.tumblr.com , and maybe there is another way to specify different stuff ... or is it just like- he knows ... very vaguely ... it looks like a namespace: 'v2' is what this option will be for ...

Templates /posts.hbs

 <section class='container stage'> <div class='inner-w'> <h2>tumblr posts</h2> <ul class='block-list event-list'> {{#each}} <li> {{title}} </li> {{else}} No posts are coming up... what up with that? {{/each}} </ul> </div> </section> 

Then this {{#each}} just knows what it should look for in most cases, but I would like to be explicit.


In all the tutorials I've seen, this is a local server - or http-mocks - and it's something like this:

 import DS from 'ember-data'; export default DS.RESTAdapter.extend({ host: 'localhoststuff:3000', namespace: 'api' }); 

Then on top of this - I get what seems to be a cors GET http://api.tumblr.com/v2/blog/feministlibraryonwheels.tumblr.com/posts?api_key=UbB4p0GxqNa6wUa8VwpIdqtywjIiA6vljZXyI9wkx9hnQnAFyk/posts 401 (Not Authorized) problem GET http://api.tumblr.com/v2/blog/feministlibraryonwheels.tumblr.com/posts?api_key=UbB4p0GxqNa6wUa8VwpIdqtywjIiA6vljZXyI9wkx9hnQnAFyk/posts 401 (Not Authorized)

and he doesn’t really look like him ... [ http://api.tumblr.com/v2/blog/feministlibraryonwheels.tumblr.com/posts?api_key=UbB4p0GxqNa6wUa8VwpIdqtywjIiA6vljZXyI9wkx9hnQAF]

What is the missing link between many quick tutorials - and the RESTAdapter in the real world - with the real API ??? Any direction will be greatly appreciated.

Also, here are some ic.ajax() attempts I have made. The payload hits the console - but when you try to get data in the templates it becomes foggy

 import Ember from 'ember'; import ajax from 'ic-ajax'; export default Ember.Route.extend({ model: function() { var libraryData = ajax({ url: 'http://www.librarything.com/api_getdata.php?userid=FLOW&showstructure=1&showTags=1&booksort=title_REV', type: 'get', dataType: 'jsonp' }); console.log(libraryData); return libraryData; } }); 



EDIT: 2.4 documents are very good. Carbon data is stable. You need to know what type of JSON you get, if it is not a JSON API format, then you need to serialize the data and form it in this format.

+5
source share
3 answers

UPDATE for Ember 1.13.0 , Ember Data 1.13. 0 and above

Tools (adapters and serializers)

To connect to an API that is not compatible with Ember-Data (e.g. tumblr), you must configure an adapter such as RestAdapter or JSONAPIAdapter to create the request properly.

(JSONAPIAdapter is a subclass of RESTAdapter that adjusts some things for the JSON API, such as the Accept: application/vnd.api+json header required by the specifications)

In addition, if the extracted data does not conform to the Ember Data JSON JSON API , you must configure a serializer , such as JSONSerializer , RESTSerializer or JSONAPISerializer , to format and massage the data, choosing the most suitable serializer for the data returned by your server. Here is a brief overview of these 3 serializers:

JSONSerializer

  • Base serializer (extends abstract DS.Serializer)
  • Provides normalization hooks for processing received data.
  • Provides serialization hooks for massaging sent data.
  • Expects plain JSON format

      {
       "id": 1,
       "name": "Bob",
       "friends": [array of friend ids],
       "links": {
         "home": "/ bobshome"
       }
     }
    

RESTSerializer

  • Extends JSONSerializer
  • Expects a similar JSON format (with "root"):

      {
       "user": {
         "id": 1,
         "name": "Bob",
         "friends": [array of friend ids],
         "links": {
           "home": "/ bobshome"
         }
       }
     }
    

JSONAPISerializer

In general, we can mix and match adapters and serializers with what is best for our data and URL endpoint structure. Each of them can be applied for each application or for each model.


Methods

When creating a query, depending on the exact behavior you need, you must override the corresponding hooks provided by the Ember data store (in the adapter):

Ember Data Search Methods

Each of the above hooks has a corresponding normalize{{HOOK_NAME}}Response method in the serializer (for example, normalizeFindRecordResponse ), where the data can be massed depending on the request method (which we call):


<strong> Examples

Let's say we want a Bob Tumblr blog called "mynameisbob".

Here is a general example of how to do this:

 export default DS.RESTAdapter.extend({ namespace: 'v2/blog/', // https://guides.emberjs.com/v2.0.0/models/customizing-adapters/#toc_endpoint-path-customization host: 'https://api.tumblr.com', // https://guides.emberjs.com/v2.0.0/models/customizing-adapters/#toc_host-customization headers: { // https://guides.emberjs.com/v2.0.0/models/customizing-adapters/#toc_headers-customization 'api_key': 'abcdefg' } // set any default ajax options you might need ajaxOptions(url, type, options = {}) { options.crossDomain = true; // make it CORS options.dataType = 'jsonp'; return this._super(url, type, options); } // find a blog findRecord: function(store, type, id, snapshot) { const URL = this.buildURL(type.modelName, id, snapshot, 'findRecord'); return this.ajax(URL, 'GET'); } }); 

Usage in Route :

 // ... model() { return this.store.findRecord('blog', 'mynameisbob'); } // ... 

However, there are several ways to do this. You can also save the api key and host URL as the properties of your adapter and simply use them to create the URL (using the buildURL hook):

 export default DS.RESTAdapter.extend({ hostUrl: 'https://api.tumblr.com/v2/blog' apiKey: 'abcdefg', buildURL: function(modelName, id, snapshot, requestType, query) { // customize the url based on the parameters // lets assume the id is the blog name return `${this.get('hostUrl')}/${id}.tumblr.com/posts?api_key=${this.get('apiKey')}`; } // find a blog findRecord: function(store, type, id, snapshot) { const URL = this.buildURL(type.modelName, id, snapshot, 'findRecord'); return this.ajax(URL, 'GET'); } }); 

Here's the Github Repo for a simple Ember app communicating with the Github API

Adapters connected to the community to serve as examples:

Some useful indications:


Pre Ember 1.13.0

Here is a simple example of how to write a custom RestAdapter . Essentially, you need to rewrite the hooks you need to search for the store ( find , findAll , findQuery ...) as well as buildURL() .

Since this is an external API and we need to worry about CORS, we also need to override the ajax hook.

Custom Tumblr Adapter:

 App.TumblrAdapter = DS.RESTAdapter.extend({ buildURL: function(type, id, record) { var tumblrBlogName = 'feministlibraryonwheels'; var tumblrApiKey = 'abcdefg'; var tumblrRequestUrl = 'http://api.tumblr.com/v2/blog/' + tumblrBlogName + '.tumblr.com' + '/posts?api_key=' + tumblrApiKey; return tumblrRequestUrl; }, ajax: function(url, method, hash) { hash = hash || {}; // hash may be undefined hash.crossDomain = true; // make it CORS hash.xhrFields = {withCredentials: true}; return this._super(url, method, hash); }, find: function(store, type, id, record) { // customization here or within buildURL return this.ajax(this.buildURL(), 'GET'); }, findAll: function(store, type, sinceToken) { // customization here or within buildURL return this.ajax(this.buildURL(), 'GET'); }, findQuery: function(store, type, query) { // customization here or within buildURL return this.ajax(this.buildURL(), 'GET'); }, findMany: function(store, type, ids, owner) { // customization here or within buildURL return this.ajax(this.buildURL(), 'GET'); } }); 

If the answer is incorrectly formatted for Ember Data, we can quickly fix it in ajax with a simple promise:

 ajax: function(url, method, hash) { hash = hash || {}; // hash may be undefined hash.crossDomain = true; // make it CORS hash.xhrFields = {withCredentials: true}; return this._super(url, method, hash).then(function(json) { // Massage data to look like RESTAdapter expects. return { tumblrs: [json] }; }); }, 

If you want to correctly identify all models with a relationship, you will need to run a custom RESTSerializer to properly massage the data.

Here is a simple jsbin example I came across while researching these things myself.

+3
source

Using Ember 1.13.3.

As for Tumblr specifically, I have the following in /post.js adapters. Hope this helps you.

 import DS from "ember-data"; export default DS.RESTAdapter.extend({ host: 'https://api.tumblr.com', namespace: 'v2/blog/example.tumblr.com', apiKey: 'example', ajaxOptions() { var hash = this._super.apply(this, arguments); hash.data = hash.data || {}; hash.data.api_key = this.get('apiKey'); hash.dataType = 'jsonp'; return hash; } }); 
+3
source

tumblr, although it seems to be a friendly api, is actually not that friendly with Ember. Ember Data expects a very specific json format, and if the answer doesn't match it, it won’t seem as “magical” or “just work” as many of the simplified tutorials.

find function: not so magic

You are on the right track (by defining a custom adapter). You can look in overriding buildURL inside your adapter.

Read here and here for more details on how to turn inbound json into a form that Ember likes.

If you install jsbin, I can take a look at it.

0
source

Source: https://habr.com/ru/post/1213783/


All Articles