Parametarized links in HAL json - json

Assuming I have an endpoint GET /api/foos/{id} which has optional parameters: includes, query, type should I create a link for each of the 'usecases' or can I include it as a single link?
Should it look more like this:
"_links":{
"self": { "href": "/api/foos/1" },
"includes": { "href": "/api/foos/1{?includes}", "templated": true },
"query": { "href": "/api/foos/1{?query}", "templated": true },
"type": { "href": "/api/foos/1{?type}", "templated": true },
}
Or maybe like this:
"_links":{
"self": { "href": "/api/foos/1" },
"query": { "href": "/api/foos/1{?includes}{?query}{?type}", "templated": true },
}
What if I also have paging related links, like next, prev etc. Should I include these templates for them, too? For example:
"next": { "href": "/api/foos?page=2{?includes}", "templated": true }

According to RFC6570, Section 3.2.1 (which is the foundation for URL templating) you can add multiple parameters and parameter without a value will be ignored:
A variable that is undefined (Section 2.3) has no value and is ignored by the expansion process.
That means for your example that you can use following HAL response:
"_links":{
"self": { "href": "/api/foos/1" },
"query": { "href": "/api/foos/1{?includes,query,type}", "templated": true },
}
And it should work for your paging example as well.

Related

How to de (serialize) _links so that value of "rel" value appear as element and _link as nested json

Spring hatios latest is keeping links as array rather than nested json and keeping relation name as "rel". We want "rel" value as child jsons root name. Please see the current and expected behaviour.
CURRENT BEHAVIOUR:
[
{
"id": "id-1",
"name": "abc",
"description": "abc",
"enrollments": [
{
"links": [
{
"rel": "fees",
"id": "feesId-1",
"href": "xyz"
},
{
"rel": "rates",
"id": "ratesId-1",
"href": "abc"
}
]
}
]
}
]
EXPECTED:
[
{
"id": "id-1",
"name": "abc",
"description": "abc",
"enrollments": [
{
"id": "1",
"end_timestamp": "2025-12-31T16:06:05Z",
"_links": {
"rates": {
"id": "ratesId-1",
"href": "abc"
},
"fees": {
"id": "feesId-1",
"href": "xyz"
}
}
}
]
}
]
Returning CollectionModel instead of List resoloved the issue in my case.

change default structure of HATEOAS links

How to change the default structure of Hateoas links:
"first": {
"href": "http://localhost:8081/api/offer/?page=0&size=20"
},
"self": {
"href": "http://localhost:8081/api/offer/"
},
"next": {
"href": "http://localhost:8081/api/offer/?page=1&size=20"
},
"last": {
"href": "http://localhost:8081/api/offer/?page=2&size=20"
}
to be like this:
{
"href": "http://localhost:8081/api/offer/?page=0&size=20",
"rel" : "next",
"method": "GET"
},

query when object name is a URL

I've written a JQ search that outputs the following, but I cannot work out how to get into the detail and extract specific information from this.
{
"https://www.example.org/rest/relation/node/recording/revision_uid": [
{
"_links": {
"self": {
"href": "https://www.example.org/user/37?_format=hal_json"
},
"type": {
"href": "https://www.example.org/rest/type/user/user"
}
},
"uuid": [
{
"value": "d40684cf-2321-42d2-9194"
}
]
}
],
"https://www.example.org/rest/relation/node/recording/uid": [
{
"_links": {
"self": {
"href": "https://www.example.org/user/37?_format=hal_json"
},
"type": {
"href": "https://www.example.org/rest/type/user/user"
}
},
"uuid": [
{
"value": "d40684cf-2321-42d2-9194"
}
],
"lang": "en"
}
],
"https://www.example.org/rest/relation/node/recording/field_category": [
{
"_links": {
"self": {
"href": "https://www.example.org/simplecategory?_format=hal_json"
},
"type": {
"href": "https://www.example.org/rest/type/taxonomy_term/tags"
}
},
"uuid": [
{
"value": "3fef93d5-926a-41aa-95cb"
}
]
}
],
"https://www.example.org/rest/relation/node/recording/field_part1_speaker": [
{
"_links": {
"self": {
"href": "https://www.example.org/by/speakername?_format=hal_json"
},
"type": {
"href": "https://www.example.org/rest/type/taxonomy_term/author"
}
},
"uuid": [
{
"value": "fb6c806f-fa6a-4aa0-89ef"
}
]
}
]
}
How do I write a query that returns 'https://www.example.org/simplecategory?_format=hal_json'?
And I'd then want a similar query that returns 'https://www.example.org/by/speakername?_format=hal_json'
So jq '._embedded' gets me the data above.
I've then tried various combinations to get to the value of https://www.example.org/rest/relation/node/recording/field_category.
- jq '._embedded.https://www.example.org/rest/relation/node/recording/field_category - but of course the URL has special characters in it.
jq .["https://www.example.org/rest/relation/node/recording/field_category"]
jq ."https://www.example.org/rest/relation/node/recording/field_category$"
I've also messed around with some of JQs built in functions, like flatten and to_entries, from_entries. I've also tried regular expressions but my efforts return Cannot iterate over null (null).
How do I write a query that returns 'https://www.example.org/simplecategory?_format=hal_json'?
If you want to specify the top-level key explicitly, the follow-on query would be:
.["https://www.example.org/rest/relation/node/recording/revision_uid"][]
| ._links.self.href
That is, the entire query would be:
._embedded
| .["https://www.example.org/rest/relation/node/recording/revision_uid"][]
| ._links.self.href
And I'd then want a similar query
An alternative to specifying the top-level key explicitly might be to select the href of interest from the array of all of them:
._embedded
| [.[][]._links.self.href]
This would yield:
[
"https://www.example.org/user/37?_format=hal_json",
"https://www.example.org/user/37?_format=hal_json",
"https://www.example.org/simplecategory?_format=hal_json",
"https://www.example.org/by/speakername?_format=hal_json"
]

