Filtering parameters in Rest API - rest

I have two entities 'persons' and 'businesses' and both of them have a sub-resource (e.g locations)
So I have endpoints:
GET /persons/{id}/locations
GET /businesses/{id}/locations
Now I want an endpoint to filter locations of a main resource.
If I do:
GET /persons/{id}/locations?country={...}
GET /businesses/{id}/locations?country={...}
I will search locations of a specific person/business.
What is the best practice to filter locations of all persons
I have some ideas:
1. GET /persons/locations?country={...}
2. GET /locations?entity=persons&country={...}
But not sure these are fine.

You can work with the expand concept where you can be used with the relationship between the entities.
GET /persons
{
"data": [
{"person_id": 1},
{"person_id": 2}
],
"links": [
{
"rel": "locations",
"href": "/person/1/locations"
},
{
"rel": "locations",
"href": "/person/2/locations"
}
]
}
GET /persons?expand=locations&country={...}
{
"data": [
{"person_id": 1, "locations": [...]},
{"person_id": 2, "locations": [...]}
]
}

Related

Is there a known offset limit for NetSuite REST API calls?

world! We are trying to use the NetSuite SuiteQL REST API to pull down data. It works perfectly fine for most of the records we are sourcing, but we hit an interesting snag when we hit large tables.
Since the known limit of a single page of data is 1,000 rows, we are simply calling it with a limit of 1,000 and setting the offsets in 1,000 row increments. Something interesting happens when we get to an offset of 100,000 rows for a record that is larger than 100,000 rows.
If we call https://myinstance.suitetalk.api.netsuite.com/services/rest/query/v1/suiteql?limit=1000&offset=98000, we get all the links that we expect.
{
"links": [
{
"rel": "previous",
"href": "https://myinstance.suitetalk.api.netsuite.com/services/rest/query/v1/suiteql?limit=1000&offset=97000"
},
{
"rel": "first",
"href": "https://myinstance.suitetalk.api.netsuite.com/services/rest/query/v1/suiteql?limit=1000&offset=0"
},
{
"rel": "next",
"href": "https://myinstance.suitetalk.api.netsuite.com/services/rest/query/v1/suiteql?limit=1000&offset=99000"
},
{
"rel": "last",
"href": "https://myinstance.suitetalk.api.netsuite.com/services/rest/query/v1/suiteql?limit=1000&offset=753000"
},
{
"rel": "self",
"href": "https://myinstance.suitetalk.api.netsuite.com/services/rest/query/v1/suiteql?limit=1000&offset=98000"
}
],
"count": 1000,
"hasMore": true,
"items": [
{
[heres my data]...
Setting it to 99,000, a lot of that information disappears. It's almost as if it thinks this is the last page.
{
"links": [
{
"rel": "previous",
"href": "https://myinstance.suitetalk.api.netsuite.com/services/rest/query/v1/suiteql?limit=1000&offset=98000"
},
{
"rel": "first",
"href": "https://myinstance.suitetalk.api.netsuite.com/services/rest/query/v1/suiteql?limit=1000&offset=0"
},
{
"rel": "self",
"href": "https://myinstance.suitetalk.api.netsuite.com/services/rest/query/v1/suiteql?limit=1000&offset=99000"
}
],
"count": 1000,
"hasMore": false,
"items": [
{
[heres my data]...
Setting it to 100,000 flat out gives me an error.
{
"type": "https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.5",
"title": "Not Found",
"status": 404,
"o:errorDetails": [
{
"detail": "The specified query parameter 'offset' is out of bounds. Provide value between 0 and 753000.",
"o:errorQueryParam": "offset",
"o:errorCode": "INVALID_PARAMETER"
}
]
Has anyone seen this kind of behavior before? I scoured the documentation and couldn't find any mention of limitation in page offsets, so I'm thinking this might be a bug of some sort (the fact that it even tells you the maximum bounds and it's clearly higher than the offset specified makes me think it's a bug), but hoping someone may have seen this before, and even better, has ideas on how to get around this!
the official documentation for NetSuite REST Web Services mentions this limitation [1]:
Using SuiteQL queries, you can return a maximum of 100,000 results. For more information, see query.runSuiteQLPaged(options).

Return Connected Node's Properties Instead of RID using OUT() in OrientDB

I am attempting to store a connected Node's data in a property of a selected Node in OrientDB via the OUT() projection. e.g.:
SELECT *, OUT("Has_Friend") AS Friends FROM Person
Given that a "Person" Node is connected to several "Friend" Nodes via the "Has_Friend" Edge, I would like the actual Friend Node properties to be stored in the "Friends" property on each Person Node returned by this query. e.g.:
{
"result": [
{
"Name": "Joe",
"Friends": [
{
"Name": "Ben",
"Title": "Mr."
},
{
"Name": "Stan",
"Title": "Dr."
}
]
},
{
"Name": "Tim",
"Friends": [
{
"Name": "Terrance",
"Title": "Esq."
},
{
"Name": "Sarah",
"Title": "Dr."
}
]
}
]
}
However, the query only stores the RID of each "Friend" Node in the "Friends" property rather than the actual data of that "Friend" Node. e.g.:
{
"result": [
{
"Name": "Joe",
"Friends": [
"#228:1",
"#227:1"
]
},
{
"Name": "Tim",
"Friends": [
"#225:1",
"#226:1"
]
}
]
}
I've searched the OrientDB documentation but am unsure as to how I might accomplish this. I suspect there's a way to nest queries for those Friend nodes inside of the primary query, but I'm not entirely sure how to do that. Any insight is greatly appreciated!
try to use expand() function. It would expands the document pointed by that link and give all properties of this document. So your query should looks like this one:
SELECT expand(in("Has_Friend")) AS Friend FROM Person

Does the OData protocol provide a way to transform an array of objects to an array of raw values?

Is there a way specify in an OData query that instead of certain name/value pairs being returned, a raw array should be returned instead? For example, if I have an OData query that results in the following:
{
"#odata.context": "http://blah.org/MyService/$metadata#People",
"value": [
{
"Name": "Joe Smith",
"Age": 55,
"Employers": [
{
"Name": "Acme",
"StartDate": "1/1/1990"
},
{
"Name": "Enron",
"StartDate": "1/1/1995"
},
{
"Name": "Amazon",
"StartDate": "1/1/1999"
}
]
},
{
"Name": "Jane Doe",
"Age": 30,
"Employers": [
{
"Name": "Joe's Crab Shack",
"StartDate": "1/1/2007"
},
{
"Name": "TGI Fridays",
"StartDate": "1/1/2010"
}
]
}
]
}
Is there anything I can add to the query to instead get back:
{
"#odata.context": "http://blah.org/MyService/$metadata#People",
"value": [
{
"Name": "Joe Smith",
"Age": 55,
"Employers": [
[ "Acme", "1/1/1990" ],
[ "Enron", "1/1/1995" ],
[ "Amazon", "1/1/1999" ]
]
},
{
"Name": "Jane Doe",
"Age": 30,
"Employers": [
[ "Joe's Crab Shack", "1/1/2007" ],
[ "TGI Fridays", "1/1/2010" ]
]
}
]
}
While I could obviously do the transformation client side, in my use case the field names are very large compared to the data, and I would rather not transmit all those names over the wire nor spend the CPU cycles on the client doing the transformation. Before I come up with my own custom parameters to indicate that the format should be as I desire, I wanted to check if there wasn't already a standardized way to do so.
OData provides several options to control the amount of data and metadata to be included in the response.
In OData v4, you can add odata.metadata=minimal to the Accept header parameters (check the documentation here). This is the default behaviour but even with this, it will still include the field names in the response and for a good reason.
I can see why you want to send only the values without the fields name but keep in mind that this will change the semantic meaning of the response structure. It will make it less intuitive to deal with as a json record on the client side.
So to answer your question, The answer is 'NO',
Other options to minimize the response size:
You can use the $value OData option to gets the raw value of a single property.
Check this example:
services.odata.org/OData/OData.svc/Categories(1)/Products(1)/Supplier/Address/City/$value
You can also use the $select option to cherry pick only the fields you need by selecting a subset of properties to include in the response

REST and many to many

I'm basing my question on How to handle many-to-many relationships in a RESTful API? but want to continue from the accepted answer.
Let's suppose we have a many-to-many relationship between players and teams (just like in the question mentioned above).
As I understand it, there are several options to model this with REST resources:
The payload contains references to the related resources
GET /players/john
yields
{
"name": "John",
"_links": [
{
"rel": "team",
"href": "/teams/1"
},
{
"rel": "team",
"href": "/teams/4"
}
]
}
and
GET /teams/1
yields
{
"name": "Team 1",
"_links": [
{
"rel": "player",
"href": "/players/john"
},
...
]
}
This forces me to update a player-resource when I just want to add a player to the team. Furthermore, when I add a player to the team using a player-resource, the corresponding team-resource gets automatically updated. According to How to handle many-to-many relationships in a RESTful API?:
you don't want the alternate URL /players/5/teams/ to remain cached
In this case, teams/1 might remain cached when I update player "John" to remove team "Team 1" from it!
The relationship is modelled as another resource
GET /teams/1
yields
{
"name": "Team 1",
}
and
GET /players/john
yields
{
"name": "John",
}
Finally,
GET /relationships
yields
[
{
"_links": [
{
"rel": "player",
"href": "/players/john"
},
{
"rel": "team",
"href": "/teams/1"
}
]
},
...
]
This way, I can create and delete relationships without affecting both player-resources and team-resources. But when I delete /players/john, should the matching relationships be automatically deleted as well? If this is the case, the same rule as above is violated. If this is not the case we need the manually delete these relationships which is a lot of work I do not want to burden the consumers of my API with.
Furthermore, if we want to update the teams a certain player "John" is in, we need to delete some relationships and add others. We open ourselves up to merge conflicts (and race conditions) when someone else is editing the player "John" or the team "Team 1".
Each side of the relationship gets its own relationship-object
GET /teams/1/players
yields something like
{
"_links": [
{
"rel": "player",
"href": "/players/john"
},
...
]
}
and
GET /players/john/teams
something like
{
"_links": [
{
"rel": "team",
"href": "/teams/1"
},
...
]
}
But adding or removing one might still affect a resource that is located at a different URL (which does not share a root element)
My questions
Is there away around the problems I have mentioned in both cases?
Which of both approaches is 'preferable' or more pure REST?
How serious should I take the contstraint mentioned in How to handle many-to-many relationships in a RESTful API?:
you don't want the alternate URL /players/5/teams/ to remain cached
Thank you in advance!
You could have the following
Team
GET /teams/dream
{
"_links": {
"self": {
"href": "/teams/dream"
}
"players": {
"href": "/players?team=dream"
}
},
"name": "Dream"
}
Player
GET /player/john
{
"_links": {
"self": {
"href": "/player/john"
},
"teams": {
"href": "/teams?player=john"
},
},
"name": "John",
}
John's teams
GET /teams?player=john
{
"_links": {
},
"items": [
{
"href": "/teams/a-team"
}
],
}
Adding john to dream team, (using json patch for example) (query string on patch post...etc though rare, is valid)
PATCH /teams?player=john
[{
"op": "add",
"path": "/-",
"value": {
"href": "/team/dream"
}
}]
Get john's teams
GET /teams?player=john
{
"_links": {
},
"items": [
{
"href": "/teams/a-team"
},
{
"href": "/teams/dream"
}
]
}
John leaves A Team :
PATCH /teams?player=john
[{
"op": "remove",
"path": "/0"
}]

MongoDB: Tree Node Structure with Object-Maps instead of Collections

Using MongoDB for storage, if I wanted to represent a tree structure of nodes, where child nodes under a single parent always have unique node-names, I believe the standard approach would be to use collections and to manage the node name uniqueness on the app level:
Approach 1: Collection Based Approach for Tree Data
{ "node_name": "home", "title": "Home", "children": [
{ "node_name": "products", "title": "Products", "children": [
{ "node_name": "electronics", "title": "Electronics", "children": [ ] },
{ "node_name": "toys", "title": "Toys", "children": [ ] } ] },
{ "node_name": "services", "title": "Services", "children": [
{ "node_name": "repair", "title": "Repair", "children": [ ] },
{ "node_name": "training", "title": "Training"", "children": [ ] } ] } ] }
I have however thought of the following alternate approach, where node-names become "Object Map" field names, and we do without collections altogether:
Approach 2: Object-Map Based Approach (without Collections)
// NOTE: We don't have the equivalent of "none_name":"home" at the root, but that's not an issue in this case
{ "title": "Home", "children": {
"products": { "title": "Products", children": {
"electronics": { "title": "Electronics", "children": { } },
"toys": { "title": "Toys", "children": { } } } },
"services": { "title": "Services", children": {
"repair": { "title": "Repair", "children": { } },
"training": { "title": "Training", "children": { } } } } } }
The question is:
Strictly from a MongoDB perspective (considering querying, performance, data maintainability and data-size and server scaling), are there any major issues with Approach #2 (over #1)?
EDIT: After getting to know MongoDB a bit better (and thanks to Neil's comments below), I realized that both options of this question are generally the wrong way to go, because they assume that it makes sense to store multiple nodes in a single MongoDB document. Ultimately, each "node" should be a separate document and (as Neil Lunn stated in the comments) there are various ways to implement a hierarchy tree, as seen here: Model Tree Structures in MongoDB
I think this use-case is not good for Mongo DB, because:
there's(MongoDB 2.6) no compress algorithm (your documents will be too large)
Mongo DB use database-level locks (when you want one large document, all DB operations will be blocked)
it will be hard to index
I think better solution will be some relational DB for this use-case.