I'm fairly new to Play 2 (Scala). I need to use pagination to output the members of a list. This is easy enough, except the pagination part.
In my route file I have my search:
GET /find/thing/:type controllers.Application.showType(type: String)
This works fine if I wanted to dump the entire list to the page.
Now, what if I want to paginate it? I suppose I could do -
GET /find/thing/:type/:page controllers.Application.showType(type: String, page: Int)
But then what happens if the user just types "myurl.com/find/thing/bestThing" without the page? Clearly there will be an error when it should automatically "default" to page 1.
Is there a way to default these arguments? If not, what is the best practice for this?
Thank you!
Two options:
declare both routes you mentioned (first using parameter with fixed value), then you can use untrail trick globally, in such case it will redirect your /find/thing/something/ to /find/thing/something (page=1)
You can use parameters with default values, then your route will be like:
GET /find/thing/:type controllers.Application.showType(type: String, page: Int ?= 1)
and genereted URL will be like:
/find/thing/something?page=123
You could use a query string parameter instead of a path parameter for the page number. Query string parameters will allow you to provide default values for when the parameter is missing.
GET /find/thing/:type controllers.Application.showType(type: String, page: Int ?= 1)
You would use them like this:
/find/thing/bestThing?page=3 // shows page 3
/find/thing/bestThing // shows page 1
Related
I'm trying to handle pagination without using string interpolation and also take advantage of http4s features.
I have came across the OptionalQueryParamDecoderMatcherand I don't know if it is a good match in my use case.
So the response contain header that has information about the number of pages in the Link attribute It has rel set to prev, next, first, or last. as follows :
<https://gitlab.example.com/api/v4/projects/8/issues/8/notes?page=1&per_page=3>; rel="prev", <https://gitlab.example.com/api/v4/projects/8/issues/8/notes?page=3&per_page=3>; rel="next", <https://gitlab.example.com/api/v4/projects/8/issues/8/notes?page=1&per_page=3>; rel="first", <https://gitlab.example.com/api/v4/projects/8/issues/8/notes?page=3&per_page=3>; rel="last"
My idea is to get the number of pages specified as last (which is the total number of pages) and then increment by one to get all the results.
The first way I thought about is string interpolation, but I believe that there would be a much simpler way to do it especially taking advantage of http4s.
Can someone enlighten me ? I'm open to your suggestions.
note: the httpRoute is specified as this example :
val routes = HttpRoutes.of[IO] {
case GET -> Root /"projects"/project_name/"Details"
}
As described in documentation you can use query matchers to extract data from query.
object Page extends OptionalQueryParamDecoderMatcher[Int]("page")
object PerPage extends OptionalQueryParamDecoderMatcher[Int]("per_page")
val routes = HttpRoutes.of[IO] {
case GET -> Root / "projects" / project_name / "Details" :? Page(page) :? PerPage(perPage) =>
...
}
OptionalQueryParamDecoderMatcherand is indeed the right usage here.
(Personally, I prefer to define API using something like Tapir or Endpoint4s (I find it saner for many reasons) and then interpret it into HTTP4s. It's a very simple way of avoiding many idiosyncrasies of HTTP4s or Akka HTTP).
I'm trying to create filters for a search on an Android app where a specific field in Algolia must exactly match the given String in order to come up as a hit. For example if Algolia has a field like "foo" and I only want to return hits where "foo" is equal to "bar", then I would expect that I would have to use a line of code like this:
query.setFilters("foo: \"bar\"");
Any guesses as to why this isn't working like I see in the examples or how to do so?
Ah, I thought that attributesForFaceting was done by setting what was searchable or not. It was on a different page within the dashboard than I was previously using. Thanks #pixelastic.
I read this article and have some problems trying to follow the examples. The following is one of the examples given in that article. The first parameter in the object filter is virtualGuests. This object filter can be used in api https://api.softlayer.com/rest/v3/SoftLayer_Account/VirtualGuests.
object_filter = {
'virtualGuests': {
'datacenter': {
'name': {'operation': 'dal05'}
}
}
}
I want to use the object filter in other api methods, like SoftLayer_Account/getBlockDeviceTemplateGroups for example. My question is how to get/set the first parameter like virtualGuests? I tried several times but failed.
Try to follow these recomendations: Getting first parameter through Service Datatype or How to define the first parameter as simple way?
Getting first parameter through Service Datatype
You are trying to get
SoftLayer_Account::getBlockDeviceTemplateGroups
As you see, you are using SoftLayer_Account service, you need to open its datatype from this service:
You can go here:
http://sldn.softlayer.com/reference/services/SoftLayer_Account and
click on "datatypes" label/option
Or go directly here:
SoftLayer_Account
So, you need to start here, the method that you are using is getBlockDeviceTemplateGroups, if you want to get this information in the datatypes, you should skip the word "get" and looking for "BlockDeviceTemplateGroups" property, so you will have the correct parameter that you need to set at first.
How to define the first parameter as simple way?
If you notice, the only changes were: skip "get" word from the method, in this case is "getBlockDeviceTemplateGroups", so it will be:
"BlockDeviceTemplateGroups"
The next step should be set the first char in lowercase like:
"blockDeviceTemplateGroups"
So, it should be the filter:
object_filter = {
'blockDeviceTemplateGroups': {
'datacenter': {
'name': {'operation': 'dal05'}
}
}
}
References:
Object Filters
Going Further with the SoftLayer API Python Client - Part
1
I have a form where a field name is the same as one of the method/url parameters on the submit, say someInt. I.e. my form has #(dummyForm:Form[Dummy], someInt:Int) and dummyForm has a field "someInt" -> number and the controller is defined as def submit(someInt:Int) =.... Sample code here.
Let's say I submit the form with dummy.someInt value 222 and url parameter 555, I find the following:
request.body.asFormUrlEncoded shows one someInt, namely the value entered in the input field: (someInt,ArrayBuffer(222))
bindFromRequest, however somehow binds the form value to the url parameter value, 555 in this case
Is this expected behaviour? I would have thought bindFromRequest would be able to differentiate between the two? Is there a preferred way to prevent this type of conflict (besides having different names)?
(There is a workaround in this case. Instead of using the parameterless version of bindFromRequest, it seems to work as desired if you explicitly specify the asFormUrlEncoded set of values, i.e. bindFromRequest(request.body.asFormUrlEncoded.getOrElse(Map())). I am using Scala - have not tried to replicate in Java.)
In the bindFromRequest function, request.queryString is explicitly append to the list of values.
Using Watir Webdriver, I wanted to have a helper that would check for any element with given id. I may not know what type it is ( button or link or text). Can I just do
browser.Element(:id, id).exists
All of the examples i've found on google check against a specific element type, as in
browser.button(:id," ").exits
If there is a way, please share the syntax.
In Watir-Webdriver, I would use something like this:
browser.element(class: 'post-tag').exists?
which would find the watir-webdriver tag on this page and report that it exists. Note that I used the 1.9 syntax instead of the alternative syntaxes of:
browser.element(:class => 'post-tag').exists?
or
browser.element(:class, 'post-tag').exists?
As Dave points out, there is #element method. (You were wrong just in capitalization, it is not #Element.)
Since you are asking about accessing it using id attribute, try this:
browser.element(:id => id)
I've never gotten .exists? to work right on it's own.
What I've had to use in these cases has been to explicitly validate the "exist?"... like:
cf_checbox = #browser.text_field(:id=>'continue-ring', :value=>true).exists?
assert( cf_description == true)
without that explicit assertion, I would always get a "true" even when the value didn't exist.