LoginSignup
23
23

More than 5 years have passed since last update.

Angular.js の Restangular で$resourceの置き換えが、簡単でとても便利

Last updated at Posted at 2014-10-08

restangular

今までこんな感じで$resourceをラップするだけのサービスを使って、各Controllerで使いまわしてたけど、いくつか問題点が。

angular.module('models', ['ngResource'])
.factory('User', ['$resource', function ($resource) {
  return $resource(
    '/api/:Version/users/:Id',
    { Id: '@Id', Version: '@Version' },
    {
      'update': { method: 'PUT' },
      'query': { method: 'GET', isArray: false, cache: true }
    }
  );
}]);
  • apiから返ってくる形式がちょっと違ったりすると、Controllerでデータを操作して$scopeに格納しなくてはないけない場面が多かった
  • $resourceだけだとmodel同士のリレーションとか階層とか表現しづらいので、またControllerに処理を書いてしまう。
  • apiごとの共通の設定とか個別の設定とか渡しにくいので、引数を増やして対応してしまって(古いバージョンのapiを呼んでるところとか)可読性やメンテナンス性が落ちていく。

などなど、色々と悩ましいことに。
Angularを書いてて思うのは、Controllerが太るけど、どうやって処理を移譲するのがいいんだろう・・。というのはよくある。

なので偶然見つけたrestangularを試してみた


angular.module('app', [
  'restangular'
]);

angular.module('app').config(function(RestangularProvider) {
  // そのまんまだけどproviderにbaseのurlを渡しておける。
  RestangularProvider.setBaseUrl('/api/v3');
  // apiの返り値を共通化する処理などを書ける
  RestangularProvider.setResponseExtractor(function(response, operation) {
    return response.results;
  });
});

// 共通処理が多いので、RestangularをControllerで直接操作しないで、serviceでラップする
angular.module('services.rest', ['restangular']).
  factory('UserSvc', function(Restangular) {
    return Restangular.all('users');
  }).
  factory('IssueSvc', function(Restangular) {
    // api毎に異なる設定も可能
    return Restangular.withConfig(function(RestangularConfigurer) {
      RestangularConfigurer.setBaseUrl('/api/v2');
    }).all('issues');
  });

// GET http://localhost:8080/api/v3/usersが呼ばれて、{page:0, results: [aaa,bbb,ccc]} 結果のresultsの部分がusersに格納される
UserSvc.getList().then(
  function(users) {
    $scope.users = users;
  }
);

とりあえず$resourceの置き換えには困らなそう。
なにか便利な機能があったら追記していく。

イメージしやすいと思うのでこんなふうに使ってますを貼っておく(汚いけど)


