Selective deep rendering of hasMany relationships in grails - json

For the following domain model:
class Route {
String name
static hasMany = [checkPoints:CheckPoint]
static belongsTo = [someBigObject:SomeBigObject]
static mapping = {
checkPoints lazy: false
}
}
I need to return a specific Route as a JSON from a web service. And I want this JSON to contain all the checkPoints but no other compositions (i.e.:someBigObject).
If I do
def route = Route.findById(id)
render route as JSON
all I got is the id's of the checkPoints, no other field is fetched:
{
"class": "com.example.Route",
"id": 1,
"checkPoints": [
{
"class": "CheckPoint",
"id": 1
},
{
"class": "CheckPoint",
"id": 2
},
{
"class": "CheckPoint",
"id": 4
},
{
"class": "CheckPoint",
"id": 3
}
],
"someBigObject": {
"class": "SomeBigObject",
"id": 2
}
}
but if I do
JSON.use('deep') {
render route as JSON
}
I get everything. I mean, almost all the database is getting fetched through various relationships.
Is there way to do this without creating the jsonMaps manually?

You can register your own JSON marshaller for chosen classes and return properties which you want to render. Map can be done automatically by iteration over class fields. Marshaller ca be registered for example in bootstrap or in domain class during creation.
JSON.registerObjectMarshaller(Route) {
return [name:it.name, checkPoints:it.checkPoints]
}
There is nice article about it under: http://manbuildswebsite.com/2010/02/15/rendering-json-in-grails-part-3-customise-your-json-with-object-marshallers/
Hope it helps

Related

Strapi repeatable Component Not Sending Image Obj with Populate=*

This is a repeatable component of strapi:
Api call:
{
"id": 1,
"attributes": {
../other fields
"imgs": [
{
"id": 37,
"title": "KeyNote Lecture",
"subtitle": "Felicitation in Chennai, Molaris 2022"
},
../Same Objects
],
}
}
See API call getting the only title, subtile, id only. but the image not getting.
Please, anyone, help.
this is because populate=* gives only first level of relations, and image inside component is a relation of second level:
Option one (easiest) use yarn add strapi-plugin-populate-deep
/api/course-director?populate=deep
Option two use qs:
const str = qs.stringify(
{
populate: { imgs: { populate: ["image"] } }
},
{ encodeValuesOnly: true }
);
populate[imgs][populate][0]=image

Angular how to handle a nested http response

