DTO (Data Transfer Object) implementation - dto

I have two questions about DTO implementation.
I have two apis return slightly different nested objects, which responses like:
{
"shop": {
"id": 1,
"name": "name",
"logo_url": "logo_url"
}
...
}
and
{
"shop": {
"id": 1,
"name": "name",
"logo_url": "logo_url",
"address": "...",
"phone": "..."
}
...
}
should I define shop as a inner class of each parent dto, or just define two different dto classes.
Some apis accept same dto object for both create and update, should I define just one class like EditShopDTO for both create and update, or define another two classes like CreateShopDTO and UpdateShopDTO.
Thank you for your help.

Related

How do I avoid redundant data lookups when resolving multiple nested graphql queries?

Is there a known solution or feature in GraphQL or Apollo for batching expensive, redundant, data lookups across multiple query and field resolvers?
Say we have Person & Pet types, and queries to fetch them:
type Query {
pets: [Pet]
people: [Person]
}
type Pet {
name: String
owner: Person
}
type Person {
name: String
}
And we have a web client that needs to get all of them to show on a page:
query PetsAndPeople {
pets {
name
owner {
name
}
}
people {
name
}
}
To resolve this query, our backend needs to make REST API calls to an external service, which happens to apply rate-limiting, or has a $ cost per query. The endpoints look like this:
GET /pets
[
{
"name": "Mittens",
"ownerId": 1
},
{
"name": "Rover",
"ownerId": 1
}
{
"name": "Spot",
"ownerId": 2
}
]
GET /person/1
{
"name": "John Doe"
}
GET /persons
[
{
"name": "John Doe"
},
{
"name": "Jane Smith"
}
]
The resolvers look like this:
{
Query: {
pets: () => fetchJSON(`${API}/pets`)
}
people: () => fetchJSON(`${API}/persons`)
},
Pet: {
name: (pet) => pet.name
person: (pet) => fetchJSON(`${API}/person/${pet.ownerId}`)
}
Person: {
name: (person) => person.name
}
}
So lets say the graphql response for the web client looks like this:
{
"pets": [
{
"name": "Mittens",
"owner": {
"name": "John Doe"
}
},
{
"name": "Rover",
"owner": {
"name": "John Doe"
}
},
{
"name": "Spot",
"owner": {
"name": "Jane Smith"
}
}
],
"people": [
{
"name": "John Doe"
},
{
"name": "Jane Smith"
}
]
}
To produce this, we had to make 4-5 REST calls on the graphql side to the external API:
GET /people to resolve all of the people's names
GET /pets to resolve all of the pets' names
GET /person/1 to resolve Mittens's owner's name
GET /person/1 to resolve Rover's owner's name (maybe apollo caches this, but I'm not sure)
GET /person/2 to resolve Spot's owner's name
Since there are restrictions on the external API (such as rate limits or $/query), I would ideally want only want to make 2 queries (GET /people and GET /pets), and then resolve the pet's owner's names based on the results of the GET /people instead of making the redundant GET /person/3 calls.
I'm wondering if there is a known solution to this problem (such as manually handling all the queries in a single top-level function somehow?)? Am I setting up my resolvers or schemas incorrectly? Is there some other Graphql or Apollo feature that I'm missing?
This is a bit of a contrived example but I have a real use case that is similar with even more nested resolvers (and so exponentially more queries being made redundantly).

Deleting children in parent-child relationship on update of parent using rest controller (grails.rest.Resource)

I'm using the Grails 3 grails.rest.Resource annotation in the following way:
#Resource(uri='/parent')
class Parent {
static hasMany = [children: Child]
}
class Child {
String property1
String property2
static belongsTo = [parent: Parent]
}
Now, let's say, I have a Parent object with 2 children and I issue a GET request for that Parent with something like GET localhost:8080/parent/1. The JSON response will look something like (assuming I'm not using the default JSON renderer, but that may not actually be relevant):
{
"id": "1",
"children": [
{
"id": "1",
"property1": "prop1",
"property2": "prop2"
},
{
"id": "2",
"property1": "prop1",
"property2": "prop2"
}
]
}
I want to be able to issue a PUT request with a JSON payload that looks something like...
{
"id": "1",
"children": []
}
... and have all of the children of the Parent be deleted.
Is this possible without implementing a custom rest controller? The children in this case are dependent objects and ideally this would be a single update as opposed to issuing separate DELETE requests on a rest controller for Child objects, and it would also be nice to not have to implement custom code to do the child delete =D.

LoopBack Relationships

