I am recently trying to upgrade my ember from ember-cli: 2.6.2
to ember-cli: 3.17
and I am having a hard time trying to parallel my implementation of ajax service to the newer ember-cli version. I wasn't the one who created the app from the scratch that is why I do not know why the import { raw } from 'ic-ajax';
is needed. Any help are very much appreciated.
Error that I am getting: Uncaught (in promise) TypeError: Cannot read property 'status' of undefined
This is my old ajax service app/services/ajax.js
import Ember from 'ember';
import { raw } from 'ic-ajax';
import dasherizeObjectKeys from '../../utils/dasherize-object-keys';
const { inject, get, isEmpty } = Ember;
export default Ember.Service.extend({
currentSession: inject.service(),
request(url, method = 'GET', data = undefined, dataType = 'json') {
data = JSON.stringify(dasherizeObjectKeys(data));
return new Ember.RSVP.Promise((resolve, reject) => {
const contentType = 'application/json';
const token = this.get('currentSession.token');
const headers= {
'Authorization': `Token ${token}`,
'X-Client-Platform': 'Web'
};
raw({ url, headers, data, type: method, dataType, contentType })
.then((response) => this.handleSuccess(response, resolve))
.catch((response) => this.handleError(response, reject));
});
},
handleSuccess(response, resolve) {
return resolve({
status: response.jqXHR.status,
response: response.response
});
},
handleError(response, reject) {
if (response.jqXHR.status === 401 && this.get('currentSession.isAuthenticated')) {
this.get('currentSession').invalidate();
}
let error = get(response, 'jqXHR.responseJSON');
if (isEmpty(error)) {
const responseText = get(response, 'jqXHR.responseText');
// FIXME: server should always return json, empty string is not json,
// after backend is fixed, `JSON.parse` and try/catch for errors are not needed
try {
error = JSON.parse(responseText);
} catch (e) {
error = {
errors: { detail: responseText }
};
}
}
error.status = response.jqXHR.status;
reject(error);
}
});
And this is my new ajax service app/services/request.js
import Service from '@ember/service';
import { Promise } from 'rsvp';
import fetch from 'fetch';
import dasherizeObjectKeys from '../../utils/dasherize-object-keys';
export default class RequestService extends Service {
request(url, method = 'GET', data = undefined, dataType = 'json') {
data = JSON.stringify(dasherizeObjectKeys(data));
return new Promise((resolve, reject) => {
const contentType = 'application/json';
const token = this.get('currentSession.token');
const headers= {
'Authorization': `Token ${token}`,
'X-Client-Platform': 'Web'
};
fetch({ url, headers, data, type: method, dataType, contentType })
.then((raw) => this.handleSuccess(raw, resolve))
.catch((raw) => this.handleError(raw, reject));
})
}
handleSuccess(response, resolve) {
return resolve({
status: response.jqXHR.status,
response: response.response
});
}
handleError(response, reject) {
if (response.jqXHR.status === 401 && this.get('currentSession.isAuthenticated')) {
this.get('currentSession').invalidate();
}
let error = get(response, 'jqXHR.responseJSON');
if (isEmpty(error)) {
const responseText = get(response, 'jqXHR.responseText');
// FIXME: server should always return json, empty string is not json,
// after backend is fixed, `JSON.parse` and try/catch for errors are not needed
try {
error = JSON.parse(responseText);
} catch (e) {
error = {
errors: { detail: responseText }
};
}
}
error.status = response.jqXHR.status;
reject(error);
}
}
When I upgraded from ic-ajax
to fetch
, I used ember-fetch which provides a drop-in replacement for the ajax from ic-ajax
:
Before
var ajax = require('ic-ajax');
rsvpAjax: function (options) {
return ajax.request(options.url, options);
}
After
import ajax from 'ember-fetch/ajax';
rsvpAjax: function (options) {
return ajax(options.url, options);
}
That got me most of the way there. But there's still some slight semantic changes that you have to deal with when switching from ajax to fetch. For one, error.jqXHR.responseJSON
no longer exists.
Before:
if(error && error.jqXHR){
var errorResponse = error.jqXHR.responseJSON || {};
// do something with the errorResponse
}
After:
if(error && typeof(error.json) === 'function'){
return error.json().then((errorResponse) => {
// do something with the error
}
}
Notice that the error json is resolved via a promise which most likely will require some refactoring since the ajax version did not.
As you see in the above example, jqXHR
does not exist anymore. I would presume your status problem is similar. If you want to see an example of an "ajax-service" using fetch
, see my ember-rest-client addon. It's a super simple wrapper around ember-fetch
which I use instead of using ember-data.