Project

General

Profile

About

Velocity services are external services (generally deployed as a war on the Servoy server or any other Servlet container) than can be leveraged by Velocity.
These are specialized web services, that are meant to be running on the server-side, and some services might have some special server requirements (OS/Java version/extra software installed).

Services can also be any REST services out there, provided that they return proper JSON or XML, they can be anywhere and you can invoke them straight from Servoy, only dealing with simple JavaScript objects that you know of.

Declaring new services

The configuration of a service is made by declaring a few objects properties in the Velocity config.json file.
The services need to be declared inside a solution object, in the services object property, like this:

solution: {
   ...
   services: {
      officeConversion: {
         url: "office/convert",
         method: "post",
         processType: "server",
         params: {
            inPath: "Path",
            outPath: "[Path]" 
         },
         returns: {
            file: "Path" 
         }
      },
      anotherService: {
         ...
      }
   },
   ...
}

Where "officeConversion" is the name of the service (a unique identifier that you will need when invoking a service from Velocity).

The JSON object defining a service has some mandatory parameters, and some optionals (with defaults).

  • url: the URL of the service (mandatory), relative to the Servoy server if the service is deployed in /application_server/server/webapps/, or a full URL, like: "http://www.yourserver.com/office/convert" - usually the URL contains the 'context' of the service (the war name - minus the extension), and the path of the servlet that will respond to the call - this will be different for each service. Note: the url can contain Velocity variables, in which case the passed parameters will be used to fill them. This allows to call REST services where parameters are passed in the URL like: http://aservice.com/service/$category/$id
  • method: can be one "post"|"get"|"put"|"delete"|"options" ("header" doesn't return anything in the body of the response so it is not a proper VERB to use for this purpose, and "trace" is not activated by default on many servlet container). Default is "post"
  • processType: can be one of "server"|"client"|"post"|"pre", defines how the service is supposed to be called, either from a server-side or client-side invocation, or transparently inside the Velocity process, "pre" being when a request is received, and "post" being when a response is generated. Default is "server" ("pre" and "post" not yet implemented in v2.2.0).
  • params: an object declaring the expected parameters (will depend on the service), no default. Some service might not need parameters, so this can also be ignored. Note that some parameters can be declared as optional by enclosing them in square brackets, so option: "[String]" will define an optional parameter named 'option' of type String. Optional parameters will not be enforced by the service invocation, while other parameters will be checked (not null and of the declared type) before the service invocation.
  • returns: an object declaring the expected parameters in the object that will be received in callback from an invocation of the service. Will also receive an optional parameter (not to be defined, which is "exception" that will contain any exception that the invocation could have thrown.
  • route: will be used for 'pre' and 'post' processType, if a request match that route then Velocity will attempt invoking the service during the request or response cycle - optional, no default.
  • insertAs: the alias of the property that will be used to insert the response from the service (when processType is 'pre' or 'post') in the request parameters or the response contextObject.
  • authentication: "none"|"basic"|"form" defines if authentication is needed by the service, default = 'none' - "form" not supported for now.
  • preemptive: boolean, some services requires preemptive authentication, setting this flag to true will do that, default is false
  • defaultUser: the default user that will be impersonated during the call to the service, the value should be one of the declared users in users.properties, no default.
  • userParam: the user parameter that will contain the value of the login to use when calling the service, no default.
  • pass[word]Param: the password parameter that will contain the value of the password to use when calling the service, no default.
  • workspaceParam: the workspace parameter that will contain the value of the workspace to use when calling the service for NT authentication
  • domainParam: the domain parameter that will contain the value of the domain to use when calling the service for NT authentication
  • headers: an object, with property/values to be used to set the header of the service invocation, no default. Headers values can contain Velocity variables, in which case the passed parameters will be used to fill them.
  • entityFormat: can be one of "json"|"xml"|"none" if a service is waiting for parameters to be enclosed as JSON or XML in the body of a POST or PUT request, otherwise the parameters will be send as a regular POST or PUT as form (url-encoded) body (which is the default).
  • returnErrorBody: (since Velocity 3.5.34) if true, will attempt to retrieve the body of the response even if the status is an error code, wrapping it in the default value (insertAs - "data" if not set) - default is false.
  • deserializeDate: boolean, by default Velocity will attempt to parse date strings to create a Date object. You can set this to false to prevent this behavior. If you want all your services to return plain strings instead of Date objects, you can also set this property at the solution level in your solution properties in config.json

Service invocation

If you define a service to be "pre" or "post" there will be no need to call it directly. Velocity will automatically check the received parameters and call the service and add the response of that service to the incoming request or outgoing response.

If you define a service to be "client" or "server", this will allow you to call it from a new method in the Velocity plugins:

[var result =] plugins.Velocity.invokeService(serviceName, parametersObject, [callbackFunction]);

The serviceName will allow Velocity to retrieve all the parameters defined in config.json, to be able to use the service.
The parametersObject must match what has been defined in the "params" object in config.json (unless they have been declared as optional).
The callbackFunction will be called by the invoker thread with a result object containing the properties as defined in the 'returns' object in config.json (plus optional "exception" property, which will be an object with "message", "statusCode" and "stackTrace" properties).
If not provided the service will be called synchronously and return the result from the invokeService call.

NB: if you define a service processType to "client" this means that the client will need the CommonsComponent HttpClient libraries. For web/headless clients, this is not a problem since these libs are available on the server. For Smart client though they need to be downloaded on the client. To help you with that, you will find a "ForClientServices" folder in the Velocity distribution zip that contains a commons.jnlp file for 5.2.x and 6.x+ Servoy versions (this is because the httpclient.jar and httpcore.jar are not located at the same place in 5.2.x and 6.x+).
So all you will need to do if you want to use 'client' processType is to place the correct commons.jnlp for you Servoy version into /plugins/velocityreport/ (overwrite the standard one).

Available services

0. Calling existing services

Of course, you can define public services with a well defined API, provided that they are returning JSON or XML.
Here are few examples of web services configuration in config.json:

SolutionName: {
    services: {
        utcTime: {
            url: "http://www.timeapi.org/utc/now.json",
            method: "get",
            processType: "client",
            returns: { 
                dateString: "String" 
            }
        },
        urlLongifier: {
            url: "http://www.longr.us/",
            method: "post",
            processType: "client",
            params: {
                url: "String" 
            },
            returns: {
                orig_url: "String",
                long_url: "String",
                short_url: "String" 
            },
            headers: {
                Accept: "application/json" 
            }
        },
        numberTrivia: {
            url: "http://numbersapi.com/$num?json",
            method: "get",
            params: {
                num: "Number" 
            },
            returns: {
                text: "String",
                found: "Boolean",
                number: "Number",
                type: "String",
                date: "[String]",
                year: "[Integer]" 
            }
        }
    }
}

Have a look in the Forums for more samples. You can post also post your own!

1. Office Conversion service

The Office Conversion service is using Office in the background on a server to convert Office documents (doc/docx, xls/xlsx, ppt/pptx) into PDF files.
The service need Office installed on a Windows server, since it is leveraging Office DCOM objects (using the Jacob library). Since DCOM is only available on Windows, this service will not work on a Mac OS X or Linux server. However, the Servoy server (and the clients) making use of this server can well be hosted on a Mac OS X, Windows or Linux server indifferently. All the calls to the service are done using plain http and REST, so the only port that needs to be opened on the Windows server will an http port (80 by default, but basically any port that your app server is configured on).

Available as 'office.war' in the Files section, you can deploy it in /application_server/webapps or any Java App server (Servlet container) on a Windows server.

The configuration of the OfficeConversion service should be as such:

  • url: should be "office/convert" if the war is deployed in /application_server/server/webapps/ or "http://yourServerDomainNameOrIP[:optionalPort]/office/convert" if deployed on another servlet container
  • method: "post"|"get"|"put"|"delete"|"options" can be used indifferently (although "delete" and "options" don't make much sense)
  • processType: "server"|"client" can be used for now
  • params: { inPath: "Path", outPath: "[Path]" } - "Path" is a generic identifier meaning "String" (a path), "File" (java.io.File) or "JSFile"
  • returns: { file: "Path" } (will be received as a JSFile in Servoy)

X. More to come...

There will be more services to come, some ideas I already have are:
  • Lucene/Solr indexing service (leveraging the SmartDoc plugin inside Velocity)
  • Rules service (using Drools/Drools-Planner on the server-side)
  • OAuth authentication service
  • JavaFX service for alternate charts

Please open a Feature Request if you have an idea for a service you would need.
And remember that you can always Incentify your Feature Request if you want that to be put on top of my priority list.