RESTapi nesting endpoint - rest

Ok, new to RESTapi so not sure if I am using the correct terminology for what I want to ask so bear with me. I believe what I am asking about is nested resources in a service but I want to ask specifically about using it for separating a blob of "closely related" content. It may be easier to provide an example. Let's say I have the following service that could output the following:
/Policy
"data": [ {
"name": "PolicyName1",
"description": "",
"size": 25000,
.... (bunch of other fields)
"specialEnablement": true,
“specialEnablementOptions”: { <-- options below valid only if specialEnablement is true
“optionType”: “TypeII”,
“optionFlagA”: false,
“optionFlagB”: true,
“optionFlagC”: false,
...(bunch of other options here)
}
},
{ . . . }],
The specialEnablementOptions are only used if specialEnablement is 'true'. It is all part of this /Policy service so has no primary key other than the policy "name" (and doesnt make sense to have to generate one) so does not fall under some of the other questions I have been reading about nested resources.
It does make it more readable to separate this set of information since there are 12 or so options but, this is REST so, maybe human readability does not weigh heavily here.
I am being told that, if we do it this way, it makes it more complex to work with during POST/PUT/PATCH commands. Specifically, it is being said in my group that if we do this, we should require two calls....one that creates the policy main information then the user must call a second time to PATCH the specialEnablementOptions (assuming specialEnablement is true). This seems kludgy to me.
I am looking for expert advise on what the best practice is.
My questions:
Does having the specialEnablementOptions nested in this way cause a
lot of complexity. Seems to me that either way we have to verify
that the settings are valid?
Does having the specialEnablementOptions nested in this way require
two calls? In other words, can a user not do a POST/PATCH/PUT for
all the fields including those in the specialEnablementOptions in
one call? We are planning to provide a way for the user to do a
PATCH of just the specialEnablementOptions options without changing
any of the first level for ease of use but is there something that
prevents them from creating or modifying all settings in one call?
Another option is to just get rid of the nested
specialEnablementOptions and put everything at the same level. I
dont have a problem with this but wasn't sure if this was just being
lazy. I dont mind doing this if the consensus is it is the best way
to do it....but I also have a second example that is similar to this
scenario but is a bit more complex where putting everything under the parent level is not really optimal (I will show in the next example)
So, my second example is as follows:
/anotherPolicy
"data": [ {
"name": "APolicyName1",
"description": "",
"count": 123,
"lastModified": "2022-05-17-20.37.27.000000",
[{
"ownerId": 1
"ownerCount": 1818181
"specialFlags": 'ABA'
},
{ . . . }]
},
{ . . . }],
The above 'count' is the total number associated to that policy and then there is a nested resource by owner where the count by owner can be seen..plus maybe other information specific to that owner. The SUM(ownerCount) would equal "count" above it. Does this scenario change any of the answers to the questions above?
I appreciate your help. I found a ton of information and reference on when to use or not use nested endpoints but all the examples seem to orient around subjects that seem like they could easily be separated into two resource...for instance whether to nest /employees under /departments or /comments under /posts. Also, they didn't deal with the complexities of having nested endpoints vs avoiding them. And last, if using nesting is unnecessary as a readability standpoint.

Related

Ranking rules for camelCase attributes

I'm building an Algolia index to search through user-created communities on my site.
Just like for subreddits, the name of the communities can't contain spaces and are therefore often written by users in camelCase.
Here is an example of an object in my index:
{
"name": "headphoneAdvice",
"description": "This community is dedicated to enthusiasts and newcomers. We are all about making the right decision when purchasing new headphones."
}
Both name and description are set to be searchable attributes and i'm currently using these ranking rules :
["typo","geo","words","filters","proximity","attribute","exact","custom"]
However, this does not seem to work well with the camelCase name. For example, if I type "advice" in the search, the object above with "name": "headphonesAdvice" isn't found.
I'm guessing this is because words in camelCase are considered single words and thus do not match.
I've looked online for rules that allow indexing of camelCase attributes but couldn't find anything really.
Any ideas?
Cheers!
After asking around, found that someone at algolia thought of this and added https://www.algolia.com/doc/api-reference/api-parameters/camelCaseAttributes/ kudos!

Can you list multiple features within the same Schema.org "LocationFeatureSpecification"?

