Microapp and Spectrum Dataflow integration
This tutorial describes how to integrate a MicroApp with a Spectrum Dataflow. It is a simple HelloWorld application that performs a roundtrip from Buzzy to Spectrum and back. It takes as input a name string (iName) and returns Hello and the name string (oResponse).
User defined Spectrum web services
Spectrum provides a REST interface to web services. User-defined web services, which are those created in Enterprise Designer as Dataflows, support GET and POST methods. To integrate Buzzy with Spectrum dataflows use the REST interface with the POST method and JSON body. More information can be found in the Spectrum Web Services Guide.
Something to take note of, is the JSON Body. The first two elements are the InputStageName and InputDataType which are always “Input” and “Row”.
Another important note, is to make sure that the dataflow webservice option is set to allow POST with a JSON body:
Create Spectrum Dataflow – Part 1
The Spectrum Enterprise Designer is a visual tool for creating dataflows. More information can be found in the Dataflow Designers Guide. In this tutorial we will create a simple dataflow that accepts data from a web service call, processes the data, and returns a response. Since this dataflow is intended to be exposed as a service on the Spectrum server, it is a service dataflow.
- Start the Spectrum Enterprise Designer
- Create a new Dataflow that is a service
- Add an input stage
- In the input stage add the input fields:
- iName as a string
- rowID as a string
- Add a Transformer stage. In the Transformer stage Construct a field as
Hello ${iName}
. Save the field as oResponse. - Add an output stage. Output the field oResponse.
- Save the Dataflow as HelloBuzzy. Be sure the enable execution and set web service options for POST
Note: An optional Transformer can be added to the flow to enable debugging. This transform uses Groovy Script to output to the Spectrum log file. See Appendix B LogIt Custom Transform for an example.
Validate Spectrum Dataflow
To validate the web service HelloBuzzy, use a test application. For this example, we will use Postman. It can be downloaded from postman.com.
- Create a new Request
- Enter the URL for the REST service. For example:
http://m4800.local:8080/rest/HelloBuzzy/results.json
- Change method to POST
- Change authorization to Basic and add Spectrum username/password
- Enter the JSON body:
{ "Input": { "Row": [{ "rowID": "12345", "iName": "Will" }] } }
- Select
Send
. This should produce output like this:{ "Output" : [ { "oResponse" : "Hello Will", "user_fields" : [ ] } ] }
The following shows the example in Postman:
Create microapp
Buzzy allows you to create simple forms or complex reporting applications, with workflows and location intelligence. These apps and forms are known as Buzzes and are built using a comprehensive set of components. One of these components is the Application content known as a MicroApp that are mini-apps inside Buzzy - use these to build forms, manage data and add interactivity.
To create the HelloBuzzy application:
- Log into Buzzy server
- Create new Buzz using Blank Template
- Change Title to HelloBuzzy
- Publish Draft
- Add Content Application
- Select Submit and change Submit Form Display to Modal form
- Select Fields
- Add Text Field iName
- Add Text Field oResponse
- Select Advanced and then Rules
- Add Rule for Element [Row]
- Select Condition submitted (created)
- Select Action and Send JSON
- Enter API URI
- Select Type POST
- Enter User and Password
- Enter JSON Body:
{ "Input": { "Row": [{ "rowID": "{{{_id}}}", "iName": "{{{iName}}}" }] } }
- Select Add Rule
Create Spectrum Dataflow – Part 2
So far, we have created the Buzzy app to enter a name and dispatch a request to Spectrum to generate a response. We will now complete the HelloBuzzy Dataflow to respond to Buzzy. The response content is in JSON format and contains the MicroApp database row identifier and field data. The row contains all the information required to update the correct Buzz and MicroApp.
"rowID": "3af492b74ba6fbae97f36be3",
"rowData": {
"iName": "Will",
"oResponse": "Hello Will"
}
The Aggregator stage is used in the data flow to combine the row and field information into the correct data structure.
A custom transform is then used to send the update back to the Buzzy server. Appendix C: Send Custom Transform provides sample Groovy Script code. Note that server and user information will need to be changed for your specific installation.
Appendix A: Useful links
HelloBuzzy exported Data Flow: Text File
Precisely Spectrum Web Services Guide
Appendix B: LogIt Custom Transform
import org.codehaus.groovy.runtime.InvokerHelper
import org.springframework.web.client.RestTemplate
import java.io.IOException
import org.springframework.util.MultiValueMap
import org.springframework.util.LinkedMultiValueMap
import org.springframework.http.MediaType
import org.springframework.http.HttpEntity
import org.springframework.http.CacheControl
import org.springframework.http.ResponseEntity
import org.springframework.http.HttpHeaders
import org.springframework.http.HttpRequest
import org.springframework.http.client.ClientHttpRequestExecution
import org.springframework.http.client.ClientHttpRequestInterceptor
import org.springframework.http.client.ClientHttpResponse
import org.springframework.security.core.Authentication
import org.springframework.security.core.context.SecurityContextHolder
import java.util.Map
import java.util.HashMap
import org.slf4j.Logger
import org.slf4j.LoggerFactory
class Main extends Script {
private static final Logger logger = LoggerFactory.getLogger(Main.class)
Main(){
}
def run() {
logger.info("input rowID: " + data['rowID'])
logger.info("input iName: " + data['iName'])
}
static void main(String[] args) {
InvokerHelper.runScript(Main, args)
}
}
Appendix C: Send Custom Transform
import org.codehaus.groovy.runtime.InvokerHelper
import org.springframework.web.client.RestTemplate
import java.io.IOException
import org.springframework.util.MultiValueMap
import org.springframework.util.LinkedMultiValueMap
import org.springframework.http.MediaType
import org.springframework.http.HttpEntity
import org.springframework.http.CacheControl
import org.springframework.http.ResponseEntity
import org.springframework.http.HttpHeaders
import org.springframework.http.HttpRequest
import org.springframework.http.client.ClientHttpRequestExecution
import org.springframework.http.client.ClientHttpRequestInterceptor
import org.springframework.http.client.ClientHttpResponse
import org.springframework.security.core.Authentication
import org.springframework.security.core.context.SecurityContextHolder
import java.util.Map
import java.util.HashMap
import org.slf4j.Logger
import org.slf4j.LoggerFactory
class Main extends Script {
private static final Logger logger = LoggerFactory.getLogger(Main.class)
private static final sscServer = "http://m5510.local:3000"
Main(){
}
def run() {
def builder = new groovy.json.JsonBuilder()
builder {
rowID data['rowID']
rowData data['rowData'].getAt(0)
}
logger.info(builder.toPrettyString())
def email='will.wilbrink@buzzy.buzz'
def pass='buzzy'
def authHeaders = login(email, pass)
data['result'] = postToBuzzy(authHeaders, builder.toPrettyString())
}
def login(email, pass) {
//def url = 'https://a.buzzy.buzz/api/login'
def url = sscServer + "/api/login"
def restTemplate = new RestTemplate()
HttpHeaders headers = new HttpHeaders()
headers.setContentType(MediaType.APPLICATION_JSON)
Map<String, String> map = new HashMap<String, String>()
map.put("email", email)
map.put("password", pass)
def requestJson = new groovy.json.JsonBuilder( map ).toPrettyString()
HttpEntity<String> request = new HttpEntity<String>(requestJson, headers)
def raw = restTemplate.postForObject( url, request , String.class )
def slurper = new groovy.json.JsonSlurper()
def result = slurper.parseText(raw)
Map<String, String> out = new HashMap<String, String>()
out.put("token", result["data"]['authToken'])
out.put("id", result["data"]['userId'])
return out
}
def postToBuzzy(authMap, jsonBody) {
//def url = 'https://a.buzzy.buzz/api/updatemicroapprow';
def url = sscServer + "/api/updatemicroapprow"
def restTemplate = new RestTemplate()
logger.info(url)
HttpHeaders headers = new HttpHeaders()
headers.setContentType(MediaType.APPLICATION_JSON)
headers.setCacheControl(CacheControl.noCache())
headers.add("X-Auth-Token", authMap.get("token"))
headers.add("X-User-Id", authMap.get("id"))
HttpEntity<String> request = new HttpEntity<String>(jsonBody, headers)
def raw = restTemplate.postForObject( url, request , String.class )
logger.info("Post returned: "+ raw)
return raw
}
static void main(String[] args) {
InvokerHelper.runScript(Main, args)
}
}