Logging every API request in Ember-Data - ember.js

I'm still a bit new to Ember. I'm using Ember 1.13 with Ember Data and the DS.RESTAdapter. For debugging purposes, as well as educational (such as getting a feel for how Ember Data works with various options such as the shouldReload* functions), I want to log every API request with mainly the URL called and optionally how it was called (eg, from a store.findAll() or store.queryRecord(), etc.). Is there a single place (my guess is somewhere in adapter:application?) where I can put a single console.log('URL called: ', url, ', from: ', callingFunction); that handles all of this?

If you use the JSONAPIAdapter or the RESTAdapter just override ajax() on the adapter to log the URI:
ajax(url, type, options) {
console.log(url);
return this._super(...arguments);
}
There is no easy way to get the caller function. Analyse the callstack, if its just for debugging purposes!
But, maybe just use the Browser log XMLHttpRequest option if its for debugging?!
If you want to know how it works, checkout the code. The adapter and the store is where you can look for knowledge.

Related

Fetch new data from API in jQuery plugin's callback

I am new to ember, so please treat me like a fool. What I'm trying to do first is to understand the concept.
In my application I heavily rely on few jQuery plugins they fetch new portion of data in their callbacks, that's how these plugins are designed, but I am not sure how can I trigger them to fetch a new portion of data from API passing to API updated query parameters after plugin has been rendered.
I have wrapped the plugin in a component, in component's template I send data to it as (I use emblem.js syntax here)
= plotly-chart chartData=model
In model I have
//app/models/data-points.js
import DS from 'ember-data';
export default DS.Model.extend({
// time: DS.attr(),
ch1: DS.attr(),
ch2: DS.attr(),
ch3: DS.attr(),
temperature: DS.attr(),
});
And then in component itself I fetch data
//app/components/plotly-chart.js
dataPoints: Ember.computed.map('chartData', function(item){
return item.getProperties('ch1', 'ch2', 'ch3', 'temperature');
}),
and make some manipulations with data, which isn't so important for the question itself.
Ah, and I have a route graph/ which later calls that component
//app/routes/graph.js
import Ember from 'ember';
export default Ember.Route.extend({
queryParams: {
start_timestamp: {
refreshModel: true
},
end_timestamp: {
refreshModel: true
}
},
model(params) {
return this.get('store').query('data-point', params);
}
});
So as you see I have tried to fetch new properties via query params, finally it works great if I just update the url in browser, but now can I trigger new call to API and fetch new data and get this new data in a component itself?
Also I'm struggling to understand what role controllers play in all of these. It is mentioned that controllers will be deprecated soon, but still used here https://guides.emberjs.com/v2.10.0/routing/query-params/
My code seems to work without controllers, so this is really confusing.
Also I suspect maybe I should use services for what I'm trying to achieve, but not sure how.
Ember experts, could you please point me into a right direction? The most important thing is how to fetch new portion of data from API with updated query parameters (query parameters to API itself, not nessesarely the ember application, but I suspect in ember-data it is the same thing? or not %) %) %)).
UPDATE 1
Really I should use services for that, shouldn't I? Pass arguments into a service and query a store there. Would that be a correct pattern?
Then query parameters in url are not the same as querying the store and is an independent thing. Am I right?
but how can I trigger new call to API and fetch new data and get this new data in a component itself?
If you change your queryParam values in a controller using an action (combined with your current route setup) it will adjust your route and re-call your API, as the values are bound together to make this particular use case simple :-) You're about 98% of the way there ... :-)
Re controllers going away, they won't for a long time as the replacement hasn't been worked out yet. You could do some of this in a service if you want to, but there is no need as you are almost done.
Thanks, that make sense though. I just worried I'm doing it wrong.
By they way finally I found a way to access store from the controller Access store from component but:
1. I was unable to take out the data from that variable, probably it's me being stupid.
2. I double it's the right way to access store directly in a component and better to use services for that or rely on “Data Down Actions Up” (DDAU) paradigm?
Finally I was able to fetch new portion of a data calling a controller's action from within the controller, but then the next problem raised - the data was updated, but the JS code did not know about that because I feed the jQuery plugin with this data and it did not pick up changes automatically. I think I might be doing it a wrong way there %)
But finally I get it working by adding an Ember's observer to that variable and in observer calling a redraw function (for chart in this particular place).
#acorncom Thanks!

good examples of testing ember with rest adapter in quint or mocha

I have been trying to test my ember application for 2 days with no success. There are examples out there that use fixtures but I was wondering if you might have an example of test scripts where RESTAdapter was used. I have tried using Fixtures for testing as you can see in the fiddle here : http://jsfiddle.net/deewen/u68Mx/1/, but that is also not working for me(sorry I couldn't find proper expect.js file).
it("Check analyticsRuns controller", function () {
//var controller = AS.__container__.lookup('controller:analyticsRunsIndex');
//the returns null too even though I have that controller
visit('/analytics')
.then(function() {
expect(find('*')).to.not.be(undefined);
});
});
Any suggestions for resource or read that could guide me on this would be highly appreciated. Thanks.
In general you don't want your test to hit a live API endpoint because at that point you're not only testing your application code, you're also testing both the functionality of the API and the state of any data that may (or may not) already be stored in the API service.
The Ember Data tests setup fake AJAX responses, much like you'd do with something like webmock on the server side. Something like that is probably the way to go.
https://github.com/emberjs/data/blob/master/packages/ember-data/tests/integration/adapter/rest_adapter_test.js#L34-L55

