Ember CLI - 适用于第三方API的RESTAdapter

时间:2015-02-20 07:13:03

标签: javascript ember.js ember-data tumblr ember-cli

我可以使用ic.ajax将数据导入我的应用程序,但似乎我应该使用RESTAdapter。解释如此简化,以至于我不确定在各种情况下该怎么做。这就是我认为应该工作的东西:(以及固定装置,本地快递服务器和http-mocks)

我将使用tumblr作为示例 - 因为它一般都是友好的API。

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;

路由/ post.js

import Ember from 'ember';

export default Ember.Route.extend({

  model: function() {
    return this.store.find('post');
  }

});

所以,据我所知 - find()是一些魔法 ajax调用......但如果我想指定jsonp或其他什么呢?

适配器/ 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

});

这有点令人讨厌,因为长时间的tumblr端点事情是如此狡猾 - 我觉得它应该只是http://api.tumblr.com而且可能有另一种方式来指定其他东西......或者它只是以某种方式知道 ...非常困惑......看起来像命名空间:' v2'是那个选项... ...

模板/ 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's up with that?
        {{/each}}
    </ul>

</div>
</section>

然后这个{{#each}}只知道它在大多数情况下应该寻找什么 - 但我想明确。


在我所见过的所有教程中,它都是本地服务器 - 或者是http-mocks - 而且它只是这样的:

import DS from 'ember-data';

export default DS.RESTAdapter.extend({

  host: 'localhoststuff:3000',
  namespace: 'api'

});

然后在此之上 - 我得到的似乎是一个角色问题GET http://api.tumblr.com/v2/blog/feministlibraryonwheels.tumblr.com/posts?api_key=UbB4p0GxqNa6wUa8VwpIdqtywjIiA6vljZXyI9wkx9hnQnAFyk/posts 401 (Not Authorized)

并且它不是真的隐藏了...... [http://api.tumblr.com/v2/blog/feministlibraryonwheels.tumblr.com/posts?api_key=UbB4p0GxqNa6wUa8VwpIdqtywjIiA6vljZXyI9wkx9hnQnAFyk][1]

许多快速教程与现实世界中的RESTAdapter之间缺少什么 - 真正的API&????任何方向都将非常感激。

此外,这里也有一些ic.ajax()次尝试。有效负载到达控制台 - 但在尝试将数据导入模板时会变得模糊

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=F.L.O.W.&showstructure=1&showTags=1&booksort=title_REV',
      type: 'get',
      dataType: 'jsonp'
    });
    console.log(libraryData);
    return libraryData;
  }

});



编辑:2.4文档非常棒。 Ember数据稳定。您需要知道如果它不是JSON API格式,您将获得什么类型的JSON,然后您需要序列化数据并将其转换为该格式。

3 个答案:

答案 0 :(得分:3)

Ember 1.13.0Ember Data 1.13.0及以上

的更新

工具(适配器和序列化程序)

要连接到不具有Ember-Data友好性的API(例如tumblr),您必须customize an adapter(例如RESTAdapterJSONAPIAdapter来正确构建请求。

(JSONAPIAdapter是RESTAdapter的子类,用于调整JSON API的一些内容,例如规范要求的Accept: application/vnd.api+json标题)

此外,如果检索到的数据不遵循Ember Data JSON JSON API格式,您应该customize a serializer,例如JSONSerializerRESTSerializerJSONAPISerializer通过为后端返回的数据选择最合适的序列化程序来格式化和按摩数据。以下是这3个序列化程序的简短摘要:

<强> JSONSerializer

  • 基本序列化程序(扩展抽象DS.Serializer)
  • 提供规范化挂钩以按摩收到的数据
  • 提供序列化挂钩以按摩发送的数据
  • 期待通常的JSON格式

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

<强> RESTSerializer

  • 扩展JSONSerializer
  • 期待类似的JSON格式(使用&#34; root&#34;):

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

<强> JSONAPISerializer

通常,我们可以混合和匹配适配器和序列化程序,使其最适合我们的数据和URL端点结构。其中每个都可以应用于每个应用程序或每个模型。


<强>方法

在构建请求时,根据您需要的确切行为,您应该覆盖Ember数据存储(在适配器中)提供的appropriate hooks

Ember Data Find Methods

上面的每个钩子在序列化器中都有一个适当的normalize{{HOOK_NAME}}Response方法(例如normalizeFindRecordResponse),根据我们的请求方式(我们调用哪个钩子)可以按摩数据:


<强>实施例

让我们说我们想要获得Bob的Tumblr博客,名为&#34; mynameisbob&#34;。

以下是通用示例,如何执行此操作:

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');
    }
});

Route中的用法:

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

但是,有多种方法可以实现这一目标。您还可以将api密钥和主机URL存储为适配器的属性,并使用它们来构建URL(使用buildURL挂钩):

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 a Github Repo用于与Github API进行通信的简单Ember应用

社区驱动的适配器作为示例:

一些有用的读物​​:


前Ember 1.13.0

以下是有关如何编写自定义RestAdapter的简单示例。基本上,您需要做的是覆盖所需的商店查找挂钩(findfindAllfindQuery ...)以及buildURL()

由于它是一个外部API,我们需要担心CORS,我们还应该覆盖ajax钩子。

自定义Tumblr适配器:

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');
    }
});

如果没有为Ember Data正确格式化响应,我们可以通过一个简单的承诺在ajax钩子中快速修复它:

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] };
    });
},

如果您希望正确定义所有具有关系的模型,则需要实现自定义RESTSerializer来正确按摩数据。

以下是我在研究这些事情时遇到的simple jsbin example

答案 1 :(得分:3)

使用Ember 1.13.3。

特别是关于Tumblr,我在adapter / post.js中有以下内容。希望这会对你有所帮助。

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;
    }
});

答案 2 :(得分:0)

tumblr,虽然看起来是一个友好的api,但对Ember并不是那么友好。 Ember Data需要一种非常具体的json格式,如果响应不匹配,那么它似乎并不是很神奇。或者只是工作&#39;就像许多简化的教程一样。

查找功能:not so magic

您走在正确的轨道上(定义自定义适配器)。您可能会考虑在适配器中覆盖buildURL。

有一个阅读herehere,详细了解如何将传入的json变成Ember喜欢的形式。

如果你提出了一个jsbin,我可以看看它。