Designing REST API(s), more complicated objects or more requests? - rest

I have problem with REST API(s) for front-end GUI and am wondering which approach is better. Are there any design patterns for these types of problems?
uri: /users/list
response: [
{
id: "1",
name "Aaa",
surname "Bbb",
contactDetails: {
telephone: "111-111-111"
email: "mail#mail.pl"
}
},
...
]
OR
uri: /users/list
response: [
{
id: "1",
name "Aaa",
surname "Bbb"
},
...
]
uri: /emails/list?userIds=1,..
response: [
{
userId: "1",
email: "mail#mail.pl"
}
]
uri: /telephones/list?userIds=1,..
response: [
{
userId: "1",
telephone: "111-111-111"
}
]
and it's the same for a single user:
uri : users/{id}
uri : users/{id}/emails
uri : users/{id}/telephones
============== Extended class model =================================
Below I paste JSON classes designed for question needs.
SystemPart : {
id : "sp2",
name : "UserAdministration",
parentSystemPart : {
id : "sp1",
name : "Administration",
...
}
...
}
SystemPermission : {
permissionType : "MODERATOR",
systemParts : [ // list of SystemPart
{
id : "sp1",
name : "UserAdministration",
parentSystemPart:{...}
},
...
],
...
}
User: {
id : "u1",
name : "a",
surname : "b",
contactDetails : {
telephone : "111-111-111"
email : "mail#mail.com"
},
identityCard : {
idType : "Id",
number : "321"
}
systemPermissions : [ // list of SystemPermission
{
permissionType : "MODERATOR",
systemParts : [...]
},
...
]
}
MapPoint : {
id : "mp1",
x : 11.11,
y : 22.22,
createdBy : { // User
id : "u1",
...
systemPermission : [...]
}
}
GUI client would like to show map point data with only it's author name, and surname
and now api for list of MapPoints
/map-points/list?x=11.00&y=22.00&d=5.0
other part of GUI would like to get list of users with its permissions
/users/list?page=0&size=5
In my opinion problem is in map-points list api which JSON is to big

I'd go with the first approach. The User class is pretty small and I don't see any benefits to calling the service separately for contact details.
Ensure that the client can filter the results based on every parameter, that way it is easy for the user of your API to get exactly what he/she wants.
For e.g. /users/list will get back everything which is perfect if there are relatively small number of users in the list and it's better to eagerly cache them all to improve client's performance.
uri: /users/list
response: [
{
id: "1",
name "Aaa",
surname "Bbb",
contactDetails: {
telephone: "111-111-111"
email: "mail#mail.pl"
}
},
...
]
If the number of users are significantly large, make sure the list can be filtered down to a small quantity based on every(or at least the significant ones like last name) parameter and the client can call your service for specific users and lazily load them as and when needed.
uri: /users/list?surname=Bbb
or
uri: /users/list?id=1
should get back:
response: [
{
id: "1",
name "Aaa",
surname "Bbb",
contactDetails: {
telephone: "111-111-111"
email: "mail#mail.pl"
}
}
]

Related

Referencing for mongoose

