What's the correct way to present paged resources with HAL? - hateoas

This sounds like a rookie question, but I'm wondering what's the best way to present paged resources with HAL format? Right now I'm using Spring HATEOAS API to convert Page object into resource PagedResourcesAssembler#toResource(Page<T>, ResourceAssembler<T,R>). This results in the following output:
{
"_links": {
"self": {
"href": "http://example.org/api/user?page=3"
},
…
}
"count": 3,
"total": 498,
"_embedded": {
"users": [
{
"_links": {
"self": {
"href": "http://example.org/api/user/mwop"
}
},
"id": "mwop",
"name": "Matthew Weier O'Phinney"
}
]
}
}
Everything works fine but the only problem is the collection being returned is under _embedded field and has the class name, so the client has to know this class name as well right? Would it be better to just return the collection under content like non-HAL format? If yes how should I achieve it using Spring HATEOAS?

That's not a problem, that's the way _embedded is defined in the HAL specification.
users is not a class, it's a link relation that will allow clients to actually find the collection it was asking for in the first place (e.g. using a JSONPath expression). That's not something coming out of the blue at all but usually is the same link relation, the client used to find that resource in the first place.
Assume an API root exposing this document:
{
"_links": {
"users": {
"href": "…"
},
…
}
}
Seeing that, the client would have to know the semantics of users to find the link it wants to follow. In your case users is basically pointing to a collection resource that supports pagination.
So if the client follows the link named users, it can then find the actual content it's looking for under _embedded.users in the HAL response by combining knowledge about the media type (HAL, _embedded) and the service's application-level semantics (users).

Related

How to query arbitrary fields in Kibana?

We're importing logs that contain the the full request/response for a given endpoint. Using the escLayout c# library. The import is working fine, however the 'structured' part of the log is stored under metadata, like so:
"metadata": {
"event": {
"controller": "main",
"method": "GetData",
"request": {
"userId": 1,
"clientTypeId": 2
},
"response": {
"marketOpen": true,
"price": 18.56
}
}
}
How do I go about querying this metadata as the fields do not appear in the 'Lens' page.
Is it a case of creating an index of some description? There are a lot of different (and occasionally large) data sets so this seems really impactable.
Is querying 'ad-hoc' data like this not a good use of Kibana? Should I look elsewhere, say Grafana before I go too far down the Elastic road?
Note: We're on Elastic 8.2.0

How do you add multiple links of the same type to a resource using Spring HATEOAS?

The HAL spec that I am working with says that you can have multiple links of the same type on a resource like this:
{
"_links": {
"items": [{
"href": "/first_item"
},{
"href": "/second_item"
}]
}
}
However Spring ResourceSupport type only seems to have an add() method that adds a single link. So I can write
order.add(linkTo(methodOn(OrderController.class).order(id)).withRel("item"));
to add one such, but I can't see how to get an array of them with a ref as items, as per the spec.
If you call ResourceSupport::add() twice (or more) with the same withRel value, it creates an array ref with that name containing each of the items.

How to get name/confidence individually from classify_text?

Most of the other methods in the language api, such as analyze_syntax, analyze_sentiment etc, have the ability to return the constituent elements like
sentiment.score
sentiment.magnitude
token.part_of_speech.tag
etc etc etc....
but I have not found a way to return name and confidence in isolation from classify_text. It doesn't look like it's possible but that seems weird. Am missing something? Thanks
The language.documents.classifyText method returns a ClassificationCategory object which contains name and confidence. If you only want one of the fields you can filter by categories/name or categories/confidence. As an example I executed:
POST https://language.googleapis.com/v1/documents:classifyText?fields=categories%2Fname&key={YOUR_API_KEY}
{
"document": {
"content": "this is a test for a StackOverflow question. I get an error because I need more words in the document and I don't know what else to say",
"type": "PLAIN_TEXT"
}
}
Which returns:
{
"categories": [
{
"name": "/Science/Computer Science"
},
{
"name": "/Computers & Electronics/Programming"
},
{
"name": "/Jobs & Education"
}
]
}
Direct link to API explorer for interactive testing of my example (change content, filters, etc.)

How to remove hypermedia elements from representations produced by Spring Data REST?

