How Do I Remove a Linked Resource from a Collection in HATEOAS? - spring

How do I remove a resource from a object's collection using HATEOAS?
A PUT will set the collection.
A PATCH will allow a partial update/add.
But how do I do partial update/remove?
Do I really need to POST the entire uri-list minus 1 in order to remove a single item?
Take this object as an example:
{
"name": "Bob Test",
"description": "this is the descript",
"_links": {
"self": {
"href": "http://localhost/example/1"
},
"example": {
"href": "http://localhost/example/1"
},
"citations": {
"href": "http://localhost/example/1/citations"
},
}
}
The object has many citations (collection):
{
"_embedded": {
"citations": [
{
"content": "asdfasdf",
"anchor": null,
"_links": {
"self": {
"href": "http://localhost/citations/1"
},
"citation": {
"href": "http://localhost/citations/1"
},
"bioMarker": {
"href": "http://localhost/citations/1/example"
}
}
},
{
"content": "c2",
"anchor": "prf",
"_links": {
"self": {
"href": "http://localhost/citations/2"
},
"citation": {
"href": "http://localhost/citations/2"
},
"bioMarker": {
"href": "http://localhost/citations/2/example"
}
}
}
]
},
"_links": {
"self": {
"href": "http://localhost/example/1/citations"
}
}
}
Now let's say I want to remove http://localhost/citations/2, how do I remove this particular item from the http://localhost/example/1/citations collection?

Get the content type from the response and send it in request header "Accept" . Usually it will be "application/xxxxx+json"

Related

Logicapp Expression to read Dynamic Json path - read child element where parent path may change but hierarchy remaining same

Hope all well.
I am in need of creating logicapp expression for reading child element in json where name of element & hierarchy remains same but parent name can be changing.
for example : JSON-1 :
{
"root": {
"abc1": {
"abc2": [
{
"element": "value1",
"element2": "value"
},
{
"element": "value2",
"element2": "valu2"
}
]
}
}
}
JSON-2 :
{
"root": {
"xyz1": {
"xyz2": [
{
"element": "value1",
"element2": "value"
},
{
"element": "value2",
"element2": "valu2"
}
]
}
}
}
I have tried these but no luck
approach-1: #{body('previous-action')?['']?['']?['element']
approach-2: #{body('previous-action')???['element']
Please let me know if anyone encountered this situation. Many thanks in advance.
I tend to find that converting the JSON to xml (at least in your case) is the simplest solution. Then when you've done that, you can't use XPath to simply make your selection.
Flow
In basic terms ...
I've defined a variable of type object that contains your JSON.
I then convert that JSON object to XML using this expression xml(variables('JSON Object'))
Next, initialize a variable is called Elements of type array (given you have multiple of them). The expression for setting that variable is where the smarts come in. That expression is ... xpath(xml(variables('XML')), '//element/text()') and it's getting the inner text of all element nodes in the XML.
Finally, loop through the results.
If you needed to take it up a level and get the second element then you'd need to change your xpath query to be a lot more generic so you can get the element2 nodes (and 3, 4, 5, etc. if they existed) in each array as well.
Note: I've stuck to your specific question of looking for element.
Result
This definition (which can be loaded directly into your tenant) demonstrates the thinking ...
{
"definition": {
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
"actions": {
"For_Each_Element": {
"actions": {
"Set_Element": {
"inputs": {
"name": "Element",
"value": "#{item()}"
},
"runAfter": {},
"type": "SetVariable"
}
},
"foreach": "#variables('Elements')",
"runAfter": {
"Initialize_Element": [
"Succeeded"
]
},
"type": "Foreach"
},
"Initialize_Element": {
"inputs": {
"variables": [
{
"name": "Element",
"type": "string"
}
]
},
"runAfter": {
"Initialize_Elements": [
"Succeeded"
]
},
"type": "InitializeVariable"
},
"Initialize_Elements": {
"inputs": {
"variables": [
{
"name": "Elements",
"type": "array",
"value": "#xpath(xml(variables('XML')), '//element/text()')"
}
]
},
"runAfter": {
"Initialize_XML": [
"Succeeded"
]
},
"type": "InitializeVariable"
},
"Initialize_JSON_Object": {
"inputs": {
"variables": [
{
"name": "JSON Object",
"type": "object",
"value": {
"root": {
"abc1": {
"abc2": [
{
"element": "value1",
"element2": "value"
},
{
"element": "value2",
"element2": "valu2"
}
]
}
}
}
}
]
},
"runAfter": {},
"type": "InitializeVariable"
},
"Initialize_XML": {
"inputs": {
"variables": [
{
"name": "XML",
"type": "string",
"value": "#{xml(variables('JSON Object'))}"
}
]
},
"runAfter": {
"Initialize_JSON_Object": [
"Succeeded"
]
},
"type": "InitializeVariable"
}
},
"contentVersion": "1.0.0.0",
"outputs": {},
"parameters": {
"ParameterTest1": {
"defaultValue": "\"\"",
"type": "String"
}
},
"triggers": {
"manual": {
"inputs": {
"method": "GET",
"schema": {}
},
"kind": "Http",
"type": "Request"
}
}
},
"parameters": {}
}