i'm currently trying to reference a collection called items with the structure below
packageSchema = schema({
recipient: String,
contents: [{item :{type: mongoose.Schema.Types.ObjectId,
ref: 'items', required : true}, amount: String}]
Below is my code for getting one package via its id
getOnePackage : function(id,callback)
{
packageModel.findById(id,callback)
.populate('contents')
}
So when i call the above function i'm expecting to get this result
{
recipient : Dave
contents : [
{item : {
_id:5d2b0c444a3cc6438a7b98ae,
itemname : "Statue",
description : "A statue of Avery"
} ,amount : "2"},
{item : {
_id:5d25ad29e601ef2764100b94,
itemname : "Sugar Pack",
description : "Premium Grade Sugar From China"
} ,amount : "5"},
]
}
But what i got from testing in Postman is this :
{
recipient : Dave,
contents : []
}
May i know where did it went wrong? And also how do i prevent mongoose from automatically insert an objectId for every single element in the contents array....
Because element in contents array is object with item field so your populate should be:
.populate('contents.item')

How to access arguments on child resolver from parent call in AWS Appsync

I have two types: Todo and Comment.
type Todo {
id: ID!
name: String
description: String
priority: Int
status: TodoStatus
comments: [Comment]
}
type Comment {
todoid: ID!
commentid: String!
content: String
}
Then I have a Query getTodo but the thing is I want to include a content arg that filters the comment (child) if the string passed is in the content of Comment.
getTodo(id: ID!, content: String!): Todo
I have tried attaching a resolver to comments (under Todo). If I add a filter here, how will I be able to get the ctx.args.content which was passed in getTodo(id: ID!, content: String!).
{
"version" : "2017-02-28",
"operation" : "Query",
"query" : {
## Provide a query expression. **
"expression": "todoid = :id",
"expressionValues" : {
":id" : {
"S" : "${ctx.args.id}"
}
}
},
"filter": {
"expression": "contains(content, :content)",
"expressionValues" : {
":content": {
"S": "${ctx.args.content}"
}
}
}
}
Or if I remove this filter and leave it like this:
{
"version" : "2017-02-28",
"operation" : "Query",
"query" : {
## Provide a query expression. **
"expression": "todoid = :id",
"expressionValues" : {
":id" : {
"S" : "${ctx.args.id}"
}
}
}
}
How will I modify getTodo Resolver to fetch comments (with content that contains the string passed)?
Can I do it like this (accessing if comments.content contains the content string args passed):
{
"version" : "2017-02-28",
"operation" : "Query",
"query" : {
## Provide a query expression. **
"expression": "id = :id",
"expressionValues" : {
":id" : {
"S" : "${ctx.args.id}"
}
}
},
"filter": {
"expression": "contains(comments.content, :content)",
"expressionValues" : {
":content": {
"S": "${ctx.args.content}"
}
}
}
}
The GraphQL arguments you are accessing via $ctx.args are available at the field level. So when you access them when resolving the Post.comments field, you get back all the arguments on that field and that field only.
So to get the content string argument you could update your Todo type to:
type Todo {
id: ID!
name: String
description: String
priority: Int
status: TodoStatus
comments(content: String): [Comment]
}
Another way, if you don't want to expose the content argument on the Post.comments field and keep the argument on the Query.getTodo field, you could pass the arguments via the source. In your Query.getTodo resolver you could return the content field as part of the todo result. You would then be able to access it inside the Todo.comments resolver via $ctx.source.content.

I can't perform a REST request with Sencha

I want to perform a rest request with sencha ext js. Threfore I created a model and a store with a proxy. Then I invoked the load function of the store. The problem is that after the invocation the store is still empty. I know this because I debugged it. This is the code:
var myModel = Ext.create('Ext.data.Model', {
fields: [
{ name: 'name' },
{ name: 'age' }
]
});
var myStore = Ext.create('Ext.data.Store', {
model: myModel,
proxy: {
type: 'rest',
url: 'http://localhost:8080/blablabla',
}
});
myStore.load();
The url 'http://localhost:8080/blablabla' is correct because when I type it in the browser I get the json list of users with the "name" and "age" fields. So the server works.
Here is an example of json that I should get:
[ {
"id" : 1,
"name" : "john",
"age": 40
}, {
"id" : 2,
"name" : "jack",
"age": 30
} ]
My Sencha code was correct. The problem was CORS not enabled. So I resolved by adding #CrossOrigin above my server method.
#CrossOrigin
#RequestMapping
public List<Thing> getThings() {
...
return myListOfThings;
}
#CrossOrigin did the trick.

How can I get details of single field in mongo db

I am making a web app. Currently I am storing the messages inside messages columns like below.
I have a column called msges and I have messages as time as key and value details. I want to create a function in which I pass the time, It will return the details of it. Can anyone help me? I can get single field but I don't know how to get it through key value. This is my function.
function getMessageDetails(uname,time,callback){
global.users.find({"uname" : uname,"msges":time},
// {"friends.friendUname":1,_id:0},
{_id:0},
function(err,doc){
if(err){
callback(false,err,"Message not found.",null);
}else{
callback(true,null,"",doc);
}
}
);
}
Thanks in advance. :)
I'd personally try to model your data a bit diffrently, If you had:
{
_id: "123123",
//...
friends: [
{ friendName: "etc..."}
],
msges : [
{
time: "16:25:02",
from: "alizia",
title : "hi buddy",
read: true
},
{
time: "12:25:02",
from: "bob",
title : "hi bobby",
read: false
}
]
}
You'd be able to query the following data by:
db.users.find({_id: "123123", "msges.time" : "16:25:02"}, { "msges.$.from" : 1 })
and will just pull out the one msg based on the query:
{
"_id" : "123123",
"msges" : [
{
"time" : "16:25:02",
"from" : "alizia",
"title" : "hi buddy",
"read" : true
}
]
}

Find the documents in mongoose whose array fields exactly match

I'm using Mongoose and have a schema like this:
var chat = new mongoose.Schema({
chatId : String,
members : [{
id : String,
name : String
}]
});
Suppose I have two chat document like this
{
chatId : 'Edcjjb',
members : [
{
id : 'a1',
name : 'aaa'
},
{
id : 'b1',
name : 'bbb'
}
]
}
{
chatId : 'Fxcjjb',
members : [
{
id : 'a1',
name : 'aaa'
},
{
id : 'b1',
name : 'bbb'
},
{
id : 'c1',
name : 'ccc'
}
]
}
I want to find all those documents which have only specfied members Id.
For example, if I specify a1 and b1
then only the first document should be retrieved as the second document contains id c1 as well.
And if I specifiy a1,b1,c1
then only second document should be specified.
Please tell me how to do this in mongoose
You can specify a clause on the array size, like
{ members : { $size : 2 } } in your first example and
{ members : { $size : 3 } } in the second one.
Can that work for you?
EDIT: I should also mention that the other part of the query should be
{ "members.id": { $all: [ "a1" , "b1" ] } }
and, for the second example,
{ "members.id": { $all: [ "a1" , "b1", "c1" ] } }