angular.module('services.rest', ['restangular'])

  .config(['RestangularProvider', function(RestangularProvider) {
      RestangularProvider.setBaseUrl('/api/v3');

      RestangularProvider.setRequestInterceptor(function(elem, operation) {
        if (operation === 'remove') {
           return undefined;
        }
        return elem;
      });

      RestangularProvider.setResponseExtractor(function(data, operation, what/*, url, response*/) {

        if (what === 'search' || what === 'feature' || what === 'conversations' || what === 'simple_search') {
          return data;
        }

        if (data instanceof Array) {
          return data;
        }
        if (data.result && data.result.users) {
          return data.result.users;
        }
        if (data.result && data.result.posts) {
          return data.result.posts;
        }
        if (data.result && data.result.notifications) {
          return data.result;
        }

        return data.results || data.result || data;

      });
      RestangularProvider.setDefaultHeaders({ 'X-Requested-With': 'XMLHttpRequest' });
    }
  ])

  .factory('AuthSvc', function(Restangular) {

    var svc = Restangular.all('auth');
    svc.addRestangularMethod('login', 'post', 'signin');
    svc.addRestangularMethod('signup', 'post', 'signup');
    svc.addRestangularMethod('register', 'post', 'register');
    svc.addRestangularMethod('changePassword', 'post', 'changePassword');
    svc.addRestangularMethod('inactivate', 'post', 'inactivate');
    return svc;

  })

  .factory('PasswordSvc', function(Restangular) {

    var svc = Restangular.withConfig(function(RestangularConfigurer) {
      RestangularConfigurer.setBaseUrl('/api/v3/auth');
    }).all('password');

    svc.addRestangularMethod('set', 'post', 'set');
    svc.addRestangularMethod('change', 'post', 'change');
    svc.addRestangularMethod('getKey', 'post', 'reset');
    return svc;

  })

  .factory('BankSvc', function(Restangular) {

    return Restangular.withConfig(function(RestangularConfigurer) {
      RestangularConfigurer.setBaseUrl('/api');
    }).all('accounts');

  })

  .factory('ImageUploadSvc', function(Restangular) {

    var svc = Restangular.all('images');
    svc.addRestangularMethod('getUploadUrl', 'get', 'get_upload_url');
    return svc;

  })

  .factory('MixSvc', function(Restangular) {

    var svc = Restangular.all('common');
    svc.addRestangularMethod('search', 'get', 'search');
    svc.addRestangularMethod('activities', 'get', 'activities');
    return svc;

  })

  .factory('CategorySvc', function(Restangular) {

    return Restangular.withConfig(function(RestangularConfigurer) {
      RestangularConfigurer.setDefaultHttpFields({cache: true});
    }).all('categories');

  })

  .factory('UserSvc', function(Restangular) {

    var svc = Restangular.withConfig(function(RestangularConfigurer) {
      RestangularConfigurer.setOnElemRestangularized(function(elem) {
        elem.addRestangularMethod('getTopicList', 'getList', 'topics');
        elem.addRestangularMethod('postTopic', 'post', 'topics');
        elem.addRestangularMethod('connectTags', 'post', 'tags');
        elem.addRestangularMethod('getTags', 'get', 'tags');
        elem.addRestangularMethod('getSlug', 'get', 'slug');
        return elem;
      });
    }).all('users');

    return svc;

  })

  .factory('MeSvc', function(Restangular) {
    return Restangular.withConfig(function(RestangularConfigurer) {
      RestangularConfigurer.setBaseUrl('/api/v3/profiles');
      RestangularConfigurer.setDefaultHttpFields({cache: true});
    }).all('me');
  })

  .factory('IssueSvc', function(Restangular) {
    var svc = Restangular.withConfig(function(RestangularConfigurer) {
      RestangularConfigurer.setOnElemRestangularized(function(elem) {
        elem.addRestangularMethod('publish', 'put', 'publish');
        elem.addRestangularMethod('reuse', 'post', 'reuse');
        elem.addRestangularMethod('start', 'put', 'start');
        elem.addRestangularMethod('end', 'put', 'end');
        return elem;
      });
    }).all('issues');
    svc.addRestangularMethod('search', 'get', 'search');
    svc.addRestangularMethod('getMyList', 'getList', '', {'related_me': 1});
    return svc;
  })

  .factory('ProposalSvc', function(Restangular) {

    return Restangular.withConfig(function(RestangularConfigurer) {
      RestangularConfigurer.setOnElemRestangularized(function(elem) {
        elem.addRestangularMethod('getCommentList', 'getList', 'comments');
        elem.addRestangularMethod('comment', 'post', 'comments');
        elem.addRestangularMethod('approve', 'put', 'approve');
        elem.addRestangularMethod('reject', 'put', 'reject');
        elem.addRestangularMethod('abort', 'put', 'abort');
        elem.addRestangularMethod('decide', 'put', 'decide');
        return elem;
      });
    }).all('proposals');

  })

  .factory('CardSvc', function(Restangular) {
    return Restangular.withConfig(function(RestangularConfigurer) {
      RestangularConfigurer.setBaseUrl('/api');
      RestangularConfigurer.setOnElemRestangularized(function(elem) {
        elem.addRestangularMethod('pay', 'post', 'pay');
        return elem;
      });
    }).all('payments');
  })

  .factory('TopicSvc', function(Restangular) {

    var svc = Restangular.withConfig(function(RestangularConfigurer) {
      RestangularConfigurer.setOnElemRestangularized(function(elem) {
        elem.addRestangularMethod('like', 'post', 'like');
        elem.addRestangularMethod('unlike', 'post', 'unlike');
        elem.addRestangularMethod('likedUsers', 'get', 'likes');
        return elem;
      });
    }).all('topics');
    svc.addRestangularMethod('search', 'get', 'search');
    svc.addRestangularMethod('simpleSearch', 'get', 'simple_search');
    svc.addRestangularMethod('featureList', 'get', 'feature');
    svc.addRestangularMethod('getFavList', 'getList', '', {'liked_by_me': 1, 'page_size': 50});

    return svc;

  })

  .factory('ConversationSvc', function(Restangular) {
    var svc = Restangular.all('conversations');
    svc.addRestangularMethod('getPage', 'get');
    return svc;
  })

  .factory('FacebookSvc', function(Restangular) {
    var svc = Restangular.all('facebook');
    svc.addRestangularMethod('send', 'post', 'post');
    return svc;
  })

  .factory('TagsMapSvc', function(Restangular) {
    return Restangular.withConfig(function(RestangularConfigurer) {
        RestangularConfigurer.setBaseUrl('/api/v3/tags');
        RestangularConfigurer.setDefaultHttpFields({cache: true});
    }).all('map');
  })

  .factory('ContactSvc', function(Restangular) {
    return Restangular.all('contacts');
  })

  .factory('NewsSvc', function(Restangular) {
    return Restangular.withConfig(function(RestangularConfigurer) {
        RestangularConfigurer.setBaseUrl('/api');
        RestangularConfigurer.setDefaultHttpFields({cache: true});
    }).all('news_feed');
  })

  .factory('BlogSvc', function(Restangular) {
    return Restangular.withConfig(function(RestangularConfigurer) {
        RestangularConfigurer.setBaseUrl('/api');
        RestangularConfigurer.setDefaultHttpFields({cache: true});
    }).all('posts');
  })

  .factory('SelectionSvc', function(Restangular) {
    return Restangular.withConfig(function(RestangularConfigurer) {
        RestangularConfigurer.setDefaultHttpFields({cache: true});
    }).all('selections');
  })

  .factory('IssueSelectionSvc', function(Restangular) {
    return Restangular.withConfig(function(RestangularConfigurer) {
        RestangularConfigurer.setDefaultHttpFields({cache: true});
    }).all('issue_selections');
  })

  .factory('FaqSvc', function(Restangular) {
    return Restangular.withConfig(function(RestangularConfigurer) {
        RestangularConfigurer.setBaseUrl('/templates');
        RestangularConfigurer.setDefaultHttpFields({cache: true});
    }).all('faq_ja');
  })

  .factory('MessageSvc', function(Restangular) {
    return Restangular.withConfig(function(RestangularConfigurer) {
      RestangularConfigurer.setDefaultHttpFields({cache: true});
    }).all('notifications');
  });


ついでに

当社ではAngular.jsでサービスを開発したいエンジニアを募集しています!とか、書いちゃいけないのかな。

23
23
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
23
23