My angular service returns the following type of response:
{
"name": "abc",
"id": 1,
"list": [
{
"name": "listName1",
"id": 1
},
{
"name": "listName2",
"id": 2
}
]
}
This is what the call in the service looks like:
fetchX(): Observable<X> {
return this.http.get<X>(some_url)
}
Now, in my component I can access the 'name' and 'id' attribute of the returned object, but for the 'list', which is a list itself, I only get 'undefined'. I'm displaying the list elements in my application (by their name), and they don't actually show up there either (the HTML part for this is definitely correct, this isn't the issue).
myX: CustomX
myList: CustomList[]
ngOnInit() {
this.service.fetchX().subscribe((response) => {
this.myX = response,
this.myList = response.list,
console.log(response.name), //returns 'abc'
console.log(response.id), //returns '1'
console.log(response.list) //returns 'undefined'})}
The entities look like this:
export class CustomX {
name: string
id: number
list: CustomList[]
}
class CustomList {
name: string
id: number
}
What am I missing? I think I may be handling the response in the service incorrectly.

How to use Rest Template to step into a JSON object?

I have learned how to use a rest template to access a JSON array like this:
[
{
"ID": "0ae6496f-bb0b-4ebd-a094-ca766e82f3e7",
"Confirmed": 0,
}
{
"ID": "e010ced5-c7cb-4090-a7ed-206f4c482a5b",
"Confirmed": 0,
}
]
I accessed the Confirmed for example with
public Model[] getModel() {
ResponseEntity<Model[]> response = restTemplate.getForEntity(apiUrl, Model[].class);
return response.getBody();
}
but now I have to access data in another Json from another API. The data looks like this
{
"prefixes": [
{
"region": "ap-northeast-2",
"service": "AMAZON",
},
{
"region": "eu-west-3",
"service": "AMAZON",
}
]
}
How can I access region or service inside, and what would be the proper name for this?
The first is a JSON array, the second a JSON object?
The first API is simply
https://example.com
Whereas the second is
https://example.com/data.json.
You have to create the POJO for return type:
List<RegionServiceObject> items;
Where RegionServiceObject looks:
public class RegionServiceObject {
private String region;
private String service;
// constructors, getters/setters, toString()....
}
The way of deseariliseing to object is similar to which you already wrote:
RegionServiceObject[] items = restTemplate.getForObject(url, RegionServiceObject[].class);
and access for specific item will be as usual for specific item:
for (RegionServiceObject item : items) {
item.getRegion();
item.getService();
// use them here
}

Access Array inside an object (json)

I have this json file and I want to access the array that is inside this object:
best-sellers": [
{
"title": "Chuteira Nike HyperVenomX Proximo II Society",
"price": 499.90,
"installments": {
"number": 10,
"value": 49.90
},
"high-top": true,
"category": "society",
"image": ""
},
{
"title": "Chuteira Nike HyperVenom Phantom III Cano Alto Campo",
"price": 899.90,
"installments": {
"number": 10,
"value": 89.90
},
"high-top": true,
"category": "campo",
"image": ""
}
}
]
This is the code on my component:
ngOnInit(): void {
this.service
.lista()
.subscribe(chuteiras =>{
this.chuteiras = chuteiras;
})
}
and my template looks like this:
<div *ngFor="let chuteira of chuteiras.best-sellers">
But angular is not reconigzing it the `best-sellers", here's the error that I'm getting:
Cannot read property 'best' of undefined
Just use bracket notation,
<div *ngFor="let chuteira of chuteiras["best-sellers"]">
well,that's one way of doing it but angular 6 came with a simple solution. when i was faced with this problem i myself resolved to this solution but it didn't work for me so after searching and making my own touches i ended up with this solution.
1.create the function to receive the JSON data in my case i used a web API
getTrending() {
return this.http.get(https://api.themoviedb.org/3/trending/all/day?api_key=${this.api_key});
}
2.call the function in my case i used a service, so after import it to my component i simply added this
showPopular(): void {
this.api.getTrending().subscribe((data: Array<object>) => {
this.list = data['results'];
console.log(this.list);
});
}
as you can see the data variable only accessed the information i required.

Using *ngFor with a JSON object in Angular 2

I'm trying to implement a decoupled wordpress solution and I'm having a bit of confusion displaying the JSON object properties in my template. I'm able to return JSON objects for the WP API but not sure how to handle them. The only way I can get a property to display it's value in a template is if I add a [0] to the interpolated property, which won't work in an ngFor loop. I've read the solution by #Thierry here access key and value of object using *ngFor
but this doesn't seem to be how Google handles the Tour of Heroes app http://plnkr.co/edit/WkY2YE54ShYZfzJLSkMX?p=preview
Google uses this data set:
{
"data": [
{ "id": "1", "name": "Windstorm" },
{ "id": "2", "name": "Bombasto" },
{ "id": "3", "name": "Magneta" },
{ "id": "4", "name": "Tornado" }
]
}
which looks like a JSON object to me, so how is the app able to handle something like this:
<ul>
<li *ngFor="let hero of heroes">
{{hero.name}}
</li>
</ul>
I'm just unclear if there's been a change in RC5 that allows iteration over an object, or do I still need to transform this somehow. I'm very new to Angular and could use a little guidance on this matter. Thanks!!
An update based on the comments, if I want to transform an api request like http://localhost:8888/wp-json/wp/v2/posts, what's the best method for that? My return code would look something like:
[
{
"id": 4,
"date": "2016-08-09T00:09:55",
"date_gmt": "2016-08-09T00:09:55",
"guid": {
"rendered": “http://localhost:8888/?p=4"
},
"modified": "2016-08-09T00:11:05",
"modified_gmt": "2016-08-09T00:11:05",
"slug": “wp-api-test”,
"type": "post",
"link": "http://localhost:8888/2016/08/wp-api-test”,
"title": {
"rendered": "testing the wp api"
},
"content": {
"rendered": "<p>loreum ipsum</p>\n"
},
"excerpt": {
"rendered": "<p>loreum ipsum</p>\n"
},
"author": 1,
"featured_media": 0,
"comment_status": "open",
"ping_status": "open",
"sticky": false,
"format": "standard",
"categories": [
1
],
}
]
Without writing all the code for you, there is no short answer to what you are asking, but here are some tips:
You have to take the JSON response you are getting back and create either an interface or class in TypeScript so when you perform the POST, Angular 2 can take the JSON and convert it to an object using your classes.
JSON to TS generator: http://json2ts.com/
Ninja Tips 2 - Make your JSON typed with TypeScript - http://blog.ninja-squad.com/2016/03/15/ninja-tips-2-type-your-json-with-typescript/
TypeScript Json Mapper - http://cloudmark.github.io/Json-Mapping/
How are you defining your services?
Here's an example:
export interface IPost {
id: number;
date: Date;
date_gmt: Date;
... // rest of your defintion
}
#Injectable()
export class BlogPostService {
private http: Http;
constructor(http: Http) {
this.http = http;
}
private apiUrl: string = 'api/blog/posts.json';
getPosts(): Observable<IPost[]> {
return (this.http.get(this.apiUrl)
.map((response: Response) => <IPost[]>response.json())
.do(data => console.log('All: ' + JSON.stringify(data)))
.catch(this.handleError)) as any;
}
private handleError(error: Response) {
console.error(error);
return Observable.throw(error.json().error || "Server error");
}
}
This line should transform your json object to array[] of IPosts
.map((response: Response) => <IPost[]>response.json())
Hope that helps.
Thanks so much for the answers. They helped lead me to the solution. I was able to solve this rather simply by creating a posts array and making it equal to the Observable return. The component looks like this:
posts: {};
constructor (private _wpService: WpApiService) {}
ngOnInit() { this.getPosts() }
getPosts() {
this._wpService.getPosts()
.subscribe(
data => {
this.posts = data;
});
}
The template looks like:
<li *ngFor="let post of posts">
<h3>{{post.title.rendered}}</h3>
</li>
Just replace {{hero.name}} by {{hero.data.name}}
The best way to handle the JSON object by creating an interface class to access the data easily