How in strapi graphql I can pull records from a given month

Hi I would like to draw from graphql only those records whose date is equal to the month - August
If I want to pull another month, it is enough to replace it only in the query. At the moment, my query takes all the months instead of the ones it gives inside the filter
schema.json
{
"kind": "collectionType",
"collectionName": "product_popularities",
"info": {
"singularName": "product-popularity",
"pluralName": "product-popularities",
"displayName": "Popularity",
"description": ""
},
"options": {
"draftAndPublish": true
},
"pluginOptions": {},
"attributes": {
"podcast": {
"type": "relation",
"relation": "manyToOne",
"target": "api::product.products",
"inversedBy": "products"
},
"value": {
"type": "integer"
},
"date": {
"type": "date"
}
}
}
My query
query {
Popularities(filters: {date: {contains: [2022-08]}}) {
data {
attributes {
date
value
}
}
}
}
Response
{
"data": {
"Popularities": {
"data": [
{
"attributes": {
"date": "2022-08-03",
"value": 50
}
},
{
"attributes": {
"date": "2022-08-04",
"value": 1
}
},
{
"attributes": {
"date": "2022-08-10",
"value": 100
}
},
{
"attributes": {
"date": "2022-07-06",
"value": 20
}
}
]
}
}
}

Spring HATEOAS doesn't generate _embedded and _link properties in the response

After upgrade SpringBoot from 1.5.4 to 2.1.7, the existing Spring HATEOAS code does no longer generate '_embedded' and '_link' in the response, instead it generates 'embedded' and 'link'. I need help to find the root cause of this, and how to fix it. Thank you.
Here is a sample of response payload:
{
"embedded": {
"orders": [
{
"id": 3172,
"orderNumber": 148700990741,
"status": "FINISHED",
"userId": "ffffffff5e7c13a4da4a9d0132e95f73",
"createdAt": "2020-03-26T02:31:32.263Z",
"updatedAt": "2020-03-26T02:31:38.853Z",
"createdBy": "ffffffff57acb9e5e4b0e06a0a570080",
"addresses": [],
"updatedBy": "ffffffff57acb9e5e4b0e06a0a570080",
"successUrl": "http://example.com/success",
"cancelUrl": "http://example.com/cancel",
"link": {
"self": {
"href": "http://local.dev-openclass.com:8088/v1/orders/3172"
},
"order": {
"href": "http://local.dev-openclass.com:8088/v1/orders/3172"
},
"transactions": {
"href": "http://local.dev-openclass.com:8088/v1/orders/3172/transactions"
}
}
}
]
},
"link": {
"self": {
"href": "http://local.dev-openclass.com:8088/v1/orders/search/?userId=ffffffff5e7c13a4da4a9d0132e95f73"
}
}
}

Missing links within Spring Data Rest Response using RestTemplate

When I make a call to a Spring Data Rest Endpoint I am expecting to see the self links and related links within each object. None of the links appear.
RestTemplate Setup:
#HystrixCommand(fallbackMethod = "getFallbackScenicList")
#RequestMapping(value = "/s", method = RequestMethod.GET, produces= MediaType.APPLICATION_JSON_VALUE)
public PagedResources<Scenic> scenic() {
String url = "http://vr-dms-an-scenic/scenic";
ParameterizedTypeReference<PagedResources<Scenic>> ptr = new ParameterizedTypeReference<PagedResources<Scenic>>() {};
ResponseEntity<PagedResources<Scenic>> responseEntity =
this.restTemplate.exchange(url,HttpMethod.GET, null, ptr, 0,100
);
PagedResources<Scenic> resources = responseEntity.getBody();
return resources;
}
Expected Response:
{
"_embedded": {
"scenic": [
{
"id": 1,
"name": "Test1 scenic",
"description": "This is a description1 for displaying information while in development",
"shortDescription": "Short Description Scenic1",
"_links": {
"self": {
"href": "http://localhost:49218/scenic/1"
},
"scenic": {
"href": "http://localhost:49218/scenic/1"
}
}
}
]
},
"_links": {
"self": {
"href": "http://localhost:49218/scenic"
},
"profile": {
"href": "http://localhost:49218/profile/scenic"
},
"search": {
"href": "http://localhost:49218/scenic/search"
}
},
"page": {
"size": 20,
"totalElements": 1,
"totalPages": 1,
"number": 0
}
}
Actual Response:
{
"_embedded": {
"scenic": [
{
"id": 1,
"name": "Test1 scenic",
"description": "This is a description1 for displaying information while in development",
"shortDescription": "Short Description Scenic1"
}
]
},
"_links": {
"self": {
"href": "http://localhost:49218/scenic"
},
"profile": {
"href": "http://localhost:49218/profile/scenic"
},
"search": {
"href": "http://localhost:49218/scenic/search"
}
},
"page": {
"size": 20,
"totalElements": 1,
"totalPages": 1,
"number": 0
}
}
I assume that Scenic doesn't contain links. So instead of
PagedResources<Scenic>
you actually want
PagedResources<Resource<Scenic>>