Ember Data's API call signature

I'm a newbie to Ember Data and I've just switched from FIXTURE data to the RESTAdapter but I don't know enough about how to connect the model and the API's call signature. Specifically I'd like to be able to call an endpoint GET /activities/[:user_id]/[:by_date]. This would load an array of "Activity" objects but only those for a given date.
Router:
this.resource('activities', { path: '/activities' }, function() {
this.route('by_date', {path: '/:user_id/:by_date'});
});
Route:
App.ActivitiesByDateRoute = Ember.Route.extend({
serialize: function(activity) {
return {
userId: 1,
dateBy: "2013-07-01"
};
}
});
First off I tried to hard code the values for userId and dateBy making the adjustments to the Route above. Sadly that did not work. I think I understand why -- although I don't have a quick way to fix this -- but more disturbing for me was that when I manually put in the parameters into the URL: http://restful.service.com/api/activities/1/2013-07-01. The results are quite surprising to me:
Initially the debugging messages suggest a success:
This however, is not correct as no network requests are actually made
If you reload the browser, it will now go out and get the Activities but to my surprise it also goes out to find the specified user. Hmmm. That's ok, the user 1 is pulled back successfully.
The Activity, however, is just a GET /activities call which fails because this endpoint needs the user and date qualifier to work. Why weren't these included in the request?
I don't think ember data supports "composite keys" (which is essentially what you are trying to do). You'd probably need to build your own Ajax for that specific model and implement it in the model hook for that specific route. You can always fetch the data and sideload it into ember-data if you'd like to have an ember data model.

ember-data adapter to read from cloudant RESTful API

The cloudant RESTful API is fairly simple but doesn't match the way ember-data expects things to be. How can I customize or create an Adapter that deals with these issues...
In my specific case I only want to load records from one of several secondary indexes (ie. MapReduce fnctions).
The URL for this is below, where [name] and [view] would change depending on user selection or the route I am in.
https://[username].cloudant.com/[db_name]/_design/[name]/_view/[view]
Looking at the ember-data source there doesn't seem to be an easy way of defining URLs like this. I took a look at findQuery and it expects to send any variables through as url params not as part of the actual URL itself.
Am I missing something? Is there an obvious way of dealing with this?
Then the data comes back in a completely different format, is there a way to tell ember what this format is?
Thanks!
I had similar problem where URL's are dynamic. I ended up creating my own adapater by extending DS.RESTAdapter and overriding the default buildURL method. For example:
App.MyAdapter = DS.RESTAdapter.extend({
buildURL: function(record, suffix) {
var username, db_name, name, view;
// Do your magic and fill the variables
return 'https://'+username+'.cloudant.com/'+db_name+'/_design/'+name+'/_view/'+view;
}
});
I ended up also defining my own find, findAll, findQuery, createRecord, updateRecord, deleteRecord etc. methods as I had to pass more variables to buildURL method.
If returning data is in different format then you can also write your own serializer by extending DS.JSONSerializer and define your own extraction methods extract, extractMany etc.
You should evaluate how well your API follows the data format required by ember/data RESTAdapter. If it is very different then it's maybe better to use some other component for communication like ember-model, ember-restless, emu etc, as ember-data is not very flexible (see this blog post). You can also write your own ajax queries directly from routes model hooks without using ember-data or other components at all. It is not very hard to do that.

How can you store a path and transitionTo it later in Ember's v2 Router?

i'm trying to migrate to the new Router in Ember. the use case is this: user is not logged in but requests a URL that requires login. he is redirected to a login route, after successful login he is redirected to his original destination.
i achieved this with the prior Router by overriding Router.route(path) and intercepting path requests when the app was in unauthorized state.
the new Router doesn't have a route() function, also, i don't know how to override it now that the Router instance is created automatically by Ember. i probably shouldn't do that anyway.
there is a Route.redirect() hook that looks useful. however, Route no longer extends Path in the v2 Router, so there is no Root.path, and no path information is passed into Route.redirect(), so i don't know how to save the path info for calling transitionTo() later.
i've supplied my general approach below. how can i accomplish this? it seems like a very common use case for many application.
// i imagine something like this should happen
App.AuthRequiredRoute = Ember.Route.extend({
redirect: function() {
if(!App.controllerFor('login').get('isLoggedIn')) {
var pathToSave = ????
App.controllerFor('login').set('pathAfterLogin',pathToSave);
this.transitionTo('login');
}
}
}
// and then after login, the LoginController would call App.router.transitionTo(this.pathAfterLogin)
I have done a lot of research into this myself in the last day or two. I can share with you what I have discovered, and a couple of thoughts.
First of all, you can some information regarding the current path and contexts like so:
this.router.router.currentHandlerInfos
This returns an array. Each object has both a name and a context property. The names correspond to the name of the router you would call in transitionTo.
In my opinion, although you could work with something like this, it would be messy. The API docs don't refer to this and it may not be the intention to use this as a public API.
I see issues with the above solution for deeper nested dynamic segments too. Given how new the router v2 is, I think it will continue to evolve and a better solution is likely to present itself. It's a fairly common thing to want to save the current location and return to it at a later date.
In the meantime, rather than a redirect, perhaps use a conditional block in your template that presents a login rather than an outlet if the authenticated flag is not set on the ApplicationController? I know it's not as "right" but it is "right now".