This is my first time dealing with a NoSQL form of database and I'm a little confused about "relationships" in document-oriented databases. I'm using LoopBack & AngularJS.
I have a model page that has many page as it's children (i.e. menu items and submenus).
A page model is as follows:
"properties": {
"name": {
"type": "string",
"required": true
},
"slug": {
"type": "string"
},
"link": {
"type": "string"
},
"createdAt": {
"type": "date",
"required": true
},
"children": {
"type": [
"object"
]
}
},
with
"relations": {
"children": {
"type": "hasMany",
"model": "page",
"foreignKey": "parentId"
}
},
My confusion is that whenever I explore the LoopBack API, and then get the parent pages, I don't see the children property populated. But, doing a get to see the children of a parent (using the parent's id) turns out fine - I can see the parentId populated with it's parent.
My question is if this is normal when dealing with NoSQL/document-oriented databases, or am I doing something wrong?
Thanks a lot!
Sometimes LoopBack queries are getting messy when its come to relationships and parallel queries.
I think this is simply a query issue in LoopBack.
As I realized this is like Parent Page object can have multiple Children page objects.
We can use following query statement to retrieve related parent page and children pages.
app.models.Page.find({
where: {
parentId : 'yourPageId'
},
include: {
relation: 'Children'
}
}, function (err, pages) {
if (err) {
cb(err);
} else {
console.log("you will get related children pages alone with parent page")
cb(null, pages);
}
});
Hope this will work...!!
I believe you might be missing the other direction of the relationship.
You can do a belongsTo relation in the children to specify that it belongs to a parent.
That should enable you to see both directions' methods in the explorer.
Also, the foreingKey parentId should be set on the children, not on the parent. I.e. leave foreignKey empty on the parent relations definition, and instead use it on the children relations definition.
So on one hand, in the model you will have inside the relations field:
"children": {
"type": "hasMany",
"model": "page",
"foreignKey": ""
},
And also
"parent": {
"type": "belongsTo",
"model": "page",
"foreignKey": "parentId"
},
plus any other relations you have.
I have tested this and it works, although I have used two different models for the relation instead of only one.
I.e. I use
ModelA hasMany ModelB and ModelB belongsTo ModelA
instead of
ModelA hasMany ModelA and ModelA belongsTo ModelA
In mongoose when you want to get the page's "children" populated you need to specifically ask for it using:
Pages.find({})
.populate('children')
.exec(function(err, pages){
//..
})
Looking on LoopBack's page (http://loopback.io/doc/en/lb2/Querying-related-models.html) there is something similar called "include", you should try doing:
Page.find({include:'children'}, function() {
//...
});
Let me know if that worked!

Sailsjs controlling the attributes returned by relationship property

In my sailsjs app I have a data object that is returning a list of it's children objects. Now those children are returning complete attributes, is there a way for me to limit the children to return just one property (ex. the id)
currently i get something like this
{
"name": "parent",
"children": [
{
"id": "id456",
"name": "child",
"createdAt": "2015-09-09T03:10:42.000Z",
"dateAdded": "2014-10-10T04:00:00.000Z"
}
],
"id": "id123",
"createdAt": "2015-09-09T03:10:42.000Z",
"dateAdded": "2014-10-10T04:00:00.000Z"
}
I would like to get back this:
{
"name": "parent",
"children": [
"id456"
],
"id": "id123",
"createdAt": "2015-09-09T03:10:42.000Z",
"dateAdded": "2014-10-10T04:00:00.000Z"
}
Waterline does have select which can be used in a criteria object, but I haven't seen this work as a criteria object for .populate(). There is a bug with sails-mongo that makes select work incorrectly. It looks like this will be fixed shortly.
Anyways, if we assume that continues not to work, you could just map it:
Parent.find()
.populate('children')
.then(function(parent){
parent.children = _.map(parent.children, function(c){return c.id}))
})
It's kind of a pain but I have to do it often enough.

Spring MVC - how to return different JSON responses based on query parameters?

I am implementing a REST api using Spring MVC. The requirement is:
/transactions returns an array of transactions.
/transactions?groupByCategory returns transactions grouped by categories.
For example request #1 returns:
[
{ "id": 1, "category": "auto", "amount": 100 },
{ "id": 2, "category": "misc", "amount": 200 },
{ "id": 3, "category": "auto", "amount": 300 }
]
whereas request #2 groups this result by category and returns the sum of each category:
[
{ "category": "auto", "amount": 400 },
{ "category": "misc", "amount": 200 }
]
Obviously the return value from these requests is of different types. How do I do this in Spring MVC? So far I have:
#RequestMapping("/transactions")
public List<Transaction> getTransactions(
#RequestParam(value="groupByCategory", required=false) String groupByCategory
) {
...
}
But this fixes the return type to List<Transaction>. How do I accommodate the second type: List<TransactionSummaryByCategory>?
Edit: I found one solution, i.e. to specify the return type as Object. That seems to work and the response is serialized correctly based on the object type. However, I wonder if this is a best practice!
public Object getTransactions(...) {
...
}
You can simply provide two methods in your controller. First one returning List<Transaction> mapped using
#RequestMapping("/transactions")
and the second one returning List<TransactionSummaryByCategory> and mapped using
#RequestMapping(value = "/transactions", params = "groupByCategory")
You can return a generic List.
public List<?> getTransactions()
{
}
Based on the request params you can populate the list with the appropriate objects