Getting readable results from Wikidata

Ok so I'm trying to get information from Wikidata about movies, take this movie for example: https://www.wikidata.org/wiki/Q24871
On the page the data is clearly displayed in a readable format, however when you trying to extract it via the API you get this: https://www.wikidata.org/w/api.php?action=wbgetentities&ids=Q24871
Here is a section from it:
"P272": [
{
"id": "q24871$4721C959-0FCF-49D4-9265-E4FAC217CB6E",
"mainsnak": {
"snaktype": "value",
"property": "P272",
"datatype": "wikibase-item",
"datavalue": {
"value": {
"entity-type": "item",
"numeric-id": 775450
},
"type": "wikibase-entityid"
}
},
"type": "statement",
"rank": "normal"
},
{
"id": "q24871$31777445-1068-4C38-9B4B-96362577C442",
"mainsnak": {
"snaktype": "value",
"property": "P272",
"datatype": "wikibase-item",
"datavalue": {
"value": {
"entity-type": "item",
"numeric-id": 3041294
},
"type": "wikibase-entityid"
}
},
"type": "statement",
"rank": "normal"
},
{
"id": "q24871$08009F7A-8E54-48C3-92D9-75DEF4CF3E8D",
"mainsnak": {
"snaktype": "value",
"property": "P272",
"datatype": "wikibase-item",
"datavalue": {
"value": {
"entity-type": "item",
"numeric-id": 646968
},
"type": "wikibase-entityid"
}
},
"type": "statement",
"rank": "normal"
},
{
"id": "q24871$CA53B5EB-1041-4701-A36E-7C348FAC984E",
"mainsnak": {
"snaktype": "value",
"property": "P272",
"datatype": "wikibase-item",
"datavalue": {
"value": {
"entity-type": "item",
"numeric-id": 434841
},
"type": "wikibase-entityid"
}
},
"type": "statement",
"rank": "normal",
"references": [
{
"hash": "50f57a3dbac4708ce4ae4a827c0afac7fcdb4a5c",
"snaks": {
"P143": [
{
"snaktype": "value",
"property": "P143",
"datatype": "wikibase-item",
"datavalue": {
"value": {
"entity-type": "item",
"numeric-id": 11920
},
"type": "wikibase-entityid"
}
}
]
},
"snaks-order": [
"P143"
]
}
]
}
],
The problem is I'm not sure how to convert sections like that into readable text. I get the API is calling a link between a class and its properties using unique IDs but I'm still stuck.
Is this actually possible at present or am I barking up the wrong tree?
What you should be looking for are the numeric-ids in each statements and add a leading Q to recover your wikidata ids, which should result to ['Q775450', 'Q3041294', 'Q646968', 'Q434841', 'Q11920']
[update: you can now directly access the Q id at mainsnak.datavalue.value.id, instead of having to build it from the numeric-id]
This can be done using wikibase-sdk (a JS lib I developed) wbk.simplify.claims function
Once you got those ids, you just need to request entities labels using the wbgetentities API:
https://www.wikidata.org/w/api.php?action=wbgetentities&ids=Q775450|Q3041294|Q646968|Q434841|Q11920&format=json&props=labels
you can even get results for only some languages, using the languages parameter: https://www.wikidata.org/w/api.php?action=wbgetentities&ids=Q775450|Q3041294|Q646968|Q434841|Q11920&format=json&props=labels&languages=en|de|fr
I see an accepted answer, but initially interpreted the question differently. Basically asking to have the same output in JSON one sees on the Wikidata item page.
SPARQL query with JSON output for above case:
https://query.wikidata.org/sparql?query=SELECT%20%3FwdLabel%20%3Fps_Label%20%3FwdpqLabel%20%3Fpq_Label%20%7B%0A%20%20VALUES%20(%3Fcompany)%20%7B(wd%3AQ24871)%7D%0A%0A%20%20%3Fcompany%20%3Fp%20%3Fstatement%20.%0A%20%20%3Fstatement%20%3Fps%20%3Fps_%20.%0A%0A%20%20%3Fwd%20wikibase%3Aclaim%20%3Fp.%0A%20%20%3Fwd%20wikibase%3AstatementProperty%20%3Fps.%0A%0A%20%20OPTIONAL%20%7B%0A%20%20%3Fstatement%20%3Fpq%20%3Fpq_%20.%0A%20%20%3Fwdpq%20wikibase%3Aqualifier%20%3Fpq%20.%0A%20%20%7D%0A%0A%20%20SERVICE%20wikibase%3Alabel%20%7B%20bd%3AserviceParam%20wikibase%3Alanguage%20%22en%22%20%7D%0A%7D&format=json
I use the Wikidata Query Front End to get my query straight and to check the results. Then use the </> Code button... explaining why you're seeing so much unnecessary whitespace above.
See also:
wikidata get all properties with labels and values of an item
SPARQL query service - Interfacing
Ok so I haven't found a solution to using the This is the "wbgetentities" system I have found that you can use the "parse" command to get the html structure.
https://www.wikidata.org/w/api.php?action=parse&page=Q24871
While it still going to need some processing its much easier than the previous solution.

