单页面应用程序和RESTful API

Ria*_*ana 6 rest hateoas angularjs single-page-application

真正的RESTful API利用超媒体,以便客户端仅依靠服务器提供的动态超媒体来浏览应用程序(称为HATEOAS的概念)

这个概念很容易适用于Web应用程序,但是如何将它应用于单页应用程序,因为SPA通常在内部管理其状态(就导航而言,不依赖于服务器)?

我的感觉是SPA无法充分利用RESTful API或者我错过了什么?

谢谢

Riana

iam*_*ddy 5

单页面应用程序(SPA)可以充分利用启用了HATEOAS的RESTful API,例如SPA(带有ui-rauter的angularJS用于状态转换)

对于计算机到计算机的交互,我们通过在表示中嵌入链接来广告协议信息,就像我们在人类网络中一样.

在消费者服务互动中: -

  1. 消费者向服务的入口点提交初始请求.
  2. 该服务处理请求并使用填充了链接的资源表示进行响应.
  3. 消费者选择其中一个链接转换到交互中的下一步.
  4. 在几个这样的互动的原因,消费者朝着它的目标前进.

插图与示例代码 服务入口点

var applicationServices = angular.module('applicationServices', ['ngResource']);
        userDetailServices.factory('DetailService', ['$resource',function($resource){
            return $resource('api/users', {},{
                        query : {
                            method : 'GET',
                            headers : {'Accept': 'application/json'},
                            isArray: true
                      }
              });
        }]);
Run Code Online (Sandbox Code Playgroud)

超媒体是关于松耦合的,在开发服务时我们通过减少耦合从消费者那里抽象细节,但无论松散耦合的程度如何,消费者必须拥有足够的信息以便与我们的服务交互

假设这api/users是服务的入口点,也是SPA知道的唯一网址,它将使用填充了进一步交互链接的资源表示进行响应.

{
    "links": [
        {
            "rel": "self",
            "href": "http://localhost:8080/persons{?page,size,sort}"
        }
    ],

    "users": [
        {
            "id": "3415NE11",
            "firstName": "somefirstname",
            "lastName": "lastname",
            "emailAddress": "someemail",
            "links": [
                {
                    "rel": "section1",
                    "href": "http://localhost:8080/persons/3415NE11/section1
                },
                {
                    "rel": "section2",
                    "href": "http://localhost:8080/persons/3415NE11/section2
                },
                {
                    "rel": "gallery,
                    "href": "http://localhost:8080/filesRepo/profile/3415NE11/images
                },
            ]
        }
    ],
    "page": {
        "size": 20,
        "totalElements": 2,
        "totalPages": 1,
        "number": 0
    }
}
Run Code Online (Sandbox Code Playgroud)

您的SPA从有关资源的部分信息开始,并将按需提供其他资源信息

  • 具有部分用户信息的用户列表(启动时,手头知道url)
  • 用户资源信息的第1部分(按需,从上面的1中查找URL)
  • 用户资源信息的第2部分(按需查找以上1中的URL)
  • 用户资源信息的第n部分(按需,从上面的1中查找URL)

使用ui-router导航

angular.module('userApp', [
        'ui.bootstrap',
        'ui.router',
        'userControllers',
        'userServices'
     ])
     .config(
            [ '$stateProvider', '$urlRouterProvider', '$httpProvider', function($stateProvider,$urlRouterProvider, $httpProvider) {

                $stateProvider
                      .state('users', {
                        url: '/users-index',
                        templateUrl: 'partials/users-index.html',
                        resolve:{ // Your SPA needs this on start-up
                               DetailService:function(DetailService){
                                  return DetailService.query();
                           }
                        },
                        controller:'UserController',
                      })
                      .state('users.section1', {
                        url: '/user-section1',
                        templateUrl: 'partials/user-section1.html',

                      })
                      .state('users.section2', {
                        url: '/users-section2',
                        templateUrl: 'partials/users.section2.html'
                      })
                       .state('users.gallery', {
                        url: '/users-gallery,
                        templateUrl: 'partials/users-gallery.html'
                      });

                 $urlRouterProvider.otherwise('/');
  }])
  .run([
        '$rootScope', 
        '$location',
        '$state', 
        '$stateParams'
        function($rootScope, $location,$state, $stateParams) {
          $rootScope.$state = $state;
          $rootScope.$stateParams = $stateParams;
        }
        ]);