Adding self link to projection in spring data rest

I have a simple application containing Products, Prices and PricedProducts.
When I request the list of PricedProducts, I want the Price and the Product to be inlined. I marked my Price repository with #RestResource(exported = false), so for this one it works ok. Products, however, need to be self standing entities (I need to be able to build several PricedProducts using the same Product for example).
I created a projection for PricedProduct, added it as excerptProjection, and a GET to /pricedProducts returns:
{
"_embedded": {
"pricedProducts": [
{
"price": {
"value": "100.50",
"currency": "EUR"
},
"product": {
"name": "Poatato",
"description": null,
"pictureUrl": null
},
"_links": {
"self": {
"href": "http://localhost:4200/api/v1.0/pricedProducts/1"
},
"pricedProduct": {
"href": "http://localhost:4200/api/v1.0/pricedProducts/1{?projection}",
"templated": true
},
"product": {
"href": "http://localhost:4200/api/v1.0/pricedProducts/1/product"
}
}
}
]
},
"_links": {
"self": {
"href": "http://localhost:4200/api/v1.0/pricedProducts"
},
"profile": {
"href": "http://localhost:4200/api/v1.0/profile/pricedProducts"
}
}
}
This inlines my product, however it does not supply a self link for it. So in my client app, when somebody edits the name of the product, for example, I don't know which product I must update, unless I do an extra request.
What I did next was to create a projection for Product, which I use inside the projection for PricedProduct. A GET to /pricedProducts now yields:
{
"_embedded": {
"pricedProducts": [
{
"price": {
"value": "100.50",
"currency": "EUR"
},
"product": {
"pictureUrl": null,
"description": null,
"name": "Potato",
"_links": {
"self": {
"href": "http://localhost:4200/api/v1.0/products/1{?projection}",
"templated": true
}
}
},
"_links": {
"self": {
"href": "http://localhost:4200/api/v1.0/pricedProducts/1"
},
"pricedProduct": {
"href": "http://localhost:4200/api/v1.0/pricedProducts/1{?projection}",
"templated": true
},
"product": {
"href": "http://localhost:4200/api/v1.0/pricedProducts/1/product"
}
}
}
]
},
"_links": {
"self": {
"href": "http://localhost:4200/api/v1.0/pricedProducts"
},
"profile": {
"href": "http://localhost:4200/api/v1.0/profile/pricedProducts"
}
}
}
Now my Product has a self link, but it points to its projection (http://localhost:4200/api/v1.0/products/1{?projection}). What I want is:
{
"_embedded": {
"pricedProducts": [
{
"price": {
"value": "100.50",
"currency": "RON"
},
"product": {
"pictureUrl": null,
"description": null,
"name": "Potato",
"_links": {
"self": {
"href": "http://localhost:4200/api/v1.0/products/1
}
}
},
"_links": {
"self": {
"href": "http://localhost:4200/api/v1.0/pricedProducts/1"
},
"pricedProduct": {
"href": "http://localhost:4200/api/v1.0/pricedProducts/1{?projection}",
"templated": true
},
"product": {
"href": "http://localhost:4200/api/v1.0/pricedProducts/1/product"
}
}
}
]
},
"_links": {
"self": {
"href": "http://localhost:4200/api/v1.0/pricedProducts"
},
"profile": {
"href": "http://localhost:4200/api/v1.0/profile/pricedProducts"
}
}
}
Thanks!
I think the simplest, and more correct, thing to do is using a child projection and parse the self link on the client side.
It's a little bit old question, but I faced the same problem today and I found a solution:
All you have to do is to REMOVE the #Projection annotation from the embedded projection (ProductProjection) which is used inside the top level projection (PricedProductProjection).
Of course, in this case you cannot use that projection in GET queries, but I assume you don't even need it. (It was created especially for this purpose)

Resources