简体   繁体   中英

How do you create an ajax service in ember-cli 3.17?

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM