JSON API identifiers for nested resources relative to parent - json

When one models resource relationships, the classic example give is for articles and comments. This becomes simple to model because:
articles can be uniquely identified: /articles/1
comments can be uniquely identified: /comments/2
their relationship can be provided as /articles/1/comments which would return only comments for that article
But how does one handle the case where the related resource only exists within the context of the parent?
For example, order and items:
order can be uniquely identified /orders/123
the items in that order only exist as /orders/123/items
and NOT as /items
In JSON-API the relationship object needs a "type" and "id" to specify the linkage:
"relationships": {
"links": {
"self": "http://example.com/orders/123/relationships/items",
"related": "http://example.com/orders/123/items"
},
"data": {
"type": <what goes here>,
"id": <what goes here>
}
}
The type and id for data would need to be relative to order number 123. Assuming, of course, that they don't get assigned a UUID or similar from a database because they are, in fact, a composite key. They exist primarily as a foreign key combination.
How does one handle that?
One option for the relation is to use type as order_item and id as a hash or something delimited string concatenation of the order's id and the item's id. (e.g. 123_abc). 123 I get from the order and abc I get from the item in the order.
Is there another way other than avoiding the need altogether to supply resource linkage?

Every resource must be uniquely identified by a combination of type and id according to JSON API specification:
Identification
Every resource object MUST contain an id member and a type member. The values of the id and type members MUST be strings.
Within a given API, each resource object’s type and id pair MUST identify a single, unique resource. (The set of URIs controlled by a server, or multiple servers acting as one, constitute an API.)
https://jsonapi.org/format/#document-resource-object-identification
Therefor you are not only requiring an ID for resource linkage but also to build any valid response including such a resource.
But there are no rules about how you generate that unique IDs per type. Combining an unique order ID with an unique item ID to get an unique ID per item in an order seems to be a fine approach if your data model doesn't include an ID.

Related

Making a Tree like Structure in Json With Recursion

I'm struggling to get my head around this one, i've had a few attempts and failed miserably.
Basically I have a list of Employees in a database, each with an ID. A Employee can have a parent Employee (Refer as Manager).
I need to output the structure in some sort of tree in json format like shown in this URL
https://raw.githubusercontent.com/bumbeishvili/Assets/master/Projects/D3/Organization%20Chart/redesignedChartLongData.json
Here is a very basic structure example
The JSON can have a structure like this, containing an array of employees:
{
"employees":[
{
"id": 1764,
"name": "Maaz",
... //other fields... this employee has no parent field or
// "parent" : 0 (invalid value)
},
{
"id": 1765,
"parent": 1764,
//other fields... this employee has Maaz as parent
}
]
}
"parent" can simply be an optional field of the employee, containing theid of the parent employee.
If the json had a recursion (i.e. "parent": { /*...*/ }) this would create several issues such as:
Will the parent employee only be stored as second level, or also appear in the list as top level? This adds redundancy or alternatively, search complexity. because if 1764 only appears as child of 1765, you have to potentially recursively trasverse the whole list tree in order to find any employee.
What is the maximum depth of the recursion? With trasversal problems.
Inconsistency or circular relations, leading to loops. If A is parent of B and B is parent of A. Or if there is redundancy but upon deletion the employee does not get wiped anywhere.
More complex operations: if you have a chain of 5 parent-child employees and remove the top one, what do you do with the rest? You would have to define a policy. And adjust the tree everytime.
A flat list on the other hand required just 2 O(n) searches when you are looking for example, for employee 1765. You will then find its parent id and search the list again for an employee with than id, if it exists.
When you add an employee, add without a parent field and edit it later. When you delete an employee, just delete it and eventual broken links will be found at (flat) search time.

How to dynamically avoid sending response containing all properties from relationship data

I am new to spring boot and rest and hence pardon me if this question is very trivial.
I have a situation where the application allows users to register and place order.
On registration of user, the service should be able to send a response with the user information including - User Name, email, contact Number, address etc.
However, while placing orders, I would like the order response object to include within the order details, only the customer (username, email). I do not want to include the address and other information part of the User object.
Currently, what is happening is whenever, I refer to an existing user instance within the Order instance, the Order response has the complete tuple information of the registered user.
In the Order confirmation response, I really do not want the entire User information.
However, if the same Order entity is being referenced for user register, I want the service to include all fields from the Order entity.
I have tried referring to the following links -
Jackson Change JsonIgnore Dynamically
How do I exclude fields with Jackson not using annotations?
However, the solutions mentioned here will always ignore the attribute in response irrespective of the scenario in which the entity is being referenced.
For example - Response from Order service is as below.
{
"id": "ORD-1000",
"priority": null,
"status": "Open",
"customer": {
"id": "1000",
"name": "Avion Solutions",
"email": "support-na#avionsolutions.com",
"contact": null,
"customerType": "gold-sx",
"shipToContactId": null,
"billToContactId": null
},
"urgency": null
}
In the above response tuple, lets say, I just want the order information with basic customer information such as name & email.
And if the customer is registering, then the response should contain all the information as mentioned in the above tuple.
How can i dynamically ignore the attributes in response of the REST service based on the context in which the entity object is being used?
Thanks in advance.
Try to use #JsonView annotation. You can define visibility for given property and on REST Controller you can define level you want to show. For more information and examples, please, read below:
Jackson JSON Views
Jackson – Bidirectional Relationships
Using #JsonView with Spring MVC

MDS business rule