How to expose REST API HAL format pagination

How should I expose pagination for a REST API by using HAL format, should I just wrap everything in another HAL formatted object with pagination metadata or ?
Is there a suggested pagination format under REST API HAL format ?
UPDATE
Example without the pagination
[
{
"Id": "SomeId",
"Attribute": 5,
"_links": {
"User": { "href": "http://mywebapi/etc", "templated": true }
},
"_embedded": { "User": { "Id": "SomeId","_links": {},"_embedded": {}} }
},
{
"Id": "SomeId",
"Attribute": 5,
"_links": {
"User": { "href": "http://mywebapi/etc", "templated": true }
},
"_embedded": { "User": { "Id": "SomeId","_links": {},"_embedded": {}} }
}
]
Example with the pagination
{
"_embedded": {
"items":
[
{
"Id": "SomeId",
"Attribute": 5,
"_links": {
"User": { "href": "http://mywebapi/etc", "templated": true }
},
"_embedded": { "User": { "Id": "SomeId","_links": {},"_embedded": {}} }
},
{
"Id": "SomeId",
"Attribute": 5,
"_links": {
"User": { "href": "http://mywebapi/etc", "templated": true }
},
"_embedded": { "User": { "Id": "SomeId","_links": {},"_embedded": {}} }
}
]},
"_links": {
"next": "next link",
"previous": "next link"
},
"_totalCount": "100"
}
It this a good practice or not ?
By the way you have an example in proper HAL RFC
https://datatracker.ietf.org/doc/html/draft-kelly-json-hal-06#section-6
"_links": {
"self": { "href": "/orders" },
"next": { "href": "/orders?page=2" },
"find": { "href": "/orders{?id}", "templated": true }
}
What i am not sure is about "_totalCount" ... i am also figuring out what would be the best way to incude a totalCount attribute in HAL format
Use links with rel="next" and rel="previous"
_totalcount can be problematic. Is it inherent property of the resource you return? Most likely not.
If you do have it, then you will be forced to provide this value every time for every page of the resource. If the total collection is very large, it will become necessary to store the count somewhere to satisfy the API. In many cases, the count may be harder to get. For example, if you implement based on other services that provide continuation token, getting _totalcount populated will become hard. If you have SQL table, it might be fairly easy to get but it comes at a cost too.
Is it really valuable for the client or UI? I would avoid if possible.