Run Code Online (Sandbox Code Playgroud)

用于angularJS SPA的UserController

(function() {
    var userControllersApp = angular.module('userControllers', ['ngGeolocation']);
      userControllersApp.controller('UserController',
              ['$scope',
               '$rootScope',
               '$http',
               '$state',
               '$filter',
               'DetailService',
               function($scope,$rootScope,$http,$state,$filter,DetailService) {

             DetailService.$promise.then(function(result){
                 $scope.users = result.users;
             });


        $scope.userSection1= function(index){

           var somelink = $filter('filter')($scope.users[index].links, { rel: "section1" })[0].href;
          $http.get(somelink).success(function(data){
             $state.go("users.section1");
          });
         // $http.post(somelink, data).success(successCallback);

        };   

        $scope.userSection2= function(index){

           var somelink = $filter('filter')($scope.users[index].links, { rel: "section2" })[0].href;
         $http.get(somelink).success(function(data){
             $state.go("users.section2");
          });
         // $http.post(somelink, data).success(successCallback);

        };

        $scope.userSection3= function(index){
           var somelink = $filter('filter')($scope.users[index].links, { rel: "gallery" })[0].href;
          $http.get(somelink).success(function(data){
             $state.go("users.gallery");
          });
         // $http.post(somelink, data).success(successCallback);

        };

    } ]);

})();
Run Code Online (Sandbox Code Playgroud)

超媒体的美妙之处在于它允许我们以声明性和恰到好处的方式传达协议信息,作为应用程序资源表示的一部分

使用嵌入式进一步interactions.look链接如何$ scope.users somelink正在解决中section1(),section2()section(3)功能.

您的Angular SPA导航(users-index.html)可以是

 <div  ng-repeat="user in users">
   <label>{{user.firstname}}</label>
    <button type="button" class="btn  btn-xs "  ng-click="section1($index)">Section1</button>
<button type="button" class="btn  btn-xs "  ng-click="section2($index)">Section2</button>
<button type="button" class="btn  btn-xs "  ng-click="section3($index)">Section3</button>
    </div>
Run Code Online (Sandbox Code Playgroud)

现在,您的SPA状态转换依赖于服务器提供的动态链接来浏览应用程序,这表明SPA可以充分利用启用了HATEOAS的RESTful API. my apologies for the very long explanation ,hope it helps.

  • 请问您如何处理深层链接?如果用户直接请求URL / user-section1会发生什么。或者,因为它指的是特定用户,所以也可以很容易地是“ / users / 123123 / section1”。我的问题不是关于如何使用angular进行此操作,而是要使用任何一种SPA。 (2认同)

Bog*_*dan 3

SPA 的特殊性在于它通过在客户端构建的 UI 提供更流畅的用户体验,而不是在服务器上构建并仅在客户端上呈现。

SPA 不一定需要保持自己的状态,服务器仍然可以驱动与 HATEOAS 的交互。对于超媒体驱动的 SPA 或以其他方式维护其自身状态并访问预定义资源,完全取决于应用程序。

组合也可以发挥作用,例如 SPA 维护某些部分的自身状态,而其他部分则由服务器驱动。从这个意义上说,请考虑例如分页结果。SPA 可能会访问特定的 URL(事先了解该资源)以获取结果列表,并对这些结果进行分页。服务器在结果中嵌入链接,以便客户端可以将它们导航到下一页和上一页(您通过服务器提供的超媒体与应用程序交互)。

我的感觉是 SPA 无法充分利用 RESTful API,还是我错过了什么?

正如我上面所说,这取决于您的应用程序。如果超媒体驱动的应用程序有意义,那么就可以这样构建。另一方面,如果让 SPA“自行驱动”更有意义,那么强制使用 HATEOS 可能不是一个好主意。