I was wondering if there were any features hidden in Angular or exposed by some 3rd-party libraries to easily create HATEOAS-compliant Restful clients.
On backend side, I am using Spring Data/REST to produce an HATEOAS JSON API.
Consuming it, though, is quite another story.
For instance, I've got those 3 entities:
Company {name, address}
Employee {firstName, lastName, employer[Company]}
Activity {rate, day, employee[Employee], client[Company]}
and requesting an activity (the most complex entity of the model) produces something like this:
{
links: [],
content: [{
rate: 456,
day: 1366754400000,
links: [{
rel: "self",
href: "http://localhost:8080/api/activities/1"
},
{
rel: "activities.activity.client",
href: "http://localhost:8080/api/activities/1/client"
},
{
rel: "activities.activity.employee",
href: "http://localhost:8080/api/activities/1/employee"
}]
}]
}
My API talks in terms of REST (resources identified by links).
An Activity has an Employee for instance. What I really want to use is : {rate: 456, day: 1366754400000, employee: {firstName:"xxx", lastName:"xxx" ...}}.
However, as you can see in the first output, my Activity only contains a link to the employee, not its data. Is there anything in Angular or in a 3rd-party library to resolve those links and embed the resulting data instead?
Any input on this?
Thanks in advance!
Checkout angular-hateoas. ITs an AngularJS module for using $resource with a HATEOAS-enabled REST API.
You could write a Response Transformation that would inspect your returned object, check for links, and resolve them before returning the response. See the section "Transforming Requests and Responses" in the $http service documentation.
Something like this:
transformResponse: function(rawData) {
var json = JSON.parse( rawData );
forEach( json.content.links, function(link) {
// resolve link...
});
return json;
}
Since the "resolve link" step is itself an $http call, sub-references would also be resolved. HOWEVER, since these are asynchronous, you would likely return a promise instead of the real value; I don't know if the transform function is allowed to do this.
As #charlietfl pointed out, however, please note that this will result in several HTTP calls to return a single entity. Even though I like the concept of HATEOAS, this will likely result in sluggishness if too many calls are made. I'd suggest that your server return the data, or some of it, directly, PLUS the link for details.
Based on your comment about wanting to work with data as against links on the client, I think Restangular would be a good fit.
I've been using angular-hal for one of my projects. It was a Spring HATEOAS backend. And I didn't run into any issues. It handles parametrized resources. I suspect it only supports HAL so since you're using Spring Data Rest you probably have to configure it to generate HAL compliant responses.
I think the confusion may be that you are asking for an Angular solution, when what you really want to do is have Spring Data send a more complete JSON response. I.e, you really just want the server to return the employee data as part of the response JSON, rather than having the client perform extra steps to look it up. I don't know what data store you are using in Spring Data, but the general solution would be to add public getEmployee() method to your Activity class and then annotate the method with #RelatedTo and #Fetch (this would be the setup for Neo4J -- may be different annotations for your flavor of Spring Data). This should cause Spring HATEOAS to include the Employee record within the response for /activity. Hope this helps.
Related
I'm in a situation where I have something similar to shopping cart. I have a set of products with known IDs I then want to create a subset with modified prices and later modify this subset
Superset
[{
"productId":1,
"price":1.99
},
{
"productId":2,
"price":2.99
},
{
"productId":3,
"price":3.99
},
{
"productId":4,
"price":4.99
}]
...
Modified Subset
[{
"productId":1,
"price":1.59
},
{
"productId":3,
"price":2.59
}]
Then I want to modify the subset again to look like
[{
"productId":1,
"price":1.79
},
{
"productId":2,
"price":3.59
}]
All I can think of is client sending a POST request like
{
"productsAdded":[
{
"productId":2,
"price":3.59
}
],
"productsModified":[
{
"productId":1,
"price":1.79
}
],
"productsDeleted":[
{
"productId":3,
"price":2.59
}
]
}
The constraints are that I would like to avoid multiple calls to correct verbs and not send the entire subset. As the actual objects have many more fields and there are thousands of objects in a subset. The update then saves the state triggers a long running fire and forget task.
The problem I see with this is that client potentially has to create a delta of
the state and the server has to reconstruct the state from the message.
This might not be a bad approach, but I am wondering if there are alternative solutions
Updating a collection the RESTful way
The Atom Publishing Protocol is built around the idea of modifying collections of atom entries in the REST architectural style. You might start out by reviewing that design.
All I can think of is client sending a POST request like
That's really close to a JSON Patch representation.
The idea is that if the client and the server share the same (usually standardized) understanding of the media-type, then they can continue to collaborate even as they are developed independently.
So using POST to pass a JSONPatch representation of the change to the resource is a good starting point; if you don't like JSONPatch (perhaps because it is domain agnostic), you could define your own more specific media type and use that.
(Note: though the message type is called "patch", you don't actually need to use the PATCH method in your API. POST on its own, PATCH on its own, or both are all acceptable alternatives.)
Your proposed solution has all of the caveats you mentioned and more. Suggestions:
Modify each object individually through independent requests using
the appropriate HTTP verbs POST, PUT, PATCH, DELETE.
Return the entire collection to be processed on the server using the
appropriate HTTP verb PUT.
Return the partial collection to be processed on the server using the appropriate HTTP verb PATCH.
Additional reference links:
https://restfulapi.net/http-methods/
http://www.restapitutorial.com/lessons/httpmethods.html
https://www.rfc-editor.org/rfc/rfc7231#section-4.3.3
https://www.rfc-editor.org/rfc/rfc5789
http://roy.gbiv.com/untangled/2009/it-is-okay-to-use-post
I'm trying to design an API to calculate a result based on inputs.
Real business:
The API compares two securities portfolios (source and target) and return the orders, the consumer gets the orders, so he/she can then places those orders to adjust portfolio from source to target.
If this is hard to be understood, then here's a similar scenario:
The API compare two text, then return the difference of the 2 texts.
It is a little bit different from the classic CRUD, because the inputs and output are different resources
My first thought is like this:
POST /api/difference
{
'source': { ... },
'target': { ... }
}
But, it will be conflict with the classic payload:
POST /api/difference
{
'lineNumber': ...,
'isAdded': ...
}
Questions:
Should I use a media-type to distinguish the the input payloads? What a 'resource' should be in this case?
What should the API look like if I also want to place the orders (or apply the text diff) in the same time when the API is called?
Iam not sure whether I understand your problem correctly, but in general it
depends on whether the resources are already persisted in the system. In case
both resources are already available in the system I would simply build an URI
like /portfolio/{source_id}/difference/{target_id} which returns the diff
result. If only the source exists I would probably use something like:
POST /portfolio/{source_id}/difference
{target}
If both resources are not available I would probably consider to first persist
such a resource and make then the comparison.
If I understood you correctly, there already exists the resource POST /api/difference and hence you are looking to change MIME type. Instead, why don't you go with the first approach and change the resource name? For example,
POST /api/compare
{
'source': { ... },
'target': { ... }
}
I am designing a restful web service to create and read reports made from an app. When creating a report its possible to add some privacy sensitive information with it like a name, phone number, mail etc. After creating the report its made publicly visible through the same web service.
POST /report
{
"name":"test",
"email":"test#example.com",
"report_contents":....
}
returns 200 OK with:
{
"id":1,
"report_contents":....
}
and a method to get said report:
GET /report/{report_id}
I have another app with which an admin can manage the reports created though the previous web service. In this application I would like to display the privacy sensitive information. It uses the following URL to get a specific report.
GET /report/{report_id}
which returns 200 OK:
{
"id":1,
"name":"test",
"email":"test#example.com",
"report_contents":....
}
Now there is the issue. This is the exact same url. Is it Is it possible/conventional or even a good idea to use the same web service for both calls, but have some kind of CRUD management with it where depending on the role of the user a part of the information is not displayed/blocked? Or would it be better to make a separate web service with restrictions?
Yes, it's OK for different representations of the same resource to be returned at the same URL for different requests. That's how content negotiation works.
If you are concerned about this, I can think of two options:
One option is to include a query parameter to make the choice of views explicit, and access can be controlled for each. E.g.
/report/{report_id}?view=full
/report/{report_id}?view=restricted
Or you could also consider two sub-resources, one called /report/{report_id}/full and one called /report/{report_id}/restricted, and then you can return a 40x code when the user doesn't have correct permission, with a Location header as a hint of where they can look.
If your language of choice supports it, you could return a dynamic object.
here's some pseudo code.
if (loggedInUser != isAdmin(user))
return new { id: 1, contents: "..." }
else
return new { id: 1, name: "test", email: "test#test.com", contents: "..." }
Personally, I would have different areas that do different things. One area that retrieves the model for everyone. In the other it'd be like an admin area.
In the one area, you have
Suppose I have a RESTful API for managing orders which uses HAL to facilitate HATEOAS:
GET /orders/2
{
"_links": {
"self": "/orders/2",
"items": "/orders/2/items"
},
"subtotal": 30.0,
"shipped": false
}
I want to write my client (application) using a set of interfaces so that, assuming that implementations of these interfaces are DI-d/built by DI-d factories, etc., I don't really (want to) have to care that they're backed by my RESTful API. As an example (pseudo C#/Java):
public interface Order {
public void addItem(Item item);
public float getSubtotal();
public boolean getShipped();
}
Order order = ...;
Item item = ...;
order.addItem(item);
...(order.getSubtotal())...;
My question is: can I/does it make sense to generate implementations of the Order/Item interface from the API? By this I mean in a manner similar to that offered with C#/web services which export WSDLs.
I've been thinking about implementing OPTIONS for resources such as /orders and /orders/{id} so that I'd effectively have a HATEOAS API for traversing the schema of the API:
GET /orders/* (I'd need a suitable wildcard of course)
{
"_links": {
"addItem": {
"href": "/orders/{id}/items",
"templated": true,
"type": "method"
}
}
}
Of course I could make this part of the _links object returned with any given resource (/orders/2, for instance) but that precludes static code generation.
I'm wondering if there's a sensible way to encapsulate the fact that if a particular link is provided, the related action should be available/performed, otherwise not.
Note: In case it matters, I'm actually working in JavaScript (specifically with AngularJS). However, I'd still like to write my application using a set of conceptual interfaces/contracts.
My question is: can I/does it make sense to generate implementations
of the Order/Item interface from the API? By this I mean in a manner
similar to that offered with C#/web services which export WSDLs.
It partially makes sense. By a simple CRUD API you can map the resources to the entities. By complex applications it does not work, because you map URIs to resources and METHOD URI pairs to operations. So every time if you need an operation not defined by HTTP, you have to create a new resource or at least a new URI for an already existing resource.
Some examples:
transfer money from one account to another: POST /transfer [acc1, acc2, amount, currency] - the transfer does not necessary exist as an entity in your domain logic (don't try that kind of solution in production code unless you want bankruptcy :D)
sending an email to another user: POST /messages [recipient, message]
you can map resources to value objects too: GET /users/123/address
you can use URIs to map reduce a collection: GET /users?name="John"
you can use PUT /users/123 [details] instead of POST /users [details] to create a new user
you can use POST /player/123/xp/increment 10 instead of PUT /player/123/xp [xp+10] to update the experience points of a player
About the WSDL like solutions you can read alot more here: Third Generation Web APIs - Markus Lanthaler.
My personal opinion that it does not worth the effort to build such a system, because it has more drawbacks than advantages.
How to I represent a complex resource for a REST post?
Hello,
Currently I have an application which when the user hits "save" it iterates over all of the form elements and creates one mass object which manages a:
var = params = [{
attributes1: form1.getValues(),
attributes2: form2.getValues(),
.. ..
}];
I then send this mass object via a RPC POST to my "Entity" model service.
This entity which I wish to persist data for is quite complex. All in all, the data is spread accross about 30 tables. To help explain my actual question, the "entity" is a building (as in a physical property/house/apartment).
What I would like, is to be able to turn my mess into a RESTful API for saving properties.
The problem I have is that, saving details for a single model that spans a single table is fine. How do I structure my data object for transport when the model has
many to many relationships
one to many relationships
one to one relationships
For example:
Here is a WATERED down version of what I might have on a property and the sample data
propertyId: 1,
locationId: 231234,
propertyName: "Brentwood",
kitchenFeatures: [
{ featureId: 1, details: "Induction hob"},
{ featureId:23, details: "900W microwave"}
],
propertyThemes: [ 12,32,54,65 ]
This actually goes on a lot more.. but you can get the general gist. kitchenFeatures would be an example of a many-to-many, where I have a featuresTable which has all of the features like so:
`featureId`, `feature`
1 "Oven Hob"
23 "Microwave"
and propertyThemes would be an example of another many-to-many.
How am I expected to form my "object" to my RESTful service? Is this even possible?
ie. If I want to save this property I would send it to:
http://example.com/api/property/1
The approach I would use here is hypermedia and links:
/property
/property/{id}
/property/{id}/features/{id}
Depending on your domain you might even get away with:
/property/{id}/features/{name}
or
/property/{id}/features/byname/{name}
Thus you can do REST operations and serve JSON or XHTML hypermedia.
Property details:
Request: GET /property/1
Response:
{
..
"name": "Brentwood",
"features": "/property/1/features"
..
}
Brentwood's features:
GET /property/1/features
{
..
"Kitchen": "/property/1/features/1",
"Dog Room": "/property/1/features/dog%20room",
..
}
GET /property/1/features/1
{
..
"Induction hob": "/property/1/features/1/1",
"900W microwave": "/property/1/features/1/23",
"nav-next" : "/property/1/features/dog%20room",
..
}
To add a relation you can do something like this:
POST /property/1/features
{
..
"Name": "Oven Hob"
..
}
If you know what the relation will be you use a PUT:
PUT /property/1/features/23
{
..
"Name": "Oven Hob"
..
}
You can serve multiple media types:
GET http://host/property/1/features/dog%20room.json
GET http://host/property/1/features/dog%20room.xhtml
For the response in xhtml the response can use named links like this:
..
Kitchen
..
There are other aspects of REST that you can use such as response code which I did not include above.
Thus, to model relations you make use of links which can be in itself a resource that can be operated on with GET, PUT, POST and DELETE or even custom verbs such as ASSOCIATE or LINK. But the first four are the ones that people are used to. Remember PUT is idempotent but not POST. See PUT vs POST in REST
Edit: You can group your links into JSON arrays to give structure to your hypermedia.
I think you're really asking, "How do I represent complex data in a form suitable for transmission within a POST?", right? It's less to do with REST and more to do with your choice of media type. I would suggest starting with a pure JSON representation, using arrays and cross-referenced ID fields to map the relationships. You could also do this with XML, of course.
The examples you gave look right on the money. You just need to ensure that both parties (browser and server) agree on the structure and interpretation of the media type you use.
I'm dealing with the exact same thing. I opted to not use id's anywhere, but use urls everywhere an id would normally be expected.
So in your case, the kitchenfeatures could simply be an array with urls to:
/feature/1
/feature/23
And the themes to
/propertyTheme/12
/propertyTheme/32
etc..
In the case of many-to-many relationships, we update all the relations as a whole. Usually we simply dump the existing data, and insert the new relationships.
For one to many relationships we sometimes extend the urls a bit where this makes sense. If you were to have comments functionality on a 'property', this could look like
/property/1/comment/5
But this really depends on the situation for us, for other cases we put it in the top-level namespace.
Is this helpful to you?