Has anyone used either [] or () in your REST API urls?
hypothetical examples:
/cars?[colors]:red,[engineType]:13
/cars?(colors):red,(engineType):13
says give me all cars with color red and a certain engine type. Colors is a sub property of the car resource.
Has anyone seen any issues using these to be aware of or is it pretty common to use?
Here's another example. Give me all the cities but only the cities where its people drink coffee
/cities?filter=(people[drinks[type]:6])
or I could even allow more sets as to perform ANDs like this
/cities?filter=(people[drinks[type]:6]),(another layer of filtering)&paging=(offset:10, limit:2)
essentially in the second, the comma itself is an implicit AND for the query because () denotes a filtering criteria so we have one filtering criteria, comma, second filtering criteria so this could easily be wired up to SQL via () and () if you think about it when parsing the url values out of the request and passing it down to a query in the backend.
this is an idea I have.
() - denotes one filter level, adding multiple () are multiple filters
[] - denotes a sub property of a resource
so the above allows the caller to say give me a list of cities but only those whos people like to drink coffee (type 6).
There isn't really an official specification of REST, but this is very unusual. The normal way to do this is to urlencode your parameters in key=value form. Almost all libraries are going to help you do that. You'd have to hand-parse this custom format you've invented (and you need to figure out any escaping issues; what if , or [ can be part of the string? It's unclear what the brackets are getting you in any case.
A more usual way to approach this would be:
/cars?color=red&engineType=13
There are 2 frequent patterns I met so far:
/cars/?colors=red&engineType=13
/cars/colors:red/engineType:13/
Using [] or () in URIs is not common. I don't think you'll have any issues by using them if that's what you desire. Just don't use {} if you want to use URI templates too.
Related
to is an infix function within the standard library. It can be used to create Pairs concisely:
0 to "hero"
in comparison with:
Pair(0, "hero")
Typically, it is used to initialize Maps concisely:
mapOf(0 to "hero", 1 to "one", 2 to "two")
However, there are other situations in which one needs to create a Pair. For instance:
"to be or not" to "be"
(0..10).map { it to it * it }
Is it acceptable, stylistically, to (ab)use to in this manner?
Just because some language features are provided does not mean they are better over certain things. A Pair can be used instead of to and vice versa. What becomes a real issue is that, does your code still remain simple, would it require some reader to read the previous story to understand the current one? In your last map example, it does not give a hint of what it's doing. Imagine someone reading { it to it * it}, they would be most likely confused. I would say this is an abuse.
to infix offer a nice syntactical sugar, IMHO it should be used in conjunction with a nicely named variable that tells the reader what this something to something is. For example:
val heroPair = Ironman to Spiderman //including a 'pair' in the variable name tells the story what 'to' is doing.
Or you could use scoping functions
(Ironman to Spiderman).let { heroPair -> }
I don't think there's an authoritative answer to this. The only examples in the Kotlin docs are for creating simple constant maps with mapOf(), but there's no hint that to shouldn't be used elsewhere.
So it'll come down to a matter of personal taste…
For me, I'd be happy to use it anywhere it represents a mapping of some kind, so in a map{…} expression would seem clear to me, just as much as in a mapOf(…) list. Though (as mentioned elsewhere) it's not often used in complex expressions, so I might use parentheses to keep the precedence clear, and/or simplify the expression so they're not needed.
Where it doesn't indicate a mapping, I'd be much more hesitant to use it. For example, if you have a method that returns two values, it'd probably be clearer to use an explicit Pair. (Though in that case, it'd be clearer still to define a simple data class for the return value.)
You asked for personal perspective so here is mine.
I found this syntax is a huge win for simple code, especial in reading code. Reading code with parenthesis, a lot of them, caused mental stress, imagine you have to review/read thousand lines of code a day ;(
I have this armor table, that has three fields to identify individual designs: make, model and version.
I have to implement a search feature for our software, that lets a user search armors according to various criteria, among which their design.
Now, the users' idea of a design is a single string that contains make, model and version concatenated, so the entry is that single string. Let's say they want to look up the specifications for make FH, model TT, version 27, they'll think of (and type) "FHTT27".
We use an IQueryOver object, upon which we add successive conditions according to the criteria. For the design, our code is
z_quoQuery = z_quoQuery.And(armor => armor.make + armor.model + armor.version == z_strDesign);
Which raises an InvalidOperationException, "variable 'armor' of type 'IArmor' referenced from scope '', but it is not defined".
This is described as a bug here: https://github.com/mbdavid/LiteDB/issues/637
After a lot of trial and error, it seems that syntaxs that don't use the armor variable first raise that exception.
Obviously, I have to go another route at least for now, but after searching for some time I can't seem to find how. I thought of using something like
z_quoQuery = z_quoQuery.And(armor => armor.make == z_strDesign.SubString(0, 2).
And(armor => armor.model == z_strDesign.SubString(2, 2).
And(armor => armor.version == z_strDesign.SubString(4, 2);
Unfortunately, the fields are liable to have variable lengths. For instance, another set of values for make, model, and version might be, respectively, "NGI", "928", and "RX", that the code above would parse wrong. So I can't bypass the difficulty that way. Nor can I use a RegEx.
Neither can I make up a property in my Armor class that would concatenate all three properties, since it cannot be converted to SQL by NHibernate.
Has someone an idea of how to do it?
Maybe I should use an explicit SQL condition here, but how would it mix with other conditions?
It seems you can use Projections.Concat to solve your issue:
z_quoQuery = z_quoQuery.And(armor => Projections.Concat(armor.make, armor.model, armor.version) == z_strDesign);
If a REST API endpoint gets all, then filters are easy. Lack of a filter means "get all results".
GET /persons - gets all persons
GET /persons?name=john - gets all persons with name of "john"
But if there is a default, then I need some way to explicitly not set the default filter. Continuing the above example, if each person has a state, "approved" or "pending", and if my system is set such that if I do not explicitly specify a state, it will return all "approved":
GET /persons - gets all approved persons, because defaults to state=approved
GET /persons?state=approved - same thing, gets all approved persons
GET /persons?state=pending - gets all pending persons
How do I get all persons? What if there are 10 possible states? Or 100?
I can think of a few ways:
GET /persons?state=any - but then I can never use the actual state any
GET /persons?state=* - would work, but feels strange? Or is it?
GET /persons?state= - some URL parsing libraries would complain about a blank query parameter, and does this not imply "state is empty" as opposed to "state is anything"?
How do I say in my GET, "override the default for the state to be anything"?
Maybe this could work for you:
GET /persons?state - gets all persons that have a state name, no matter which value
GET /persons?state= - gets all persons that have an empty value for the state name
You probably don’t need to differentiate between these two situations, so you could use either one for getting all persons with the state name (I just think that the variant without = is more beautiful).
FWIW, the application/x-www-form-urlencoded format (i.e., typically used in HTML forms) doesn’t differ between an empty and no value.
As far as the URI standard is concerned, this name-value pair syntax in the query component is only a convention anyway, so you can use whichever syntax/semantics you wish.
I don't think there is one answer to this question. As long as you document that the default state is approved well I don't think it matter to the clients if you pass any, * etc. All of your proposals are fine except the last one. I don't think that is a good one.
If I was designing the API I would use all and keep this as a standard. I would also recommend to use paging for all endpoints that returns list of elements. I use offset and limit as paging query parameters. In my API I return 20 elements as default if the client haven't specified another paging criteria.
Consider the case where a certain mocked function is expected to be called several times, each time with a different value in a certain parameter. I would like to validate that the function was indeed called once and only once per value in a certain list of values (e.g. 1,2,5).
On the other hand, I would like to refrain from defining a sequence as that would dictate a certain order, which is an implementation detail I would like to keep free.
Is there some kind of matcher, or other solution for this case?
I'm not sure if this influences the solution in any way but I do intend to use WillOnce(Return(x)) with a different x per value in the list above.
By default gMock expectations can be satisfied in any order (precisely for the reason you mention -- so you don't over specify your tests).
In your case, you just want something like:
EXPECT_CALL(foo, DoThis(1));
EXPECT_CALL(foo, DoThis(2));
EXPECT_CALL(foo, DoThis(5));
And something like:
foo.DoThis(5);
foo.DoThis(1);
foo.DoThis(2);
Would satisfy those expectations.
(Aside: If you did want to constrain the order, you should use InSequence: https://github.com/google/googletest/blob/master/googlemock/docs/cook_book.md#expecting-ordered-calls-orderedcalls)
If you expect a function, DoThing, to be called with many different parameters, you can use the following pattern:
for (auto const param : {1, 2, 3, 7, -1, 2}){
EXPECT_CALL(foo, DoThing(param));
}
This is particularly helpful if your EXPECT_CALL includes many parameters, of which only one is changing, or if your EXPECT_CALL includes many Actions to be repeated.
Following conversion
SELECT to_tsvector('english', 'Google.com');
returns this:
'google.com':1
Why does TSearch2 engine didn't return something like this?
'google':2, 'com':1
Or how can i make the engine to return the exploded string as i wrote above?
I just need "Google.com" to be foundable by "google".
Unfortunately, there is no quick and easy solution.
Denis is correct in that the parser is recognizing it as a hostname, which is why it doesn't break it up.
There are 3 other things you can do, off the top of my head.
You can disable the host parsing in the database. See postgres documentation for details. E.g. something like ALTER TEXT SEARCH CONFIGURATION your_parser_config
DROP MAPPING FOR url, url_path
You can write your own custom dictionary.
You can pre-parse your data before it's inserted into the database in some manner (maybe splitting all domains before going into the database).
I had a similar issue to you last year and opted for solution (2), above.
My solution was to write a custom dictionary that splits words up on non-word characters. A custom dictionary is a lot easier & quicker to write than a new parser. You still have to write C tho :)
The dictionary I wrote would return something like 'www.facebook.com':4, 'com':3, 'facebook':2, 'www':1' for the 'www.facebook.com' domain (we had a unique-ish scenario, hence the 4 results instead of 3).
The trouble with a custom dictionary is that you will no longer get stemming (ie: www.books.com will come out as www, books and com). I believe there is some work (which may have been completed) to allow chaining of dictionaries which would solve this problem.
First off in case you're not aware, tsearch2 is deprecated in favor of the built-in functionality:
http://www.postgresql.org/docs/9/static/textsearch.html
As for your actual question, google.com gets recognized as a host by the parser:
http://www.postgresql.org/docs/9.0/static/textsearch-parsers.html
If you don't want this to occur, you'll need to pre-process your text accordingly (or use a custom parser).