angular 1.5 $资源,如何为所有请求设置默认操作(例如transformResponse)?

时间:2016-11-03 23:59:56

标签: angularjs default angular-resource

我有一个资源:

angular.module('mymodule')
    .factory('someResource', someResource);

function someResource($resource) {
  return $resource('/something', {}, {
    find  : {method: 'GET', isArray: true, transformResponse: convertFn},
    create: {method: 'POST', isArray: true, transformResponse: convertFn},
    update: {method: 'PUT', isArray: true, transformResponse: convertFn},
  });

  function convertFn(){
    //...
  }

}

是否可以不在每种类型的请求中复制transformResponse?定义一些默认的transformResponse?

可能的解决方案只是通过以编程方式添加属性来修改定义对象,但这样的解决方案看起来很难维护。

angular.module('mymodule')
    .factory('someResource', someResource);

function someResource($resource) {
  var types = {
    find  : {method: 'GET', isArray: true},
    create: {method: 'POST', isArray: true},
    update: {method: 'PUT', isArray: true},
  }

  //add transform to each, es6
  Object.keys(types).forEach(k => types[k].transformResponse = convertFn)

  return $resource('/something', {}, types);

  function convertFn(){
    //...
  }

}

修改
对于这个想法,请求georgeawg 另一种方法可能是:为默认值编写包装函数,如:

angular.module('mymodule')
    .factory('someResource', someResource);

function someResource($resource) {
  var types = {
    find  : defaults({method: 'GET'}),
    create: defaults({method: 'POST', isArray: false}),
    update: defaults({method: 'PUT'}),
  }

  return $resource('/something', {}, types);

  function convertFn(){
    //...
  }

  function defaults(opts) {
    return Object.assign({
      isArray: false,
      transformResponse: convertFn
    }, opts)
  }

}

有一些更清洁的解决方案吗?

3 个答案:

答案 0 :(得分:1)

怎么样:

angular.module('mymodule')
    .factory('someResource', someResource);

function someResource($resource) {
  return $resource('/something', {}, {
    find  : action('GET'),
    create: action('POST'),
    update: action('PUT')
  });

  function action(method) {
      return { method: method,
               isArray: true,
               transformResponse: convertFn
              };
  }

  function convertFn(){
    //...
  }

}

使用响应拦截器

由于$resource使用了$http服务,response interceptor可以转换回复:

