简体   繁体   English

自定义(OData)路线在Restangular中

[英]Custom (OData) routes in Restangular

On the server side, I'm using Web API with the OData routing convention, which means that my route for getting a single entity looks something like this: 在服务器端,我将Web API与OData路由约定一起使用,这意味着我获取单个实体的路线如下所示:

/api/v1/Products(1)

rather than: 而不是:

/api/v1/Products/1

Normally, in Restangular, I'd be able to get a single entity with something like this: 通常,在Restangular中,我将能够获得具有以下内容的单个实体:

Restangular.one('Product', 1);

But that doesn't work for my OData endpoint. 但这不适用于我的OData端点。 I've looked at customGET , and setRequestInterceptor but I can't seem to find an example of or figure out how to change the route to match my endpoint. 我看过customGETsetRequestInterceptor但似乎找不到示例或弄清楚如何更改路由以匹配我的端点。 Preferably globally since all of my entities will have this same format. 最好在全球范围内使用,因为我的所有实体都将采用这种相同的格式。

Any help is greatly appreciated. 任何帮助是极大的赞赏。

Restangular documentation details how to create a custom configuration, you could do the same by editing the source restangular.js but this extensibility point allows us to keep a clean implementation that should be compatible with most customisations or future versions of RestAngular as well as allowing side-by-side standard REST APIs and OData v4 APIs. Restangular文档详细介绍了如何创建自定义配置,您可以通过编辑源代码restangular.js来执行此操作,但是此可扩展性点使我们能够保持整洁的实现,该实现应与大多数定制或RestAngular的未来版本兼容,并且允许并行标准REST API和OData v4 API。

How to create a Restangular service with a different configuration from the global one 如何使用与全局配置不同的配置创建Restangular服务

// Global configuration
app.config(function(RestangularProvider) {
  RestangularProvider.setBaseUrl('http://localhost:16486');
  RestangularProvider.setRestangularFields({ id: 'Id' });
});

// Restangular service targeting OData v4 on a the specified route
app.factory('ODataRestangular', function(Restangular) {
  return Restangular.withConfig(function(RestangularConfigurer) {
    RestangularConfigurer.setBaseUrl(RestangularConfigurer.baseUrl + '/odata');

    // OData v4 controller(key) Item Route convention
    RestangularConfigurer.urlCreatorFactory.path.prototype.base = function(current) {
      var __this = this;
      return _.reduce(this.parentsArray(current), function(acum, elem) {
        var elemUrl;
        var elemSelfLink = RestangularConfigurer.getUrlFromElem(elem);
        if (elemSelfLink) {
          if (RestangularConfigurer.isAbsoluteUrl(elemSelfLink)) {
            return elemSelfLink;
          } else {
            elemUrl = elemSelfLink;
          }
        } else {
          elemUrl = elem[RestangularConfigurer.restangularFields.route];

          if (elem[RestangularConfigurer.restangularFields.restangularCollection]) {
            var ids = elem[RestangularConfigurer.restangularFields.ids];
            if (ids) {
              // Crude Implementation of 'several', don't try this with more than
              // 60 Ids, performance degrades exponentially for large lists of ids.
              elemUrl += '?$filter=((Id eq ' + ids.join(')or(Id eq ') + '))';
            }
          } else {
            var elemId;
            if (RestangularConfigurer.useCannonicalId) {
              elemId = RestangularConfigurer.getCannonicalIdFromElem(elem);
            } else {
              elemId = RestangularConfigurer.getIdFromElem(elem);
            }

            if (RestangularConfigurer.isValidId(elemId) && !elem.singleOne) {
              elemUrl += '(' + (RestangularConfigurer.encodeIds ? encodeURIComponent(elemId) : elemId) + ')';
            }
          }
        }
        acum = acum.replace(/\/$/, '') + '/' + elemUrl;
        return __this.normalizeUrl(acum);

      }, RestangularConfigurer.baseUrl);
    };

    // add a response interceptor for OData v4:
    RestangularConfigurer.addResponseInterceptor(function(data, operation, what, url, response, deferred) {
      var extractedData;
      // Collection requests are 'getList' operations
      if (operation === "getList") {
        // return the value array
        extractedData = data.value;
      } else {
        // return the first item in the array
        if(data.value.length > 0)
          extractedData = data.value[0];
      }
      // pass the metadata back
      if(extractedData) {
        extractedData.meta = { context: data['@odata.context'] };
        if(data['@odata.count'])
          extractedData.meta.count = data['@odata.count'];
      }
      return extractedData;
    });
  });
});

Implementation example: 实施示例:

// Controller for list route
function ListCtrl($scope, ODataRestangular) {
  $scope.providers = ODataRestangular.all("providers").getList({ $count:true }).$object;
  $scope.some = ODataRestangular.several("providers", 15,16,17,18).getList();
  $scope.single = ODataRestangular.one("providers", 15).get();
}

Captured URLs from network Traffic: 从网络流量中捕获的URL:

http://localhost:16486/odata/providers?$count=true

http://localhost:16486/odata/providers?$filter=((Id eq 15)or(Id eq 16)or(Id eq 17)or(Id eq 18))

http://localhost:16486/odata/providers(15)

I struggled to try to write a custom service factory and to modify BreezeJS to work with OData v4 and only recently stumbled into Restangular, I can now really appreciate the extensible design that went into restangular, the general lack of documented client side framework support has been the Achilles heel that has prevented a wider adoption of OData v4. 我一直努力尝试编写一个自定义服务工厂,并修改BreezeJS以使其与OData v4一起使用,直到最近才偶然发现Restangular,现在我真的很欣赏进入restangular的可扩展设计,因为通常缺少文档化的客户端框架支持阿基里斯之heel阻止了OData v4的广泛采用。 I hope this answer contributes to getting more developers onboard with version 4. 我希望这个答案有助于使更多的开发人员使用版本4。

Restangular does not explicitly support OData APIs. Restangular不明确支持OData API。 You can make the basics work, but you would probably be better off using a library that does support querying an OData API, like breeze.js . 您可以使基础工作正常,但是最好使用支持查询OData API的库,例如breeze.js

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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