MGNLPER-19 - Getting issue details... STATUS
Introduction
Periscope currently has various SearchResultSuppliers however all of them are bound to JCR. One should be able to define a SearchResultSupplier which brings results outside of Magnolia e.g. our documentation can be searchable within Periscope.
The usual way of doing this is to fetch/search this information via REST, hence we should be able to create generic REST based SearchResultSupplier for Periscope.
Problem statement
Providing capabilities as such is not very straightforward due to the fact that JSON response from REST based service will not be in the same format and/or same keys.
For instance:
{ "results": [ { "title": "foo" }, { "url": "fooURL" } ] }
{ "myFunkyResults": [ { "myDifferentTitle": "foo", "myDifferentURL": "fooURL" } ] }
Proposed Solution (Periscope specific)
In the scope of Periscope, we only need to display results to the user and in order to do that we need a title and an URL that we will navigate to when user selects that particular result.
That means user only need to specify a title and navigation url via some kind of configuration and we will simply try to fetch that information in the SearchResultSupplier.
JsonPath
https://github.com/json-path/JsonPath
http://goessner.net/articles/JsonPath/
With JsonPath, one can easily point to particular values in any JSON result. That being said configuration as such is sufficient to configure a RestSearchResultSupplier.
This is an example of JSON response we get when we query confluence, it's clear that we need to combine 'title's and 'webui's to generate results.
{ "results":[ { "id":"156405429", "type":"page", "status":"current", "title":"Periscope", "restrictions":{ }, "_links":{ "webui":"/display/DEV/Periscope", "tinyui":"/x/tY5SCQ", "self":"https://wiki.magnolia-cms.com/rest/api/content/156405429" }, "_expandable":{ "container":"", "metadata":"", "extensions":"", "operations":"", "children":"", "history":"/rest/api/content/156405429/history", "ancestors":"", "body":"", "version":"", "descendants":"", "space":"/rest/api/space/DEV" } } ], "start":0, "limit":25, "size":1, "_links":{ "self":"https://wiki.magnolia-cms.com/rest/api/content/search?cql=(type=page%20AND%20(title~%22Periscope*%22%20OR%20text~%22Periscope*%22))", "base":"https://wiki.magnolia-cms.com", "context":"" } }
With that in mind, one has to define titleJsonPath and navigationURLJsonPath according to the JSON result above.
// This one for the JSON snippet above requestURL: "https://documentation.magnolia-cms.com/rest/api/content/search?cql=(type=page AND (title~\"%1$s*\" OR text~\"%1$s*\"))" navigationBaseURL: "https://documentation.magnolia-cms.com" titleJsonPath: $..title navigationURLJsonPath: $..webui class: info.magnolia.periscope.search.rest.RestSearchResultSupplierDefinition // Working solution for wikipedia as an general example requestURL: "https://en.wikipedia.org/w/api.php?format=json&action=query&titles=%s&redirects" navigationBaseURL: "https://en.wikipedia.org/?curid=%s" titleJsonPath: $..title navigationURLJsonPath: $..pageid class: info.magnolia.periscope.search.rest.RestSearchResultSupplierDefinition
This is how one defines where the specific values will be found, in this example we have '$..title' which translates into all title values which are two levels under the root and same as the '$..webui'.
One has to specific a 'baseURL' and an additional 'URL', those are needed to make the REST request from backend as well as appending the found 'navigationURL' from the JSON result.
Upon search request we append baseURL with URL and do the REST request and the response is parsed with JsonPath library and obtained 'title' and 'navigationURL' is utilised to generate results.
That being said, baseURL is appended with the parsed 'navigationURL' which is utilised to redirect the user when a particular response has been selected.
Getting results in the backend is very straightforward too:
ReadContext context = JsonPath.parse(resultJson); List<String> read = context.read(definition.getTitleJsonPath()); List<String> read2 = context.read(definition.getNavigationURLJsonPath());