When using Spring Data for my REST API, the responses returned currently include the _links field:
{
"_embedded": {
"users": [
{
"imageUrl": "some_image_url",
"name": "some name",
"id": "57420b2a0d31bb6cef4ee8e9",
"_links": {
"self": {
"href": "http://localhost:8080/users/57420b2a0d31bb6cef4ee8e9"
},
"user": {
"href": "http://localhost:8080/users/57420b2a0d31bb6cef4ee8e9{?projection}",
"templated": true
}
}
},
...
Is there a way to produce output, such that the _links field is hidden? e.g.:
{
"_embedded": {
"users": [
{
"imageUrl": "some_image_url",
"name": "some name",
"id": "57420b2a0d31bb6cef4ee8e9",
},
...
I find that because I am exposing the id field, _links are not really necessary, and mostly just clutter up my responses.
There isn't. Hypermedia is a fundamental trait of REST APIs and Spring Data REST heavily uses it to allow you to build clients that can use the links present in the responses to navigate to related resources.
Of course you can dumb down your clients to not make use of that information but that will lead to a much tighter coupling (as you can't change the URIs on the server side anymore, your clients expects to talk to a dedicated server whereas with hypermedia you can just point it to a different server etc.).
In contrast to a lot of other self-proclaimed REST frameworks out there, one of the key aspects of the framework's design is to respect the fundamental principles in REST and explicitly leverage them. Or at least, don't create incentives to easily break them. This is clearly expressed in the reference documentation and on the project website. Find out more about key design decisions in this presentation on Spring Data REST, and this one on Domain-Driven Design & REST.

Some doubts about the use of parameters into a request toward a REST web service?

I am pretty new in Spring and in REST web services and I have the following dout following a tutorial that show how to implement a RESTful web service using Spring MVC.
So, into a controller class I have this method:
#Controller
#RequestMapping("/api/categories")
public class CategoryRestController {
#RequestMapping
#ResponseBody
public CategoryList getCategories(#RequestParam("start") int start, #RequestParam("size") int size ) {
List<Category> categoryEntries = categoryService.findCategoryEntries(start, size);
return new CategoryList(categoryEntries);
}
}
This method handle HTTP GET request toward the resoruce /api/categories and return the retrieved list into JSON format (I think that it depends by the content negotiazion: if the caller put the Accept header as JSON the method return the result in JSON format, is it right?)
By the way my doubt is related the HTTP request shown in the tutorial, infact it do:
http://localhost:8080/springchocolatestore/api/categories?start=0&size=2
that is handled by the previous controller method to return a paginated list (that could be hude) in JSON format, infact I retrieve the following output:
{
"categories": [
{
"links": [
{
"rel": "self",
"href": "http://localhost:8080/springchocolatestore/api/categories/1",
"variables": [],
"templated": false,
"variableNames": []
}
],
"name": "Truffles",
"description": "Truffles",
"id": {
"rel": "self",
"href": "http://localhost:8080/springchocolatestore/api/categories/1",
"variables": [],
"templated": false,
"variableNames": []
}
},
{
"links": [
{
"rel": "self",
"href": "http://localhost:8080/springchocolatestore/api/categories/2",
"variables": [],
"templated": false,
"variableNames": []
}
],
"name": "Belgian Chocolates",
"description": "Belgian Chocolates",
"id": {
"rel": "self",
"href": "http://localhost:8080/springchocolatestore/api/categories/2",
"variables": [],
"templated": false,
"variableNames": []
}
}
]
}
Ok, so in the request I specify the pagination parameter by categories?start=0&size=2
My doubt is related to the user of this parameter. From what I have understand (but maybe it could be wrong) the use of the parameter is against the RESTful principles. Is it true or am I mising something?
Or maybe in this specific case are valid because the parameter are not specifing an object (that have to be returned into my JSON output) but are only related to some options?
I mean that maybe I can't use parameter to specify a specific object, something like this:
// RETRIEVE THE PRODUCT WITH ID=1
http://localhost:8080/springchocolatestore/api/producs?product=1
So I think that the previous is not following the RESTfull standard because I am specifing a product object with a parameter and not accessing to it as a resource, so I have to do in this way:
http://localhost:8080/springchocolatestore/api/producs/1
Can you give me some clarification?
Tnx
REST doesn't have much to do with URLs, and using request parameters is not unRESTful.
But I agree that path variables are generally used to identify a specific resource, and parameters are generally used for search or pagination parameters.

Resources