AngularJS 与超媒体 (HATEOAS) : how to use hypermedia urls accross states

标签 angularjs rest hateoas hypermedia

我有一个 AngularJS 申请 ui路由器消耗 REST API 超媒体 .总体思路是让 API 为其各种调用生成 url,并阻止客户端自己构建 url。

例如,在获取产品列表时,API 返回的内容如下:

[
  {
    "id": 1,
    "name": "Product A",
    "_links": {
      "self": {
        "href": "http://localhost:4444/api/products/1",
        "name": null,
        "templated": false
      },
      "actions": []
    }
  },
  {
    "id": 2,
    "name": "Product B",
    "_links": {
      "self": {
        "href": "http://localhost:4444/api/products/2",
        "name": null,
        "templated": false
      },
      "actions": []
    }
  }
]

所以,问题是:我想 导航到详细信息 的一种产品。我有来自集合超媒体的 API url。但是,在更改状态时,我需要以某种方式将此 url 传递给详细状态,以便详细状态的 Controller 可以获取产品。

UI url 与 API url 完全解耦,即客户端有自己的 url 方案。

实现此目标的最佳方法是什么 ,一直保持客户端无状态并且每个页面都可以添加书签?

一种解决方案是通过 ui router 传递 url的data属性(property)。但是,该页面不能添加书签。另一种方法是在 UI url 中传递 API url,这将使页面保持可收藏(只要 API url 不变),但 UI url 会非常难看。

还有其他想法吗?

除非我对此非常错误,否则我不是在寻找模板化解决方案,即 API 返回需要由客户端注入(inject)参数的 url 模板的解决方案。关键是 url 已经填充了数据,因为某些 url 比上面提供的示例要复杂得多。

最佳答案

我以前遇到过几次这个问题。我在下面逐步详细说明了我的首选解决方案。最后两个步骤专门针对您在帖子中概述的问题,但可以在整个应用程序中应用相同的原则。

1. 根端点

首先在 API 级别定义一个根端点。相应的根实体是顶级链接的集合,换句话说,客户端需要直接访问的链接。

这个想法是 客户端只需要知道一个端点 ,即根端点。这样做的好处是您无需将路由逻辑复制到客户端,并且 API 的版本控制变得更加容易。

根据您的示例,此根端点可能如下所示:

{
    "_links": {
      "products": {
        "href": "http://localhost:4444/api/products",
      }
    }
}

2. 抽象主状态

接下来定义一个抽象的 super 状态,它位于状态层次结构的顶部。我通常将此状态命名为 main 以避免与根端点混淆。这个 super 状态的任务是解析根端点,比如:
$stateProvider.state('main', {
    resolve: {
        root: function($http) {
         return $http.get("http://localhost:4444/api/").then(function(resp){
              return resp.data;
         });
        }
    }
});

3. 产品概览状态作为主状态的子状态

然后创建一个产品状态,它是主状态的后代。因为根端点已经解析,我们可以在这种状态下使用它来获取产品 API 的链接:
 $stateProvider.state('products', {
    parent: 'main',
    url: "/products",
    resolve: {
        products: function($http, root) {
         return $http.get(root._links.products.href).then(function(resp){
              return resp.data;
         });
        }
    }
});

4. 产品详细状态作为产品状态的子状态

最后,创建一个产品详细信息状态作为上述产品状态的子状态。通过 $stateParams 传入产品 ID (因此,它是客户端 URI 的一部分)并使用它从父级解析的产品数组中检索正确的产品:
$stateProvider.state('products.product', {
    url: "/{productId}"
    resolve: {
        product: function($http, $timeout, $state, $stateParams, $q products) {
         var productId = parseInt($stateParams.productId);
         var product;

        for (var i = 0; i < products.length; i++) {
            product = products[i];
            if (product.id === productId) {
                return $http.get(product._links.self.href).then(function(response){
                    return response.data;
                });
                }
        }

        // go back to parent state if no child was found, do so in a $timeout to prevent infinite state reload
        $timeout(function(){
            $state.go('^', $stateParams);
        });

        // reject the resolve
        return $q.reject('No product with id ' + productId);
    }
});

您可以将上面的代码移动到服务中,以使您的状态更轻量级。

希望这可以帮助!

关于AngularJS 与超媒体 (HATEOAS) : how to use hypermedia urls accross states,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38998858/

相关文章:

angularjs - 使用 ng-token-auth 检索身份验证状态和当前用户

delphi - 在 Delphi XE2 中使用 PayPal REST 客户端

rest - 在 REST : WADL or not IDL, 上,以下方法对吗?

javascript - 使用悬停和 Angular 更改 div 的颜色时出错

javascript - ng-click 编译后多次触发

node.js - 在 REST 应用程序中处理数据库错误时,什么被视为标准?

rest - 使用 REST API 存储、流式传输视频和处理请求

json - 任何人都可以对 CURIE 以及如何使用它们提供一个很好的解释吗?

api - 具有经过身份验证的用户的 REST api 的无状态性

javascript - 使用 Angularjs 的动态网格