For other clients, a "REST level 0", or RPC-like interface is available, using JSON encoded strings for passing parameters and receiving results from services. Each service responds to POST requests to the following URL http[s]://cyclos.url/[network/]web-rpc/<short-service-name>, where the short-service-name is the service with the first letter as lowercase. So, for example, https://my.cyclos.instance.com/network/web-rpc/accountService is a valid URL, being mapped to AccountService. Other URLs are also supported, as described in Section 3.4.1, “URL mapping”
For authentication, the username and password should be passed as a HTTP header using the standard basic authentication – a header like: "Authentication: Basic <Base64-encoded form of username:password>". Actually, username or other principal type (user identification method) will be chosen according to the configuration. If the configuration allows more than one principal type, it is possible to specify a value in the "Principal-Type" header, which must match the principal type internal name. Alternatively, it is possible to login the user via LoginService and pass the obtained session token in the "Session-Token" header. A third access option is to use an access client token. In this case, the header "Authorization: Bearer <access client token>" is used to specify the access client token. Alternatively, the header Access-Client-Token can be passed in with the token as value.
To specify a channel, pass the header "Channel: <channel internal name>". If no channel is passed, Web Services is assumed.
When the URL is specified up to the service, as stated above, the request body must be a JSON object with the ‘operation’ and ‘params’ properties, where operation is the method name, and params is either an array with parameters, or optionally the parameter if the method has a single parameter (without the array) or even omitted if the method have no parameters. For objects, the parameters are expected to be the same as the Java counterparts (see the JavaDocs for a reference on the available properties for each object).
As result, if the request was successful (http status code is 200), an object with a single property called result will be returned. The object has the same structure as the object returned by the service method, or is a string, boolean or number for simple types. Requests which resulted in error (status code distinct than 200) will have the following structure:
errorCode: A string generated from the exception java class name. The unqualified class name has the Exception suffix removed, and is transformed to all uppercase, separated by underlines. So, for example, for org.cyclos.model.ValidationException, the error code is VALIDATION; for org.cyclos.model.banking.InsufficientBalanceException, the error code is INSUFFICIENT_BALANCE, and so on.
Any other properties (public getters) the thrown exception has will also be mapped as a property here, for example, org.cyclos.model.ValidationException holds a property called validation which contains an object representing a org.cyclos.utils.ValidationResult.
Besides using the URL pointing to the service, and have the POST body as a JSON, selecting the operation and the parameters, it is also possible to choose the operation in the URL itself, as a subpath in the URL. For example, https://my.cyclos.instance.com/network/web-rpc/userService/search already maps to the search operation. The POST body, then, is expected to be just the JSON for the parameters, with the same rules as explained above: if is a single parameter, the body can be the JSON value directly, and if no parameters, the POST body can be empty.
Additionally, the service methods that are readonly can be invoked by GET requests. In this case, the parameter can be passed using 2 forms:
Finally, services are mapped to other 2 URLs besides <name>Service: one without the 'Service' suffix, and another one, pluralized. Also, if an operation doesn't match, it will be attempted by prepending 'get' with the first letter capitalized. This will allow shorter urls on calls, like:
All output objects, when converted to JSON, will have a property called class, which represents the fully-qualified Java class name of the source object. Most clients can just ignore the result. However, when sending requests to classes that expect a polymorphic object, the server needs to know which subclass the passed object represents. In those cases, passing the class property, with the fully qualified Java class name is required. An example is the AdService. When saving an advertisement, it could either be a simple advertisement (AdvertisementDTO) or a webshop advertisement (AdWebShopDTO). In this case, a class property with the fully qualified class name is required. Note, however, that in most cases, the class information is not needed.
Whenever a subclass of EntityVO is needed, numbers or strings are also accepted (besides objects). Numbers always represent the vo identifier (id property). Strings can either be id when they are numeric, or can represent one of the following cases:
If the value is supposed to be a number handled as user principal (for example, a mobile phone) or account number, it must be prefixed with a single quote. For example, to represent a phone number as string, the following is accepted: '5187653456. If not prefixed, it would be interpreted as user id instead. The single quote prefix is the same as Excel / LibreOffice use to represent a number as string.
Other points to note with JSON handling:
Assuming that the authentication header is correctly passed, the following request can be performed to search for users: POST https://my.cyclos.instance.com/network/web-rpc/userService with the following body:
{
"operation": "search",
"params": {
"keywords": "user",
"groups": "consumers",
"pageSize": 5
}
}
The resulting JSON will be something like:
{
"result": {
"currentPage": "0",
"pageSize": "40",
"totalCount": "2",
"pageItems": [
{
"class": "org.cyclos.model.users.users.UserDetailedVO",
"id": "-2717327251475675143",
"display": "Consumer 1",
"shortDisplay": "c1"
},
{
"class": "org.cyclos.model.users.users.UserDetailedVO",
"id": "-2717467988964030471",
"display": "Consumer 3",
"shortDisplay": "c3"
}
]
}
}Note the params "groups" property of the input query is a collection of BasicGroupVO. It is being passed the string "consumers", which is matched to the group internal name.
The above request is equivalent to a POST to https://my.cyclos.instance.com/network/web-rpc/users/search (using the plural name) with the following body:
{
"keywords": "user",
"groups": "consumers",
"pageSize": 5
}Note only the parameters part is passed. If the service method would require multiple parameters, the body should be a JSON array. If a single string, the string should be quoted, just like in JSON.
Also, the above request is equivalent to a GET to https://my.cyclos.instance.com/network/web-rpc/user/search?keywords=user&groups=consumers&pageSize=5 (singular name). Only methods which take a single parameter object can use query parameters.