app.config(function($httpProvider) {
    $httpProvider.interceptors.push(function() {
      return {
       'request': function(config) {
           //
        },

        'response': function(response) {
          if (response.config.url.startsWith("/something") {
              response.data = convertFn(response.data);
          };
          return response;

          function convertFn(data) {
             //return new data
          }
        }
    });
});

答案 1 :(得分:0)

你看过棱角分明$http interceptors了吗? ngResource将尊重响应拦截器功能。 Here's a post详细说明了用法。

答案 2 :(得分:0)

可以拥有一个非常通用的基础$资源并继承它。

我在SO帖子上找到了我无法找到的答案。如果有人发现它编辑我的帖子来添加它。

以下是我使用的代码:

angular.baseResourceServiceMaker = function(service){
    return ['$injector', '$resource', 'TypeService', '$http', '_', 'BackEndpoint', 'Utils',
            function($injector, $resource,TypeService, $http, _, BackEndpoint, Utils){
        this.restUrl = BackEndpoint+'/rest/';
        this.baseName = '';
        this.resource = null;
        // from angular-resource
        var toString= function() {
            var value = [];
            _.forEach(this, function(e) {
                value.push('' + e);
                });
            return '[' + value.join(', ') + ']';
          };
          var isObject = function isObject(value) {
              // http://jsperf.com/isobject4
              return value !== null && typeof value === 'object';
            };
        var isFile = function(obj) {
          return toString.call(obj) === '[object File]';
        }


        var isFormData = function(obj) {
          return toString.call(obj) === '[object FormData]';
        }


        var isBlob = function(obj) {
          return toString.call(obj) === '[object Blob]';
        }
        this.defaultToJson = function(d) {
              return isObject(d) && !isFile(d) && !isBlob(d) && !isFormData(d) ? angular.toJson(d) : d;
        };
        this.typeServiceProcessData = function(d){
            return TypeService.processData(d);
        };
        this.typeServiceProcessJsData = function(d){
            return TypeService.processJsData(d);
        };
        this.generateTransformRequestFn = function(mapKeyValues){
            return function(data){
                var object = {};
                _.forEach(_.keys(mapKeyValues), function(key){
                    Utils.setAttributeValue(object, key, Utils.getAttributeValue(data, mapKeyValues[key]));

                });
                return object;
            }
        };

        this.addedMethods = {};
        // use of resource will be internal, to handle transformation of data
        // and so on...
        this.getResource = function(){
            if(this.resource == null){
                var baseResourceUrl = this.restUrl + this.baseName + '/';
                var baseResourceMethods = {
                        'get':      {method:'GET', transformResponse:[$http.defaults.transformResponse[0], this.typeServiceProcessData],
                            url:baseResourceUrl+':id'},
                        'create':   {method:'POST', url:baseResourceUrl, transformRequest:[this.typeServiceProcessJsData, this.defaultToJson]},
                        'update' :  {method:'PUT', transformRequest:[this.typeServiceProcessJsData, this.defaultToJson]},
                        'search':   {method:'GET', isArray:true, transformResponse:[$http.defaults.transformResponse[0], this.typeServiceProcessData], 
                            url:baseResourceUrl+'search/(:search)/:offset/:limit/:order',
                            params: {offset:0, limit:50, order:"creationDate=asc"}
                        },
                        'custom_search':    {method:'GET', isArray:true, transformResponse:[$http.defaults.transformResponse[0], this.typeServiceProcessData], 
                            url:baseResourceUrl+':prefix/search/(:search)/:offset/:limit/:order',
                            params: {search:'pk=gt=0',offset:0, limit:50, order:"creationDate=asc"}
                        },
                        'list':     {method:'GET', isArray:true, transformResponse:[$http.defaults.transformResponse[0], this.typeServiceProcessData], 
                            url:baseResourceUrl+'search/(pk=gt=0)/0/50/creationDate=asc'
                        },

                        'delete':   {method:'DELETE'} 
                    };
                _.forEach(_.keys(this.addedMethods), function(key){
                    baseResourceMethods[key] = this.addedMethods[key];
                }, this)
                this.resource = $resource(baseResourceUrl+':id',
                    {id:'@pk'}, baseResourceMethods
                    );
            }
            return this.resource;
        };
        this.get = function(id){
            this.getResource().get({id:id});
        };
        this.create = function(data){
            this.getResource().create(data);
        };
        this.update = function(data){
            this.getResource().update(data);
        };
        this.search = function(searchQuery){
            this.getResource().search({search:searchQuery});
        };
        this.searchPaginate = function(searchQuery, offset, limit){
            this.getResource().search({search:searchQuery, offset:offset, limit:limit});
        };
        this['delete'] = function(id){
            this.getResource()['delete']({id:id});
        };
           // Finishes the other injections
        $injector.invoke(service, this);

    }];
};

关于此代码的一些评论:

  • 函数isFile / isObject,...是angular.js的c / c,因为我保留了angularJS的defaultTransformResponse,这个函数使用的是不在我范围内的内部函数,所以我不得不抄袭它。
  • 我定义了默认方法create / update /...
  • 我有一个typeService,我声明我的所有类型和字段,所以我可以自动转换类型:例如我的服务器的日期总是时间戳,所以我自动将它转发到transformResponse中的Javascript日期,反之亦然transformRequest。
  • addedMethods用于添加其他方法。
  • restUrl是所有其他服务的入口点,baseName必须由实现设置,它是资源的入口点。 BackEndPoint是定义应用程序的contextPath的常量。

使用示例:

.service('ArticleService',angular.baseResourceServiceMaker(['$http', function($http){
      this.baseName = 'article';
      var baseResourceUrl = this.restUrl + this.baseName + '/';
      this.addedMethods.root ={
              method:'GET', isArray:true, 
              transformResponse:[$http.defaults.transformResponse[0], this.typeServiceProcessData], 
              url:baseResourceUrl+'root'
      };
}]))