I am new with MDS, and I have a question about one to many relation mapping in MDS
I have a product, contains descriptions in multiple languages. I have created two entities with derived hierarchy structure: product (P_ID, P_name)and Addtional description(P_ID, P_Name_in_German, P_name_in_English).
Additonal description is a drop down from product table from MDS UI, but I only want to populate info that releated with its same P_ID. How can I achieve that? Can I use business rules here and how it should look like?
(2012 Master data service' web interface)
I have also faced a similar problem. I have decided to add multiple fields for languages and apply business rules for them. Let's see how it would work for your entity:
Product entity
{
Code
Name
Name_in_English (text)
Name_in_German (text)
Default_language (domain based, points to Languages entity)
}
Languages entity
{
Code
Name
}
Add values to the Languages entity:
Code = "EN", Mane = "EN"
Code = "DE", name = "DE"
Now we need to add the following business rules to the Product entity:
BR1:
{
IF Condition - Equals: Default_language equals "EN"
THEN Action - Change value: Name = Name_in_English
}
BR2:
{
IF Condition - Equals: Default_language equals "DE"
THEN Action - Change value: Name = Name_in_German
}
After that You will see the product names in your product entity only in proper language which is chosen by drop-down field Default_language.
The second option:
If You want user to see only the Name field and don't want him to see additional fields,
You can hide those fields (Name_in_English and Name_in_German) by setting their width to zero.
Moreover, You can use attribute groups to separate two modes of view:
first mode (for the regular user) - You see only Code and Name
second mode (for the administrator) - You see fields: Name_in_English, Name_in_German, Default_language.
For it to work You need to create two attribute groups:
1) attribute group "EN" (add attributes Name and Code to the group)
2) attribute group "DE" (add attributes Name_in_English, Name_in_German, Default_language to the group)
Hope something of that is helpful!
You're missing something. You said you have a derived hierarchy structure but you don't show a domain based attribute on the Additional description entity with a pointer back to the Product entity. Perhaps you were thinking that the P_ID for Additional Description is the pointer back but it isn't (based on your explanation). It is the entity Code identifier for the Additional Description entity and not the key you need that points back to Product. Perhaps you meant One to One. One to Many implies you have a separate Parent_P_ID back to the Product entity.
Add the Domain Based Parent_P_ID attribute to the Additional Description entity and then reconstruct your derived hierarchy structure. This may not be that helpful because I think you have left something out of the explanation of what you are trying to do.
Hi Cocunuts,
We can not assign derived hierarchy to entities in MDS 2012,but we can achieve this in MDS 2016 , Your Domain based attribute(Drop down) cannot be further filtered in MDS 2012.

JSON Schema required attributes

i've tried to find a similar answer but couldn't, so here it goes:
When defining the schema for a json document, if we define an attribute as required, is this requirement for input data, or is it for input and output?
Example:
let's say we have a property called Id. This Id always exists for the resource, but this Id is generated by the server. If i want to publish my schema for public consumption, and i allow someone to create instances of this resource, should the Id be defined as required or not? Are the required properties only those that the consumers of the API MUST send to create the resource, or are all the properties that the resource always have, including server generated properties?
If you need to validate that the "id" key is there then you should make it required. What you could do is have two different schemas: one to validate the schema from the user (sans "id") and one to validate the api call one which would include the "id" key

Why do associated collections contain null values? (Hibernate, Annotation, Spring)

[Edit: Apparently, this is only an issue for arrays and FoxyBOA's answer might direct to (or even is) the answer.]
My question relates to these software: Hibernate3+Annotation, Spring MVC, MySQL and in this example also Spring Security.
I was wondering, why collections, which are automatically associated by Hibernate contain null values for each row number of the child table (besides the elements which are correct). My Example:
I have a users and an authorities table, the primary key of the users table is username which serves as foreign key. Right now, there are 13 rows in my authorities table. When I retrieve a user from the database (MySQL InnoDB) and Hibernate automatically retrieves the user's authorities corresponding to this mapping:
#OneToMany
#JoinColumn(name = "username")
#IndexColumn(name="id") // "id" was the primary key and is used to sort the elements
public Authority[] getAuthorities() {
return authorities;
}
public void setAuthorities(Authority[] authorities) {
this.authorities = authorities;
}
... I end up with a collection "authorities" containing 14 (0-13) elements of which only four are not-null (four rows in the database table belong to that specific user, so that is correct). As far as I realize, I am using Hibernate defaults for properties like Fetchmode etc. I am getting the user like this:
Criteria criteria = getSession().createCriteria(User.class);
criteria.add(Restrictions.eq("username",username));
User user = (User) criteria.uniqueResult();
The logging information from org.hibernate.loader.loader correctly "mentions" four rows for the resultset. Still, the user created has the four correct elements plus ten null values in the Array. In my specific example, this results in this exception:
java.lang.IllegalArgumentException: Granted authority element 0 is null - GrantedAuthority[] cannot contain any null elements
The answer lies in the #IndexColumn annotation. It is using the value of id as the array index, thus the number of elements in the Array is basically going to be the value of the highest ID in the Authorities table.
see the hibernate documentation on indexed collections
try removing the annotation.
Also just as a thought; have you considered using a Set for the mapping? it isn't strictly necessary, it just a bit more common form of mapping that's all.
I can recommend you check your data. If you have a missed indexes (id column in your case), then instead of missed id you'll get null in your array.
I.e.
table authorities:
username id
bob 1
bob 3
bob 5
As a result you will have an array:
{0=null, 1=bob, 2=null, 3=bob, 4=null, 5=bob}
UPDATE:
I met the situation in two cases:
Missed key values in indexed column id at authorities table (e.g. 0,1,3,4,5 - missing value 2. Hibernate will automatically add to an array value with key 2 and value null).
Indexed values are in order, but select criteria filter part of them (e.g. your HQL similar to that "from user u join u.authorities a where a.id=2". In that case hibernate load a user, but in authorities array you will have only 3 values: 0 - null, 1 - null, 2 - authority with id 2).