Code Monkey home page Code Monkey logo

angular-spring-data-rest's Introduction

Build Status Coverage Status Bower version npm version

angular-spring-data-rest

An AngularJS module with an additional interceptor which eases the work with a Spring Data REST backend.

See how it works

If you want to see the module in action, then check out the sample application which runs with Spring Boot and is super easy to setup: angular-spring-data-rest-sample

Table of contents

Quick start

To use the SpringDataRestAdapter Angular module with bower execute the following command to install the package:

bower install angular-spring-data-rest

or with npm:

npm install angular-spring-data-rest

Overview

Spring Data REST integrates Spring HATEOAS by default. This simplifies the creation of REST presentations which are generated with the HATEOAS principle.

Therefore the Spring Data REST responses have resources and embedded resources like in the following JSON response example:

{
    "_links": {
        "self": {
            "href": "http://localhost:8080/categories{?page,size,sort}",
            "templated": true
        }
    },
    "_embedded": {
        "categories": [
            {
                "name": "Test category 1",
                "_links": {
                    "self": {
                        "href": "http://localhost:8080/categories/1"
                    },
                    "parentCategory": {
                        "href": "http://localhost:8080/categories/1/parentCategory"
                    }
                }
            },
            {
                "name": "Test category 2",
                "_links": {
                    "self": {
                        "href": "http://localhost:8080/categories/2"
                    },
                    "parentCategory": {
                        "href": "http://localhost:8080/categories/2/parentCategory"
                    }
                }
            }
        ]
    },
    "page": {
        "size": 20,
        "totalElements": 2,
        "totalPages": 1,
        "number": 0
    }
}

