我可以使用ic.ajax将数据导入我的应用程序,但似乎我应该使用RESTAdapter。解释如此简化,以至于我不确定在各种情况下该怎么做。这就是我认为应该工作的东西:(以及固定装置,本地快递服务器和http-mocks)
我将使用tumblr作为示例 - 因为它一般都是友好的API。
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;
import Ember from 'ember';
export default Ember.Route.extend({
model: function() {
return this.store.find('post');
}
});
所以,据我所知 - find()
是一些魔法 ajax调用......但如果我想指定jsonp或其他什么呢?
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'是那个选项... ...
<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]
此外,这里也有一些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;
}
});
答案 0 :(得分:3)
工具(适配器和序列化程序)
要连接到不具有Ember-Data友好性的API(例如tumblr),您必须customize an adapter(例如RESTAdapter或JSONAPIAdapter来正确构建请求。
(JSONAPIAdapter是RESTAdapter的子类,用于调整JSON API的一些内容,例如规范要求的Accept: application/vnd.api+json
标题)
此外,如果检索到的数据不遵循Ember Data JSON JSON API格式,您应该customize a serializer,例如JSONSerializer,RESTSerializer或JSONAPISerializer通过为后端返回的数据选择最合适的序列化程序来格式化和按摩数据。以下是这3个序列化程序的简短摘要:
<强> JSONSerializer 强>:
期待通常的JSON格式
{ "id": 1, "name": "Bob", "friends": [array of friend ids], "links": { "home": "/bobshome" } }
<强> RESTSerializer 强>:
期待类似的JSON格式(使用&#34; root&#34;):
{ "user": { "id": 1, "name": "Bob", "friends": [array of friend ids], "links": { "home": "/bobshome" } } }
<强> JSONAPISerializer 强>
通常,我们可以混合和匹配适配器和序列化程序,使其最适合我们的数据和URL端点结构。其中每个都可以应用于每个应用程序或每个模型。
<强>方法强>
在构建请求时,根据您需要的确切行为,您应该覆盖Ember数据存储(在适配器中)提供的appropriate hooks:
上面的每个钩子在序列化器中都有一个适当的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应用
社区驱动的适配器作为示例:
一些有用的读物:
以下是有关如何编写自定义RestAdapter的简单示例。基本上,您需要做的是覆盖所需的商店查找挂钩(find
,findAll
,findQuery
...)以及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)
查找功能:not so magic
您走在正确的轨道上(定义自定义适配器)。您可能会考虑在适配器中覆盖buildURL。
有一个阅读here和here,详细了解如何将传入的json变成Ember喜欢的形式。
如果你提出了一个jsbin,我可以看看它。