I am working on Schema.org Resort schema for a ton of resorts on a travel website and am trying to find the most efficient ways of filling out the schema with regards to amenities.
The current code looks something like this:
"amenityFeature": [
{
"#type":"http://schema.org/LocationFeatureSpecification",
"name":"Spa",
"value":"true"
},
{
"#type":"http://schema.org/LocationFeatureSpecification",
"name":"Internet Access",
"value":"true"
},
{
"#type":"http://schema.org/LocationFeatureSpecification",
"name":"Tennis Courts",
"value":"true"
}
]
My question is, can I write it like this instead to shorten lines of code:
{
"#type":"http://schema.org/LocationFeatureSpecification",
"name":[
"Spa", "Internet Access", "Tennis Courts"
],
"value":"true"
}
When I test it in Google’s Structured Data Testing Tool, it doesn’t give any errors. Here is what it looks like in the SDTT when I write it the short way:
And here is what it looks like if I do it the first/long way:
If I do it the short way, I want to make sure all those items are getting listed as amenities and not just different names for the same amenity. Otherwise, I'll go the long route.
No, each LocationFeatureSpecification represents one feature:
Specifies a location feature by providing a structured value representing a feature of an accommodation as a property-value pair of varying degrees of formality.
Your second snippet would represent one feature with multiple names.

Mongo query with regex fails when backslash\newline is there in a field

Hi I have a field in a user collection called "Address".User saving their address from a textarea in my application. mongodb convert it to new line like following.
{
"_id": ObjectId("56a9ba0ffbe0856d4f8b456d"),
"address": "HOUSE NO. 3157,\r\nSECTOR 50-D",
"pincode": "",
},
{
"_id": ObjectId("56a9ba0ffbe0856d4f8b456d"),
"address": "HOUSE NO. 3257,\r\nSECTOR 50-C",
"pincode": "",
}
So now When I am running a search query on the basis of "address".Like following:
guardianAdd = $dm->getRepository('EduStudentBundle:GuardianAddress')->findBy(array(
'address' => new \MongoRegex('/.*' .$data['address'] . '.*/i'),
'isDelete' => false
));
echo count($guardianAdd);die;
it does not give any result. My Searchi key word is : "HOUSE NO.3157 SECTOR 50-D".
However if I am searching using like: HOUSE NO. 3157 its giving correct result.
Please advice how to fix this.Thanks in advance
First of all, trailing .* are redundant. regexps /.*aaa.*/ and /aaa/ are identical and match the same pattern.
Second, you probably need to use multiline modifier /pattern/im
Finally, it is not quite clear what you want to fix. The best think you can do is to provide some basic explanation of regex syntax in the search form, so users can search properly, e.g. HOUSE NO.*3157.*SECTOR 50-D to get best results.
You can make some bold assumptions and build the pattern with something like
$pattern = implode('\W+',preg_split('/\W+/', $data['address']))
which will give you a regexp HOUSE\W+NO\W+3157\W+SECTOR\W+50\W+D for different kind of HOUSE NO.3157 SECTOR 50-D requests, but it will cut all the regex flexibility available with bare input, and eventually will result with unexpected response anyway. You can follow this slippery slope and end up with your own query DSL to compile to regex, but I doubt it can be any better or more convenient than pure regex. It will be more error prone for sure.
Asking right question to get right answers is true not only on SO, but also in your application. Unfortunately there is no general solution to search for something that people have in mind, but fail to ask. I believe that in your particular case best code is no code.

RESTful reordering of nested objects