The above response is the result of calling the endpoint to get all categories(http://localhost:8080/categories). It contains the _links property which holds an object with several named resources(e.g. self). These resources are used to navigate to a related entity(e.g. parentCategory) or to a specific endpoint defined by the backend.

The _embedded property holds an array of the requested items, and each of the items has again a _links property which defines the resources for the specific item. You can find more about how the responses of Spring Data REST look like here.

This Angular module provides two ways of processing a response from the Spring Data REST backend and ease the usage with the resources and embedded items:

  1. Using an instance of the SpringDataRestAdapter.
  2. Add the SpringDataRestInterceptor to the Angular $httpProvider.interceptors such that all responses are processed.

The SpringDataRestAdapter

The spring-data-rest Angular module provides a provider for the SpringDataRestAdapter object. This object is the core of the module and it processes a given response and adds the following additional properties/methods to it:

  1. _resources: this method wraps the Angular $resource function by default (this is exchangeable) and adds an easy way to retrieve the resources defined in the _links property. It is also used to retrieve all available resources of the given object. Read more about this method here.
  2. _embeddedItems: this property replaces the _embedded property and sets the named array (categories in the upper example response) with the embedded items as its value. Read more about this property here.

Spring Data REST also generates an index response when you make a GET response to the configured base url of the dispatcher servlet. This response looks like the following example:

{
  "_links" : {
    "users" : {
      "href" : "http://localhost:8080/users{?page,size,sort}",
      "templated" : true
    },
    "categories" : {
      "href" : "http://localhost:8080/categories{?page,size,sort}",
      "templated" : true
    },
    "accounts" : {
      "href" : "http://localhost:8080/accounts{?page,size,sort}",
      "templated" : true
    },
    ...
  }
}

This response shows all configured Spring Data REST repositories and the links to these resources. The SpringDataRestAdapter is also able to handle this response and to provide an easy method to retrieve all the available resources with the _resources method. Please read more about this here.

Another feature is that the SpringDataRestAdapter is able to automatically fetch the links of a resource and adds the response of the link as a property to the main response. Please read more about this here.

Usage of SpringDataRestAdapter

To use the SpringDataRestAdapter object you need to include the angular-spring-data-rest.js file (or the minified version) and add the spring-data-rest module as a dependency in your module declaration:

var myApp = angular.module("myApplication", ["ngResource", "spring-data-rest"]);

Now you are able use the SpringDataRestAdapter object and process a given response and you will get a promise back which resolves with the processes response:

SpringDataRestAdapter.process(response).then(function(processedResponse) {
  ...
});

The response can be a String or a promise from an $http.get() call (or any other promise which resolves the response) like in the following example:

var httpPromise = $http.get('/rest/categories');

SpringDataRestAdapter.process(httpPromise).then(function (processedResponse) {
    $scope.categories = processedResponse._embeddedItems;
});

For simplicity the rest of the examples assume that you already have the response present. Please read on on how to use the _resources method and the _embeddedItems property to ease the handling of resources and embedded items.

Usage of _resources method

The _resources property is added on the same level of the JSON response object where a _links property exists. When for example the following JSON response object is given:

var response = {
    "_links": {
        "self": {
            "href": "http://localhost:8080/categories{?page,size,sort}",
            "templated": true
        }
    },
    "_embedded": {
        ...
    }
    ...
}

Then the SpringDataRestAdapter will add the _resources method to the same level such that you can call it the following way (inside the then function of the promise):

SpringDataRestAdapter.process(response).then(function(processedResponse) {
  processedResponse._resources(linkName, paramDefaults, actions, options);
});

This _resources method is added recursively to all the properties of the JSON response object where a _links property exists.

The _resources method parameters and return type

The _resources method takes the following four parameters:

  • linkName: the name of the link's href you want to call with the underlying Angular $resource function. You can also pass in a resource object with parameters in the following way:
SpringDataRestAdapter.process(response).then(function(processedResponse) {
  var resourceObject = {
    "name": "self",
    "parameters": {
        "size": 20,
        "sort": "asc"
    }
  }
  processedResponse._resources(resourceObject, paramDefaults, actions, options);
});

This will call Angular $resource method by default (this is exchangeable) with the href of the self resource and will add the parameters size and sort as query string to the URL. If the resource object parameters and the paramDefaults parameters are set, then these two objects are merged such that the resource object parameters appear first in the new object and the paramDefaults parameters last.

  • paramDefaults: the default values for url parameters. Read more here.
  • actions: custom action that should extend the default set of the $resource actions. Read more here.
  • options: custom settings that should extend the default $resourceProvider behavior Read more here.

You are also able to add URL templates to the passed in linkName parameter. (This just works if you pass a string and not a resource object) The following example explains the usage:

SpringDataRestAdapter.process(response).then(function(processedResponse) {
  var resources = processedResponse._resources("self/:id", {id: "@id"});
  var item = resources.get({id: 1}).then(function(data) {
    item = data;
  };
});

The _resources method returns the Angular resource "class" object with methods for the default set of resource actions. Read more here.

If no parameter is given the _resources method will return all available resources objects of the given object. When for example the following JSON response object is given:

var response = {
    "_links": {
        "self": {
            "href": "http://localhost:8080/categories{?page,size,sort}",
            "templated": true
        },
        "parentCategory": {
            "href": "http://localhost:8080/categories/1/parentCategory"
        }
    },
    "_embedded": {
        ...
    }
    ...
}

Then the following call to the _resources method without any parameter will return an array of all available resource objects.

SpringDataRestAdapter.process(response).then(function(processedResponse) {
  var availableResources = processedResponse._resources();
});

The above call will result in the following return value:

[
    {
        "name":"self",
        "parameters": {
            "page": "",
            "size": "",
            "sort": ""
        }
    },
    {
        "name":"parentCategory"
    }
]

This functionality is useful if you want to first check all available resources before using the _resources method to retrieve the specific resource.

_resources usage example

This example refers to the JSON response in the Overview. If you want to get the parent category of a category you would call the _resources method the following way:

SpringDataRestAdapter.process(response).then(function(processedResponse) {
  var parentCategoryResource = processedResponse._embeddedItems[0]._resources("parentCategory");

  // create a GET request, with the help of the Angular resource class, to the parent category
  // url and log the response to the console
  var parentCategory = parentCategoryResource.get(function() {
    console.log("Parent category name: " + parentCategory.name);
  });
});

Exchange the underlying Angular $resource function

If you want to exchange the underlying call to the Angular $resource method then you are able to do this within the configuration of the SpringDataRestAdapter. By default it will use the Angular $resource function.

The following example shows how to set a custom function:

myApp.config(function (SpringDataRestAdapterProvider) {

    // set the new resource function
    SpringDataRestAdapterProvider.config({
        'resourcesFunction': function (url, paramDefaults, actions, options) {
            // do the call to the backend and return your desired object
        }
    });
});

The description of the parameters you will find here. You can also read more about the configuration of the SpringDataRestAdapter here (and how to use the $http service in the configuration phase)

Usage of _embeddedItems property

The _embeddedItems property is just a convention property created by the SpringDataRestAdapter to easily iterate over the _emebedded items in the response. Like with the _resources method, the SpringDataRestAdapter will recursively create an _embeddedItems property on the same level as a _embedded property exists for all the JSON response properties.

_embeddedItems usage example

This example refers to the JSON response in the Overview. If you want to iterate over all categories in the response you would do it in the following way:

SpringDataRestAdapter.process(response).then(function(processedResponse) {

  // log the name of all categories contained in the response to the console
  angular.forEach(processedResponse._embeddedItems, function (category, key) {
    console.log("Category name: " + category.name);
  });
});

Be aware that the original _embedded property gets deleted after the SpringDataRestAdapter processed the response.

How to automatically fetch links

The SpringDataRestAdapter is able to fetch specified links automatically. This means that if you have the following response:

{
    "_links": {
        "self": {
            "href": "http://localhost:8080/categories{?page,size,sort}",
            "templated": true
        },
        "anotherLink": {
            "href": "http://localhost:8080/anotherLink"
        }
    },
    ...
}

and you want to fetch the data from the anotherLink link then you just need to pass the link name to the SpringDataRestAdapter process function:

SpringDataRestAdapter.process(response, 'anotherLink').then(function(processedResponse) {
  var fetchedObject = processedResponse.anotherLink;
});

Now you are able to get the data from the processed resource by just accessing the property named anotherLink.

The SpringDataRestAdapter by default adds the response of the link to a property in the original response with the same name as the link.

If you want to process the returned response again with the SpringDataRestAdapter then you are able to set the recursive flag when creating it:

SpringDataRestAdapter.process(response, 'anotherLink', true).then(function(processedResponse) {
  ...
});

Now the response of the anotherLink will be processed the same way as the main response was processed. But be aware when setting the recursive flag to true, because when your responses of the links contain the same link name again, then it will end up in a infinite loop.

It will not fetch the self link as this would make no sense because the data is already in the response. The self key is also configurable. Read more here.

As a last configuration option you are able to set the fourth parameter called fetchMultiple of the process method which is used to define if a link is fetched multiple times if the same link is contained in multiple links and you want to resolve each one of them. The drawback is that it won't cache the responses in any way. So if you enable this then multiple network calls will be made. Here an example:

SpringDataRestAdapter.process(response, 'anotherLink', true, true).then(function(processedResponse) {
  ...
});

⚠️ If you set the fetchMultiple to true you could end up in an infinite loop if you have circular dependencies in your _links.

Fetch multiple or all links

If you want to fetch multiple links then you are able to add an array of strings with the given link names:

SpringDataRestAdapter.process(response, ['anotherLink', 'testLink']).then(function(processedResponse) {
  ...
});

and if you want to fetch all links, then you can use the predefined and also configurable fetchAllLinkNamesKey:

SpringDataRestAdapter.process(response, '_allLinks').then(function(processedResponse) {
  ...
});

Please read more here on how to configure the fetchAllLinkNamesKey.

Exchange the underlying fetch function

If you want to exchange the underlying function to fetch the links then you are able to do this within the configuration of the SpringDataRestAdapter. By default it will use the Angular $http function.

The following example shows how to set a custom function:

myApp.config(function (SpringDataRestAdapterProvider) {

    // set the new resource function
    SpringDataRestAdapterProvider.config({
        'fetchFunction': function (url, key, data, fetchLinkNames, recursive) {
            // fetch the url and add the key to the data object
        }
    });
});

The description of the parameters you will find here. You can also read more about the configuration of the SpringDataRestAdapter here (and how to use the $http service in the configuration phase)

The fetch method parameters

The parameters for the fetch method are the following:

  • url: The url of the link from which to fetch the data.
  • key: The name of the link which is used to name the property in the data object.
  • data: The data object in which the new property is created with the response of the called url.
  • fetchLinkNames: The fetch link names to allow to process the fetched response recursiveley
  • recursive: True if the fetched response should be processed recursively, false otherwise.

How to use SpringDataRestAdapter with promises

The SpringDataRestAdapter is also able to process promises instead of data objects. The data object which is passed to the specified promise when it is resolved needs to be in the following formats:

{
    data: {
        "_links": {
            "self": {
                "href": "http://localhost:8080/categories{?page,size,sort}",
                "templated": true
            },
            "anotherLink": {
                "href": "http://localhost:8080/anotherLink"
            }
        },
        // the rest of the JSON response
        ...
    }
}

or

{
    "_links": {
        "self": {
            "href": "http://localhost:8080/categories{?page,size,sort}",
            "templated": true
        },
        "anotherLink": {
            "href": "http://localhost:8080/anotherLink"
        }
    },
    // the rest of the JSON response
    ...
}

The data property of the second format of the promise object is the JSON response of the back end. To process such a promise you need to call the SpringDataRestAdapter like in the following example:

SpringDataRestAdapter.process(promise).then(function(processedResponse) {
    // you can now use the processedResponse as any other processed response from the SpringDataRestAdapter
};

You can also right away use the promise support with the Angular $http.get() method like in the following example:

SpringDataRestAdapter.process($http.get('categories')).then(function(processedResponse) {
    $scope.categories = processedResponse._embeddedItems;
};

Configuration of the SpringDataRestAdapter

The SpringDataRestAdapter is designed to be configurable and you are able to configure the following properties:

  • linksKey (default: _links): the property name where the resources are stored.
  • linksHrefKey (default: href): the property name where the URL is stored in a link object.
  • linksSelfLinkName (default: self): the name of the self link in the links object.
  • embeddedKey (default: _embedded): the property name where the embedded items are stored.
  • embeddedNewKey (default: _embeddedItems): the property name where the array of embedded items are stored.
  • embeddedNamedResources (default: false): true if the embedded resources names (can be more than one) should be left as is, false if they should be removed and be replaced by the value of the first embedded resource
    • Example if set to true:
    {
        ...
        "_embeddedItems": {
            "categories": [...]
        }
        ...
    }
    • Example if set to false:
    {
        ...
        "_embeddedItems": [...]
        ...
    }
  • hrefKey (default: href): the property name where the url is stored under each specific link.
  • resourcesKey (default: _resources): the property name where the resource method is stored.
  • resourcesFunction (default: undefined): the function to use to call the backend. Read more how to do this here
  • fetchFunction (default: undefined): the function to use to fetch data from the backend. Read more how to do this here
  • fetchAllKey (default: _allLinks): the key to pass to the SpringDataRestAdapter to fetch all available links

You are able to configure the SpringDataRestAdapter provider in a Angular configuration block in the following way:

myApp.config(function (SpringDataRestAdapterProvider) {

    // set the links key to _myLinks
    SpringDataRestAdapterProvider.config({
        'linksKey': '_myLinks'
    });
});

The config method of the SpringDataRestAdapterProvider takes a configuration object and you are able to override each value or completely replace the whole configuration object. The default configuration object looks like this:

{
    "linksKey": "_links",
    "linksHrefKey": "href",
    "linksSelfLinkName": "self",
    "embeddedKey": "_embedded",
    "embeddedNewKey": "_embeddedItems",
    "embeddedNamedResources": false,
    "resourcesKey": "_resources",
    "resourcesFunction": undefined,
    "fetchFunction": undefined,
    "fetchAllKey": "_allLinks"
}

If you want to use the $http service inside the fetch function in the configuration phase then you need to use the Angular injector to get the $http service:

myApp.config(function (SpringDataRestAdapterProvider) {

    // set the new fetch function
    SpringDataRestAdapterProvider.config({
        fetchFunction: function (url, key, data, fetchLinkNames, recursive) {
            var $http = angular.injector(['ng']).get('$http');

            $http.get('/rest/endpoint').then(function (responseData) {
                console.log(responseData);
            })
        }
    });
});

The SpringDataRestInterceptor

If you want to use the SpringDataRestAdapter for all responses of the Angular $http service then you can add the SpringDataRestInterceptor to the $httpProvider.interceptors in an Angular configuration block:

myApp.config(function (SpringDataRestInterceptorProvider) {
    SpringDataRestInterceptorProvider.apply();
});

The apply method will automatically add the SpringDataRestInterceptor to the $httpProvider.interceptors.

Dependencies

The spring-data-rest Angular module requires the ngResource Angular module.

Release notes

Check them here: Release notes

Acknowledgements

When I first searched for an Angular module for Spring Data REST I just found the marvelous project of Jeremy which is useful if you just use Spring HATEOAS. So please have a look at his angular-hateoas project because he gave me the full permissions to use his code base and project structure for this project here. At this point I want to thank him for his nice work.

License

This Angular module is available under the MIT license.

(c) All rights reserved Guy Brand

angular-spring-data-rest's People

Contributors

bagnier avatar bryant1410 avatar guylabs avatar myosotys avatar tcrossland avatar tonycapone avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

angular-spring-data-rest's Issues

Automatic fetched data is not being processed

Hi Guy,

I have another one :)

After automatic fetching data there is the usual "_embedded" attribute in it and not the "_embeddedItems" attribute.

I researched a little bit in the code and found out that the fetched data is actually not being processed. This is change, which fixes this issue.
Line 107:

if (recursive) {
   return processData(responseData.data, fetchLinkNames, true).then(function (processedData) {
        data[key] = processedData;
   });
} else {
    return processData(responseData.data).then(function (processedData) {
       data[key] = processedData;
    });
}

Handling HTTP code 204

Hi @guylabs

Somehow API will return 204 rather than 404 for unknown links.
How can i handle this 204 code ? Now when i get 204 all of request will be break and nothing happened.

Thanks

Release of version 0.4.6?

Hi Guy,

could you please release version 0.4.6 with the latest fixes? That would be great!

Thanks in advance
Torsten

Automatically retrieve links in an object property

Is there a way to automatically retrieve links in a payload that looks like the below?

personprojectsesByPersonid: [ ],
personskillsesByPersonid: [
    {
        _links: {
            skillsBySkillid: {
                href: "http://localhost:8985/api/skills/1"
            },
            personByPersonid: {
                href: "http://localhost:8985/api/people/4"
            }
        }
    },
    {
        _links: {
            skillsBySkillid: {
                href: "http://localhost:8985/api/skills/2"
            },
            personByPersonid: {
                href: "http://localhost:8985/api/people/4"
            }
        }
    }
],

Fetching resources compatible with saving

Hi,
I have a manyToOne relation between Type and Channel entities. When I prefetch the type and channels type.channel gets the embedded object inside. This is a problem when I try to save the resource because in order to work spring data rest is expecting type.channel to be an URL.
Is any possibility of saving resources work properly with prefetched children?
Thanks in advance.

Not able to fetch underlying link data

Hi Guy,

I'm writing to you as a last resort to help solve my current issue. I have used your code earlier to fetch the underlying links data and it worked fine. Currently when I'm trying to use it, it is not working.
Not sure why.

Below is my code: I have included all the required dependencies and compared the code with your example. Everything seems fine.

JSON:

{ "amount": 0, "year": 2017, "month": 3, "assessmentDate": "2017-03-07T18:30:00.000+0000", "transactionBalance": null, "_links": { "self": { "href": "http://localhost:8080/totalcharges/1046" }, "currentCharges": { "href": "http://localhost:8080/totalcharges/1046" }, "homeId": { "href": "http://localhost:8080/totalcharges/1046/homeId" }, "communityInfo": { "href": "http://localhost:8080/totalcharges/1046/communityInfo" }, "hoaId": { "href": "http://localhost:8080/totalcharges/1046/hoaId" }, "assessmentRuleType": { "href": "http://localhost:8080/totalcharges/1046/assessmentRuleType" } } }

JS Code:

SpringDataRestAdapter.process($http.get('/totalcharges/search/findByHoaId_hoaId?hoaId=1289','homeId',true)).then(function (processedResponse) { console.log("Inside adapter all"); $scope.totalCharges = processedResponse._embeddedItems; console.log('attendance users '+ JSON.stringify($scope.totalCharges)); });

Can you help me with some troubleshooting steps?

Thanks,
Kiran

Given data is not of type object.

I'm experiencing problems when processing spring data rest responses like:

{
  "_embedded" : {
    "timeSeries" : [ {
      "id" : 1400,
      "lastDate" : "1991-01-06T23:00:00.000+0000",
      "data" : [ 89.34576078, 90.86743282, 91.5561206, 91.52988487 ],
      "tsDataType" : "CLOSE",
      "_embedded" : {
        "asset" : {
          "id" : 15,
          "ticker" : "BUHY:IND",
          "description" : "Bloomberg USD High Yield Corporate Bond Index",
          "provider" : "BLOOMBERG",
          "assetClass" : "INDEX",
          "indexType" : "BOND",
          "assetClassForType" : "INDEX"
        }
      },
      "_links" : {
        "self" : {
          "href" : "http://localhost:8080/alphaquant-web/restdata/timeSeries/1400"
        }
      }
    }, {
      "id" : 52,
      "lastDate" : "2015-05-31T22:00:00.000+0000",
      "data" : [ 156.931961, 157.007523, 156.968109, 157.001785, 156.967865, 100.0 ],
      "tsDataType" : "OPEN",
      "_embedded" : {
        "asset" : {
          "id" : 15,
          "ticker" : "BUHY:IND",
          "description" : "Bloomberg USD High Yield Corporate Bond Index",
          "provider" : "BLOOMBERG",
          "assetClass" : "INDEX",
          "indexType" : "BOND",
          "assetClassForType" : "INDEX"
        }
      },
      "_links" : {
        "self" : {
          "href" : "http://localhost:8080/alphaquant-web/restdata/timeSeries/52"
        }
      }
    } ]
  }
}

I get this exception
"Given data '15' is not of type object."
when processing the response with SpringDataRestAdapter.process()

Fetch recursive causes infinite loop

Hi..

I wanna ask..

  1. Can i use recursive without get infinite loop?
  2. If can't, can i fetch another link in multi level (another link inside another link)?

Thank You

Handling spring data rest exception

My spring data rest implementation throws exception in some cases. I would like to handle that exception in the error part of the promise call. The issue is that the error part is not called.

var myHttpPromise = $http.post('http://localhost:54000/api/v1/systems', vm.data);
SpringDataRestAdapter.process(myHttpPromise)
    .then(function (processedResponse) {
    }, function(response) {
            console.log(response);
    });

I looked at the code in angular-spring-data-rest-interceptor-provider.js and I was wondering if you should reject the promise in case of erros.

return SpringDataRestAdapter.process(response.data).then(function (processedResponse) {
                                response.data = processedResponse;
                                return response;
, function(response) {
            return $q.reject(response);
    });

Populate all references to the same resource

I've got a call that will return multiple entities. I've configured the SpringDataRestAdapter to recursively resolve multiple links.

This actually works fine, but my problem is the filter that ensures that each URL is called only once which leads to unpopulated fields if one of the entities has a link to an resource that was already fetched for another entity. This leaves all references after the first one empty.

While I do appreciate that each URL is only called once (I've already got 29 requests with only one call of SpringDataRestAdapter), it would be extremely useful if other entities that reference the same links would get populated aswell.

Problem with automatically fetching

Hi Guy,

first of all I want to thank You for Your great work. I'm trying to use the fetch feature of the module and it didn't work for me at all. The resolvedResponse is always the same as before. I'm using v0.3.1

Than I tried the https://github.com/guylabs/angular-spring-data-rest-sample. The sample about automatic link fetching delivered a lot of 404s in the chromes console.

I have created a fork for the example with working parent structure and a pull request in the angular-spring-data-rest-sample repository so You can verify my problem.

I have also looked at the js-code and I'm almost sure that the problem is in the fetch function and the usage of the $http without resolving the promise.

Hope this can help You.

BR,
Shari

POST with Spring projections?

Hi,

I have a collection of items, for which I have a projection setup in Spring boot, so that it inlines some data that I don't want to fetch for each item individually.

I'm doing the save with the following code:

this.clusterResponse._resources('self').save({ name: cluster.name, analysisMethods: cluster.analysisMethods.map((method) => method._links.self) },

but this returns me a resource with links, not taking into account the projection (since you need to add this explicitly by adding ?projection=name.

The only thing I want is to create a new cluster in this case, and add the item to the list, so I don't need to refresh the entire list or refetch the invidual item. Any examples on how to do this?

How to chain resources calls

I would like to call several resources like that:

POST http://lolcahost:54000/api/v1/portfolios
PATCH http://lolcahost:54000/api/v1/portfolios/1
GET http://lolcahost:54000/api/v1/portfolios/1/evaluate
GET http://lolcahost:54000/api/v1/portfolios/1
GET http://lolcahost:54000/api/v1/portfolios/1/summaries
Process the output

I wrote that code but I am not sure it's the correct way to use SpringDataRestAdapter. I also have an issue with one of the processed response that does not have a _resources object.

// POST http://lolcahost:54000/api/v1/portfolios
var myHttpPromise = $http.post('http://localhost:54000/api/v1/portfolios', {});
SpringDataRestAdapter.process(myHttpPromise)
    .then(function (processedResponse) {
        // PATCH http://lolcahost:54000/api/v1/portfolios/1
        var self = processedResponse._links.self.href;
        var data = {};
        return SpringDataRestAdapter.process($http.patch(self, data));
    })
    .then(function (processedResponse) {
        // GET http://lolcahost:54000/api/v1/portfolios/1/evaluate
        var resources = processedResponse._resources("self/:id", {id: "evaluate"});
        return SpringDataRestAdapter.process(resources.get());
    })
    .then(function (processedResponse) {
        // GET http://lolcahost:54000/api/v1/portfolios/1
        console.log(processedResponse);
        // ERROR processedResponse does not have a _resources property
        var resources = processedResponse._resources("self");
        return SpringDataRestAdapter.process(resources.get());
    .then(function (processedResponse) {
        // GET http://lolcahost:54000/api/v1/portfolios/1/summaries
        return processedResponse._resources('summaries');
    })
    .then(function (summaries) {
        // Process the output
        console.log(summaries);
    }, function (response) {
        console.log(response);
        console.log(response.data.error);
        logger.error(response.data.error);
    });

Undefined Methods

I have:

64: console.log(processedResponse);
65: console.log(processedResponse._embeddedItems);
66: console.log(processedResponse._resources());

The contents of processedResponse look correct, but _embeddedItems and _resources return squat.

Line 64 looks fine.
Line 65 is undefined.
Line 66 is undefined.

Thanks.

"Given data '' is not of type object." when empty array response.

Hi Guy, it's me again..

I'm working with the configuration 'embeddedNamedResources' to true. With this configuration when I receive a response like the following:

{
  "_embedded": {
    "externalUsers": []
  },
  "_links": {
    "self": {
      "href": "http://localhost:8080/Users/58130325-a4c7-483f-a37e-3ceee4ba50ba/externalUsers"
    }
  }
}

So there aren't any 'ExternalUser' object in the response. In this case, the call to the service responds with the error "Given data '' is not of type object.". This problem doesn't occur when working with the configuration 'embeddedNamedResources' setted to false (default).

Here is the angular code where the error occurs:

userService.get({'id': auth.getUserId()}).$promise.then(function(user){
  user._resources('externalUsers').get().$promise.then(function (externalUsers) {
    ...
  }).catch(function (error) {
    console.log(error);  //execution comes here and error contains the message
  });
});

Thank you!

Feature Request: Reject with message if link not found

Hi Guy,

upfront: You can close this one if this is not the desired behavior.

If I call processData for automatic link fetching with link name that doesn't exist in the given data, there is no feedback, that the link name is wrong.

For example SpringDataRestAdapter.process(httpPromise, 'parent1', true) called in the example app just ignores that there is no parent1 link and returns the data unmodified.

I would expect this to result in an error like deferred.reject("The given link name: " + name + " can not be found") This would help to developers with messy API-Doc ;)

BR,
Shari

Correct use of resources children

Hey Guy,

  Could I ask you a question if you have time? Sorry I realise this should have been an issue in it's own right. 

screen shot 2016-03-17 at 21 02 07

I'm using SpringDataRestAdapter to interact with my spring data rest api. From the screen shot you can see that I've just loaded all the questions and I'm attempting to load their answers (one-to-many) relationship. In the debug window the _embeddedItems array is an array of Questions with _links to each questions answers. I'm trying to prompt SpringDataRestAdapter to autoload the answers by passing 'answers' as an argument to the processWithPromise call but to no avail.

The urls look like http://localhost:8080/api/questions http://localhost:8080/api/question/1/answers

The Question.loadAnswers(question) call is commented out... It works in that it loads the question's answers but I felt I was using the framework incorrectly.

Here is the method

Question.loadAnswers = function (question) {

            question.answers = question.answers? question.answers : [];

            angular.forEach(question._links.answers, function (answerLink) {
                var deferred = $http.get(answerLink);
                return SpringDataRestAdapter.processWithPromise(deferred).then(function (data) {
                    question.answers = data._embeddedItems;
                });
            });
        };

Congratulations on an excellent piece of coding Guy! I've also posted this question up on stackoverflow in case the issue is with my understanding of promises as opposed to how to use the framework :)

http://stackoverflow.com/questions/36072090/springdatarestadapter-load-child-resources

Thanks, Mark.

Working with ngResource services?

Your projects seems promising but I have some difficulties with the documentation. You write:

Now you are able to instantiate the SpringDataRestAdapter object and process a given response:

var processedResponse = new SpringDataRestAdapter(response);

What is the 'response'? Do I have to get it "manually" with $http? What about ngResource that is used by angular-spring-data-rest itself?

Normally with ngResource you can create and use a resource service like this:

myApp.factory('Category', function ($resource) {
    return $resource('category/:categoryId', {categoryId: '@id'});
}

$scope.categories = Category.query(); // in the controller

How can I use angular-spring-data-rest this way to also make use of all ngResource convenience functions like 'get' or 'save'?

Collection of Links

I have some HAL+JSON data which looks like:

{
  "_embedded": {},
  "_links": {
    "self": {
      "href": "http://localhost/api/article"
    },
    "api/article": [
      {
        "href": "/api/article/1"
      },
      {
        "href": "/api/article/2"
      },
      {
        "href": "/api/article/3"
      },
      {
        "href": "/api/article/4"
      }
    ]
  }
}

Notice that the "api/article" key in "_links" has an array of objects. This is similar to the "admins" link on the HAL specification page: http://stateless.co/hal_specification.html

When I try to use the following bit of code:

SpringDataRestAdapter.process($http.get('/api/article'), 'api/article').then(function(processedResponse) {
    console.log(processedResponse);
});

I get the following exception:

angular.js:13550` Error: The provided resource name 'api/article' has no valid URL in the 'href' property.
    at checkUrl (angular-spring-data-rest.js:507)
    at getProcessedUrl (angular-spring-data-rest.js:349)
    at angular-spring-data-rest.js:281
    at Object.forEach (angular.js:336)
    at angular-spring-data-rest.js:267
    at processQueue (angular.js:15961)
    at angular.js:15977
    at Scope.$eval (angular.js:17229)
    at Scope.$digest (angular.js:17045)
    at Scope.$apply (angular.js:17337)

Doing a quick bit of looking through the code... it looks like perhaps an array of links for the same key is not supported? Is this the case or am I doing something else wrong? I was expecting "processedResponse" to be an array of promises. How would you handle a collection of links?

Relative _links

Hello.

I would like to try out this Angular plugin, but in my Spring Data Rest responses, all the _link contains the servlet context path. My application is under an HTTP server, so URL with a context path are all remapped to a wrong URL.

This is an example GET respnose on http://localhost/rest/measure


{
  "_links" : {
    "self" : {
      "href" : "http://localhost/raspberry-grow-room/rest/measure{?page,size,sort}",
      "templated" : true
    }
  },
  "_embedded" : {
    "measure" : [ {
      "unit" : "°C",
      "iconClass" : "fa fa-fire",
      "_links" : {
        "self" : {
          "href" : "http://localhost/raspberry-grow-room/rest/measure/1"
        },
        "locales" : {
          "href" : "http://localhost/raspberry-grow-room/rest/measure/1/locales"
        }
      }
    } ]
  },
  "page" : {
    "size" : 20,
    "totalElements" : 1,
    "totalPages" : 1,
    "number" : 0
  }
}

Can you see the problem? I want to remove the /raspberry-grow-room base path. Can you please help me?

Egidio

Allow AngularJS dependency version 1.4

Your bower.json requires AngularJS to be version ~1.3.15 which means any patch level greater than 1.3.15 but definitely a version less than 1.4. In my current project I would like to use the most recent AngularJS version 1.4.8 together with your module. The only way to make it work is to provide a custom resolution in my bower.json which forces Bower to use version 1.4.8. This is a dirty workaround and produces warning during the build process.
I have already tested your module in conjunction with AngularJS 1.4.8 and it seems to work fine for my use cases. Therefore, could you please update your bower.json to allow the recent version?

For example you could use the caret prefix instead: ^1.3.15 - This allows any minor version greater than 1.3.15 and less than 2.0, see https://github.com/npm/node-semver#caret-ranges-123-025-004

URL templates

SDR by default produces urls with templates similar to:
http://localhost:8080/api/users/0
Is it possible to get a $resource function with such template from a processed resource? So that api._resources('users') would return equivalent of $resource('/api/users/:userId'). Is this feature currently available?

Inheritance support

Hi,

When we have a class "A" with two subclasses "B" and "C", we could have a spring data rest repository for the class "A" which would return all "B" and "C" objects in the following format:

{
 "_embedded": {
    "as": [ "A" class objects ],
    "bs": [ "B" class objects ]
  },
  "_links": { ... },
    "profile": { ... },
    "search": { ... }
  },
  "page": { ... }
}

Would it be possible to know which is the class of each embedded object?

Thank you.``

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.