Search w/ Dynamic Options via collection+json
By: Johnathon Wright on: February 11, 2014
We're searching for people using 'location', 'radius', and 'specialization' fields. Since collection+JSON apparently doesn't provide a mechanism for delivering options like the HTML tag <option>
, we've forked the Ruby gem for collection+JSON and added that feature:
Find our repo with details at GitHub
Given I am an anonymous user
When I go to the search page
and I enter my postal code
And I select a specialty
And I submit the form
Then I should be on the results page
And I should see my criteria in an updatable form
And I should see the results
And another important scenario:
Given I am on the result page
Then I should see my search criteria
And I should see a list of the cities where the resulting people are located
And I should be able to filter by those cities.
Because of the second scenario, we need to pass back not just the results, but also the inquiry details, which will include our criteria and city list. Collection+JSON is implicitly limited to one kind of result per response, ie you can't have a collection with both an inquiry item AND a result item, since there is no rel-tag in the item. And even if there were a rel-tag... having two kinds of data mixed up together would be a giant mess.
So our challenge is to present meta-data about the search, available filters, and the results.
Our modified collection+json includes a 'related' collection which could hold the inquiry information. However, we need the expressiveness of the 'template' section for this task. So the 'items' collection links to the inquiry that has been submitted. items[0].links gives you a link to the results.
Our modified collection+JSON schema includes 'options' in the template/query section. This is the perfect mechanism for sending back the list of cities.
But that still leaves the problem of meta-data.... how many results were there? What page are we on? etc.
{
"collection": {
"href": "/inquiries/4.json",
"items": [
{
"href": "/inquiries/4.json",
"data": [
{
"name": "location",
"value": "70508"
},
{
"name": "radius"
},
{
"name": "specialization_id",
"value": "12"
}
],
"links": [
{
"href": "/inquiries/4/results.json",
"rel": "specialist_search_results_resource"
}
]
}
],
"template": {
"data": [
{
"name": "inquiry[location]",
"prompt": "Location",
"value": "70508"
},
{
"name": "inquiry[search_area]",
"prompt": "Where are you looking?",
"options": [
{
"value": "local",
"prompt": "Close to Me"
},
{
"value": "us",
"prompt": "Anywhere in the US"
},
{
"value": "global",
"prompt": "Anywhere in the world."
}
]
},
{
"name": "inquiry[specialization_id]",
"prompt": "Category",
"value": 12,
"options": [
{
"value": 1,
"prompt": "Rails"
},
{
"value": 2,
"prompt": "Ruby"
},
{
"value": 3,
"prompt": "AngularJS"
},
{
"value": 4,
"prompt": "jQuery"
}
]
}
]
}
}
}
In order to do this, we will need to have two kinds of locations... a home location and a cities collection. Our cities are actually CBSAs, so I'll call them Areas.
Since no values selected would necessarily mean no results, we'll assume a null value means all values. That way, the initial submit will come back something like this:
{
"name": "inquiry[home]",
"prompt": "I live in",
"value": "70508",
},
{
"name": "inquiry[areas]",
"prompt": "Locations",
"value": [ 10100, 31080, 31060, 35440 ],
"options": [
{
"value": 10100,
"prompt": "Aberdeen, SD"
},
{
"value": 31080,
"prompt": "Los Angeles"
},
{
"value": 31060,
"prompt": "Los Alamos, NM"
},
{
"value": 35440,
"prompt": "Newport, OR"
}
]
}
Update
We've added a 'meta' element after some discussion