I have a RESTful API that supports two objects so as object A contains an ordered list of nested objects B:
Create object A - POST /a
Create object B and add to A - POST /a/<id>/b
Update object B in A - PATCH /a/<id>/b/<id>
What would be a RESTful way to update the order of B objects in a specific A?
Option 1: PATCH /a/<id> with json content that replaces A.Bs
A has a list of embedded Bs, namely A.Bs so you can replace that list in its entirety also changing the order on the way. This relies on the client to resubmit the entire list correctly.
Option 2: PATCH /a/<id> with json content that replaces A.B_order
Add a separate list of B ids and have the client update it. This is similar to Option 1 but does not rely on the client resubmitting all the objects. It does require the server to manage the list, updating it upon B creation, and validating the update contains all the required B ids on list order update.
Option 3: PATCH /a/<id>/b with json content that replaces A.Bs
The same as Option 1, but with a different URL
Which would be most RESTful and clear?
Any other options?
I would suggest using the proposed standard defined in RFC 6902. Specifically, the "move" op would seem to be what you're looking for.
Given Foo has Bars and Bars are resources (have ID or link), when you need to reorder foo.bars then I would suggest:
’PUT /foos/:id/bars’ with array of IDs or links in the body.
But if Bars are not resources (have no ID), then:
’PATCH /foos/:id’ with body of Foo including complete new array of Foo.bars in the ’bars’ property.
The question I would ask myself is: "What does 'order' mean in this case".
The specific instances of B don't have an order between them. They're all independent resources that are not really 'aware' of each order.
Given that, it's not really the B resource that you are changing. What are you changing?
Presumably there is a collection of B's somewhere. You do a GET request on that collection to get an ordered list of B's. Do you get that list on /a/<id> or on /a/<id>/b ?.
Wherever that ordered list is, I would also do the operation to change the order because the order is a 'property' of the collection.
So for the sake of the argument, lets assume that your 'collection of B lives on /a/<id>b. What format should that be?
Well, a good REST service will replace the entire state. So as a default I would do a PUT request on that resource and do a full replace of the entire thing.
If you don't like that idea and want to use PATCH to update only a part of the collection (and nothing else), I think I would opt for one of these:
Use a standard format, like json-patch.
Come up with your own syntax to describe this.
Option 2 will likely be a lot simpler to implement, and I would also keep the format as simple as possible.
If you use a format like HAL, a collection is probably a list of links. In that case I would use a syntax like:
{
"_links": {
"item": [
{ "href": "/a/<id>/b/ordered-item-1" },
{ "href": "/a/<id>/b/ordered-item-2" }
]
}
}
If you don't have a hypermedia-style API, you probably use id's and force the client to expand id's in urls. In that case, I'd imagine the format could look like:
{
"items": [ 1, 3, 5, 2]
}
In each case, it's a Good Idea to define your own media type for this, because this format for PATCH has special meaning to your api. For example:
application/vnd.jonathan.patch+json

Address an ordered list the RESTful way

I doubt what's the best way to address an ordered list in a RESTful API. Imagine the following example: Let's create a chart list of LPs, where you want to add new LPs, delete those which aren't in the TOP10 yet, and change their positions. How would you implement those methods in a RESTful JSON-API?
I thought of the following way:
GET / to return the ordered chart list like [{ "name": "1st-place LP", "link": "/uid123" }, { "name": "2nd-place LP", "link": "/uid987" }, ...]
GET /{uid} to return a LP by its unique ID, returning sth. like {"name": "1st-place LP", "ranking": 1 }
GET /ranking/{position} to access e.g. the current first-ranked LP, returning a 303 See Other with a Location-header like Location: /uid123
POST / with request body { "name": "my first LP title" } to create a new LP without specifying its current chart position
Now it's the question how we could change the current chart positions? One could simply PUT /{uid} to update the ranking attribute, but I think a PUT /ranking/{position} would be more natural. On the other hand it doesn't make sense to PUT against an URI which will return a 303 See Other when using GET.
What do you think would be the best way to address such a chart list? I don't like the solution of changing simply the ranking attribute in the LP-datasets as this could end in senseless states like two LPs with the same ranking and so on.
I see two questions. 1. What is the most RESTful (beautiful) way to design the API? 2. How do I make sure that two LPs does not get the same ranking?
1:
Your LPs could have several properties that are relative to eachother, e.g. different ranking on different charts. I would say that you want the ranking moved OUT of your LP resource. Keep the ranking on a certain list as a separate resource. Example:
GET /LPuid only returns properties about the LP, not relative properties, like rankings
GET /billboard/3 returns the URI to LP that has rankning 3 on the billboard list.
PUT /billboard takes a document of 100 LP URI's.
PUT /billboard/3 INSERTS an LP URI at that ranking and moves the other ones down.
2: That has nothing to do with rest and you would have that issue no matter how you design your API. Transactions is one solution.
You have two collection resources within your music service. As such, I would design a URI structure like this:
/ => returns links to collections (ergo itself a collection resource)
/releases => returns a list of LPs
/chart => returns the top 10 LPs, or redirects to the current chart URI
You would POST to /releases to add a new LP, and PUT or PATCH to /chart to define a new chart or alter the current chart. You will need to define what representation formats are transfered in each case.
This gives you the flexability to define thinks like /chart/2012-12-25 to show the chart as it stood on christmas day 2012.
I do not suggest using PUT /chart/{position} to insert an LP at a specific position and shuffle everything else down. Intermediarys would not know that a PUT to that URI causes other resources to change their URIs. This is bad for caching.
Also, as a user, I would hope you avoid the word "billboard" as the other answer suggests. A billboard conjures in the mind pictures of an advertising hoarding, and not anything to do with ranking charts!