Automatic version update
This is an application for adding a fews helpful features to your rest services :
Some basic features required in most rest services.
Include jsonfilter inc file to your REST services class and apply $$$JSFilter(json) macro to a %DynamicObject Or %DynamicArray.
Include jsonfilter
Class Isc.JSONFiltering.Rest.FilteringDemo Extends %CSP.REST
{Parameter CONTENTTYPE = {..#CONTENTTYPEJSON};
XData UrlMap [ XMLNamespace = "http://www.intersystems.com/urlmap" ]
{
<Routes>
<Route Url="/demoresponse" Method="GET" Call="demoJsonResponse" Cors="true"/>
</Routes>
}ClassMethod demoJsonResponse() As %DynamicObject
{
Set json = [{"name":"John", "city":"Charleroi"},{"name":"Tony","city":"Charleroi"},{"name":"Lorenzo","city":"Namur"},{"name":"Matteo","city":"Namur"},{"name":"Alessio","city":"Namur"},{"name":"Alain","city":"Bruges"},{"name":"Aurélien","city":"Mons"}]Write $$$JSFilter(json).%ToJSON() Return $$$OK
}
}
$$$JSFilter(json) macro apply all json filter features automatically.
It’s an interesting feature for your client app that need to reduce the bandwith usage.
Property filter is a simple dynamic array which contain the list of properties.
You can use dot as a separator to specify a nested property.
Set json = {"name" : { "first" : "Edith", "last" : "Scott"}, "friends" : [{"name": "Perkins Cruz", "id":"1", "address":[{"city":"London","street":"no value"},{"city":"Roma","street":"no value"}]}]}
Set propertyFilter = ["name.first","friends.name","friends.address.city"]
Set filteredJSON = $$$JSFilterProperty(json,propertyFilter)
Write filteredJSON.%ToJSON()
For testing purpose in an Iris terminal, you can use a classmethod call instead of $$$JSFilterProperty macro.
Set filteredJSON = ##class(Isc.JSONFiltering.Services.FilteringServices).filterJSON(json,propertyFilter)
We recommand to always use macro in your app. It would be useful if a class is renamed in a further version.
Result
{"name":{"first":"Edith"},"friends":[{"name":"Perkins Cruz","address":[{"city":"London"},{"city":"Roma"}]}]}
Seach Criteria work with dynamic array parameters following this syntax [[“property”,“value”,“operator”],[“property2”,“value2”,“operator2”],…].
It’s the same structure of restriction predicate syntax used with %FindDocuments (%DocDB.Database).
Set json = [{"name":"John", "city":"Charleroi"},{"name":"Tony","city":"Charleroi"},{"name":"Lorenzo","city":"Namur"},{"name":"Matteo","city":"Namur"},{"name":"Alessio","city":"Namur"},{"name":"Alain","city":"Bruges"},{"name":"Aurélien","city":"Mons"}]
Set searchCriteria = [["city","Namur","="]]
Set result = $$$JSFilterCriteria(json,searchCriteria)
Write !,result.%ToJSON()
You can use the folowing classmethod instead of $$$JSFilterCriteria for testing purpose :
Set result = ##class(Isc.JSONFiltering.Services.FilteringServices).searchCriteria(json,searchCriteria)
Result
[{"name":"Lorenzo","city":"Namur"},{"name":"Matteo","city":"Namur"},{"name":"Alessio","city":"Namur"}]
Sort parameter is a dynamic array with two items.
The first item is the “sort by” property and the second item is the order “desc” or “asc”.
If the second item is missing, “desc” is selected by default.
The used property to sort can be a nested property, but not a list or a property in a nested list of object.
Set json = [{"name":"John", "city":"Charleroi"},{"name":"Tony","city":"Charleroi"},{"name":"Lorenzo","city":"Namur"},{"name":"Matteo","city":"Namur"},{"name":"Alessio","city":"Namur"},{"name":"Alain","city":"Bruges"},{"name":"Aurélien","city":"Mons"}]
Set sort = ["city","desc"]
Set result = $$$JSFilterSort(json,sort)
Write !,result.%ToJSON()
You can use the folowing classmethod instead of $$$JSFilterSort for testing purpose :
Set result = ##class(Isc.JSONFiltering.Services.FilteringServices).sort(json,sort)
Result
[{"name":"Alain","city":"Bruges"},{"name":"John","city":"Charleroi"},{"name":"Tony","city":"Charleroi"},{"name":"Aurélien","city":"Mons"},{"name":"Lorenzo","city":"Namur"},{"name":"Matteo","city":"Namur"},{"name":"Alessio","city":"Namur"}]
Maximum number of records to return.
Set json = [{"name":"John", "city":"Charleroi"},{"name":"Tony","city":"Charleroi"},{"name":"Lorenzo","city":"Namur"},{"name":"Matteo","city":"Namur"},{"name":"Alessio","city":"Namur"},{"name":"Alain","city":"Bruges"},{"name":"Aurélien","city":"Mons"}]
Set limit = 3
Set result = $$$JSFilterLimit(json,limit)
Write !,result.%ToJSON()
You can use the folowing classmethod instead of $$$JSFilterLimit for testing purpose :
Set result = ##class(Isc.JSONFiltering.Services.FilteringServices).limitResult(json,limit)
Result
[{"name":"John","city":"Charleroi"},{"name":"Tony","city":"Charleroi"},{"name":"Lorenzo","city":"Namur"}]
Client REST app can use these features just by adding request parameters.
See the following tab:
Feature | Request Parameter Name | Example Value |
---|---|---|
Property filtering | jsflt | name,friends[name,address[city]] |
Searching | jsfltsc | ["name.first","Edith","="] |
Sorting | jsfltsrt | name.first,desc |
Limit | jsfltlmt | 5 |
There is no mandatory query parameter.
Backend application retrieve filter data provided by client app and process it with $$$JSFilter macro.
In the following example, the macro return a filtered %DynamicObject or %DynamicArray.
json is a %DynamicObject or %DynamicArray to filter.
Set filteredJSON = $$$JSFilter(json)
The macro $$$JSFilter retrieve all filters data in %request.Data and call the appropriate process.
Available macro :
Feature | Macro | Classmethod |
---|---|---|
Property filtering | $$$JSFilterProperty(json,propertyFilter) | ##class(Isc.JSONFiltering.Services.FilteringServices).filterJSON |
Searching | $$$JSFilterCriteria(json,searchCriteria) | ##class(Isc.JSONFiltering.Services.FilteringServices).searchCriteria |
Sorting | $$$JSFilterSort(json,sort) | ##class(Isc.JSONFiltering.Services.FilteringServices).sort |
Limit | $$$JSFilterLimit(json,limit) | ##class(Isc.JSONFiltering.Services.FilteringServices).limitResult |
All By %Request | $$$JSFilter(json) | ##class(Isc.JSONFiltering.Services.FilteringServices).applyAllFilterParameters |
Remember to use macros in your app instead of classmethod.
Make sure you have git and Docker desktop installed.
Clone/git pull the repo into any local directory
$ git clone https://github.com/lscalese/isc-rest-json-filter.git
Open the terminal in this directory and run:
$ docker-compose build
$ docker-compose up -d
Open an Iris Terminal
zpm
install json-filter
install swagger-ui
Not available with zpm install.
Open IRIS terminal:
$ docker-compose exec iris irissession iris
USER>zn "IRISAPP"
IRISAPP>Set ^UnitTestRoot = "/opt/irisapp/tests/"
IRISAPP>Do ##class(%UnitTest.Manager).RunTest(,"/nodelete")
There is Open API Specification 2.0.
Swagger-UI can be used:
http://localhost:52773/csp/jsonfilterrest/_spec
in search barBasic test page : http://localhost:52773/csp/jsonfilter/Isc.JSONFiltering.Rest.FilteringCSPDemo.cls
This page is now useless with swagger-ui module.
For testing purpose a Postman collection is available with some filter examples.
This project is licensed under the MIT License - see the https://github.com/lscalese/isc-rest-json-filter/blob/master/LICENSE file for details.
This repository is ready to code in VSCode with ObjectScript plugin.
Install VSCode, Docker and ObjectScript plugin and open the folder in VSCode.
Open /src/cls/PackageSample/ObjectScript.cls class and try to make changes - it will be compiled in running IRIS docker container.
Feel free to delete PackageSample folder and place your ObjectScript classes in a form
/src/Package/Classname.cls
Read more about folder setup for InterSystems ObjectScript
The script in Installer.cls will import everything you place under /src into IRIS.
The simplest dockerfile which starts IRIS and imports Installer.cls and then runs the Installer.setup method, which creates IRISAPP Namespace and imports ObjectScript code from /src folder into it.
Use the related docker-compose.yml to easily setup additional parametes like port number and where you map keys and host folders.
Use .env/ file to adjust the dockerfile being used in docker-compose.
Settings file to let you immedietly code in VSCode with VSCode ObjectScript plugin)
Config file if you want to debug with VSCode ObjectScript
Read about all the files in this artilce
If you are interested by these features, you will be probably interested by GraphQL approach.
An Objectscript implementation by Gevorg Arutiunian is available here.