Introduction
Kinvey Business Logic is a robust node.js code execution runtime that allows you to customize the behavior of requests to your backend by providing a means to implement server-side business logic. However, it is sometimes desireable to run business logic on an external application server in languages other than node.js. For this purpose, Kinvey provides a means of creating external business logic.
Core Concepts
The External Business Logic architecture is defined as an HTTP RPC API that can be implemented by any application server and allows you to execute business logic tasks from that server via your Kinvey backend. Externa Business Logic can be developed in any language, such as node.js
, Java
, and C#
, as long as it adheres to the defined RPC interface. The service receives RPC requests from the Kinvey Cloud Service (KCS), executes logic based on those requests, and transforms the results into JSON to be sent in the response.
External Business Logic in JAVA
To run Business Logic on a Java application server, you need to create a JAVA HTTP service that uses our open-source Java SDK.
Setup
To start from scratch you need to know the following details.
Create an Application Project
Using Eclipse, IntelliJ, or your Java EE IDE of choice, create a new project and import the Kinvey Business Logic SDK. The SDK relies on Jersey to provide REST capabilities for receiving Business Logic requests from the Kinvey Cloud Service (KCS).
Create a Jersey project with a class for each collection or custom endpoint for which you want to implement Business Logic. Alternatively, you can utilize one of the sample projects included in the SDK as a template. The quickstart project contains a bare-bones project for one endpoint.
Modify the Web.xml file
Modify the web.xml file for your project to include the SDK as a dependency for authentication by adding com.kinvey.business_logic.interceptors.KinveyAuthInterceptor
to the ContainerRequestFilters
init parameter. The resulting parameter should look like:
<init-param>
<param-name>com.sun.jersey.spi.container.ContainerRequestFilters</param-name>
<param-value>com.sun.jersey.api.container.filter.LoggingFilter;com.kinvey.business_logic.interceptors.KinveyAuthInterceptor</param-value>
</init-param>
The Kinvey SDK uses Jackson for JSON parsing/marshalling. To include this in the web servlet, add a reference to Jackson to the packages
initialization parameter. Additionally, you should add the package containing your BL classes to this parameter as well.
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>com.fasterxml.jackson.jaxrs;com.myApp.package</param-value>
</init-param>
You can optionally add an ExceptionMapper
provider for handling all exceptions to the packages
init parameter. Adding this mapper will handle all uncaught exceptions and return them as a valid response to the Kinvey client. If this init parameter is not added, you must provide your own exception handling. Adding this mapper to the above produces the following:
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>com.fasterxml.jackson.jaxrs;com.myApp.package;com.kinvey.business_logic.providers</param-value>
</init-param>
Setting up your Class Files
Next, in your REST class files, annotate the class with a @Path
reference to the collection or endpoint that this class will provide business logic for, and add the @Consumes
and @Produces
annotations as follows:
@Path("/myEntity/{command}")
@Consumes("application/json")
@Produces("application/json")
The External BL SDK uses a single POST entry point for all requests to a single collection (or endpoint). This method can be named anything, but must be annotated with @POST
, return a CommandResponse
object, and contain a method signature of @PathParam("command") String command, Request<CollectionArguments> request
For example:
@POST
public CommandResponse myBLRequest(@PathParam("command") String command, Request<CollectionArguments> request){
CommandResponse myResponse = CommandResponse.initialize(); // do something
// set myResponse values
return myResponse;
}
Security
To ensure that valid requests to your Business Logic code are only coming from the Kinvey Cloud Service, appId and masterSecret credentials are included in the auth header of all requests coming from Kinvey. To validate against these credentials, you need to create a Listener class that listens to these credentials using the KinveyAuthCredentials
class. To do this, create a class that implements ServletContextListener
. Implement the contextInitialized method, get an instance of KinveyAuthCredentials
, and set your appId and master secret.
public class AppConfiguration implements ServletContextListener {
private final static Logger LOGGER = Logger.getLogger(AppConfiguration.class.getName());
@Override
public void contextInitialized(ServletContextEvent sce) {
LOGGER.info("App is being configured.");
KinveyAuthCredentials auth = KinveyAuthCredentials.getInstance();
auth.setAppId(YOUR_APP_ID);
auth.setMasterSecret(YOUR_MASTER_SECRET);
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
//To change body of implemented methods use File | Settings | File Templates.
}
}
In your web.xml, add the class above as a listener under the <web-app>
tag.
<listener>
<listener-class>com.yourpackagename.AppConfiguration</listener-class>
</listener>
Building a custom BL Service
To build a BL Service in any language, an HTTP RPC service must be implemented to receive requests from the Kinvey Cloud Service. The API for external BL should implement POST to an endpoint for each data collection and hook that will be accessed via the Kinvey Cloud Service. The URL takes the format https://{base_url}/:collectionName/:hook
.
For each collection, six possible routes are enabled:
Route |
---|
/:collectionName/onPreFetch |
/:collectionName/onPostFetch |
/:collectionName/onPreSave |
/:collectionName/onPostSave |
/:collectionName/onPreDelete |
/:collectionName/onPostDelete |
For custom endpoints, :collectionName
is the endpoint name.
Route |
---|
/:endpointName/onRequest |
Request Parameters
External BL Requests contain the following properties in the Request Body, authenticated via Basic Auth with mastersecret
credentials:
Property | Description |
---|---|
arguments | The payload of the BL Task |
command | The command to be executed (hook type) |
kinveyAction | The method of the original request (e.g. POST, PUT) |
httpAction | The original HTTP Action (Fetch , Delete or Save ) |
The arguments
object contains the following properties:
Property | Description |
---|---|
appId | The ID of the app environment |
appMetadata | Metadata about the app enivornment |
targetFunction | The target function to execute |
requestId | The unique ID of the request |
collectionName | The collection or endpoint name |
hookType | The type of BL Hook |
request | The request object |
response | The response object |
The appMetadata
object contains:
Property | Description |
---|---|
appsecret | The app secret |
mastersecret | The app mastersecret |
pushService | Push configuration information |
API_version | The API version of the request |
name | The app name |
platform | The platform making the request (e.g. Android, Xamarin) |
url | The original URL of the request |
The request
object contains:
Property | Description |
---|---|
method | The HTTP Method (e.g. POST, PUT, GET) |
headers | Any HTTP Headers |
body | The body of the original request |
params | Query parameters of the original request |
username | The username of the user who made the request |
userId | The ID of the user who made the request |
entityId | The entityId (if present) of the entity the request was made against |
collectionName | The name of the collection |
The response
object contains:
Property | Description |
---|---|
status | The statuscode of the response |
headers | Response HTTP Headers |
body | The body of the response |
BL Response
Once your external service processes the BL code, a response must be sent. The response body should contain the request
and response
objects, and should set a status code. Additionally, a response
property complete
should be set. If the Kinvey request is to end immediately following the BL script (equivalent to response.complete()
in Kinvey Business Logic), The complete
property should be set to true
and a status code must be set.