-
Choreographer SDK for ExpressJS
- Getting started
-
API
passRequestHeaders ()
-
install (options)
-
deploy (modelFileName, options)
-
deployStub (modelName, stubFileName)
-
start ([modelName], [data], [options])
-
completeTask (taskName, [modelInstanceId], [data])
-
moveToTask (taskName, [modelInstanceId])
-
addVariables ([modelInstanceId], data)
-
variables([modelInstanceId])
-
instance([modelInstanceId])
-
getDefinition([modelName])
configure (options)
- Running example apps
Choreographer SDK for ExpressJS
A client SDK for Choreographer, used for building express.js based web applications. Hides most of the complexity by wrapping javascript wrappers around ExpressJS middleware. Below are the key features –
- easily deploy the model file
- re-create instances at a route
- complete tasks
- get information about the model instances
- add custom variable into active instances
- retrieve all available variables at a given time
You can use this SDK in two approaches, depending on your use cases.
- Use
install
middleware and bind CG context to Express request - Create your own CG instance and handle all operations with your own logic. You should avoid this approach unless you've pressing reasons to do so.
But that's not all, you can also mix both these approaches.
Getting started
This section assumes you've working knowledge of Nodejs and Express web framework.
Prerequisites
Before you begin, please install few required libraries/tools to make sure you have everything to run the app. Run below commands in your terminal or console one by one and ensure these are installed. If you already have ES6 installed or you're using Webpack, ignore below steps.
$ npm install -g babel-cli
$ npm install -g babel-boilerplate
From the folder of your choice, run –
$ es6-babel-generate ask.name && cd ask.name && rm src/*.js && touch src/index.js model.conf
If you are running on windows command prompt use this one instead –
$ es6-babel-generate ask.name && cd ask.name && del "src\*.js" && echo. > src/index.js && echo. > model.conf
This command will create a folder named ask.name
and install all required
ES6 libraries. At this point, your folder structure should
look like this –
$ /ask.name
.
├── .babelrc
├── .npmignore
├── model.conf
├── package.json
└── src
└── index.js
1 directory, 5 files
Now, install Express and Choreographer Express SDK in this folder –
$ npm install
$ npm install --save express
$ npm install --save choreographer-express
You also need Choreographer server to be running for this example code to run, you can do so by running Choreographer Console, which self hosts a Choreographer server.
Model
Copy and paste below model in model.conf
present in the root folder.
modelInfo.name = "ask.name"
userTasks.askName {
expectedInputs {
name {
type = "string"
}
}
}
sequenceFlows.1.start = askName
sequenceFlows.1.end = askName
This is a simple model that expects user to provide their name. Nothing useful however we will eventually build complex scenarios in this model later on in this documentation.
Notice the model.conf
file is kept in the root. CG expects model.conf
to
be in the root as it automatically finds and deploys it. You can also
customize the defaults, you will see that in a bit.
You need not build any UI but only REST endpoints exposed through a simple Express server and SDK helps you to execute the model you created.
Now write src/index.js
file, essentially the express server –
import cg from 'choreographer-express';
import express from 'express';
let app = express();
app.use(cg.install({
newInstanceTrigger: (req) =>
req._parsedUrl.pathname === 'askName'
}));
app.get('/', (req, res) => res.send("Running ... "))
// user submits the form so we need to complete the task askName
app.post('/ask-name', (req, res) => {
var value = req.body.data.name;
req.completeTask('askName', {
name: value
})
.then((taskInfo) => res.send(`Hello ${taskInfo.vars.name}`))
.catch((err) => res.send(`Something went wrong - ${err}`));
});
app.listen(3000);
Above example uses req.completeTask
to complete the task askName
. The
cg.install
takes care of installing the model that is present in the root
folder.
Now run npm run build && node dist/index.js
. At this point, the server should
be running and listening at port 3000.
Visit http://localhost:3000
and you should see Running ...
text in your
browser.
API
The SDK lets you tune its strings, if you are not satisfied with the default settings,
you can configure it using wrenches that come along in form of options
and other parameters
–
passRequestHeaders ()
Retuns middleware function. Set the header in Choreographer server requests. A simple example –
app.use(cg.passRequestHeaders());
install (options)
If you are easy-going, don't like that extra baggage, no worries – install
will do all the heavy lifting!
options.modelName
Model configuration file name, defaults to model.conf
in the root path.
options.serviceUrl
Choreographer url, defaults to http://0.0.0.0:9000
options.newInstanceTrigger
A trigger function that returns true
or false
to decide whether to start a
new instance. By default, whenever user visits the root path (/
) a new
instance will be created and older ones are ignored (older ones are
just left as it is in CG).
A simple example –
app.use(cg.install({
newInstanceTrigger: (req) => req._parsedUrl.pathname === '/dashboard' && req.method === 'POST';
}));
This example starts a new instance of the model every time the user logs in and reaches dashboard.
options.cookieSettings.name
& options.cookieSettings.maxAge
A cookie name to be used while setting the modelInstanceId
in the cookies.
SDK takes care of setting modelInstanceId
in the cookies to remember
when newInstanceTrigger
returns true
therefore it will reuse the same
instance id. CG does not provide any session-like features and left it to client
sdks to handle the way sdks will be implemented depending upon the
underlying framework.
app.use(cg.install({
cookieSettings: {
name: 'mt-instance',
maxAge: 60 * 60 * 24 // 1 day
}
}));
options.cookieSettings.name
defaults to cg-instance
and
options.cookieSettings.maxAge
defaults to 0 days, meaning, until the current
browser session.
options.initialData
Initial JSON object to be used while starting a new instance. By default, its value is an empty object.
A simple example –
app.use(cg.install({
initialData: {
"someVariable" : "value"
}
}));
This example starts a new instance of the model with initial JSON
{
"someVariable" : "value"
}
options.headers
This contains the list of keys or a string which can be consider as regx expression. This key will provide the headers, which we want to set in Choreographer request's header. By default, its value is an empty array.
app.use(cg.install({
headers: "x-custom"
}));
Example of header list:
app.use(cg.install({
headers: ["x-custom-header-1","x-custom-header-2"]
}));
Below is a complete example of install
with custom settings –
const triggerFunc = (req) => {
return req.isLoggedIn == true;
};
app.use(cg.install({
serviceUrl: 'http://cgdev.exzeo.com',
newInstanceTrigger: triggerFunc,
cookieSettings: {
name: 'someName',
maxAge: 60 // 60 minutes
},
initialData: {
"someVariable" : "value"
}
}));
deploy (modelFileName, options)
Note: In most cases you don't need to call this method if you're using
install
middleware.
Deploys a model file mentioned in modelFileName
parameter which defaults to
/model.conf
. This function takes care of memoizing model deployments,
meaning, already deployed models will not be deployed every time it is called
during runtime.
app.use((req, res, next) -> {
cg.deploy('conf/some.conf')
.then((s) => {
next();
})
.catch(s) => {
console.error(`couldn't deploy the model - ${s}`);
next();
});
});
modelFileName
The name of the model file along with path.
options.forceDeploy
Deploys the model forcefully. Note that setting forceDeploy
is merely suggesting
SDK to ignore memoization of the previous deployments and forcefully call
CG to deploy the model. However, CG only re-deploys in case the model has some
changes in model content.
app.use(function(req, res, next) {
cg.deploy('conf/some.conf', {forceDeploy: true});
})
deployStub (modelName, stubFileName)
Deploys a js stub file mentioned in stubFileName
parameter which defaults to
/model.stub.js
, aganist the model mentioned in modelName
parameter.
Note: In cases of using
install
middleware. You dont need to pass themodelName
.
app.use((req, res, next) -> {
cg.deployStub('modelName', 'conf/model.stub.js')
.then((s) => {
next();
})
.catch(s) => {
console.error(`couldn't deploy the stub - ${s}`);
next();
});
});
modelName
the name of model defined in model conf file.
stubFileName
The name of the js stub file along with path for a deployed model.
start ([modelName], [data], [options])
NOTE: If you've used
install
middleware, you don't need to use this method to start an instance.
Starts new instance for a given model name (not the file name, it can be different).
The modelName
is optional. In case, one is not passed and install
middleware
is already called, this method try to look for modelName
from Router's request
object otherwise throws an error. A method called cg.modelInfo()
provides
complete response after starting the model instance.
modelName
Name of the model. The file name and modelName can be different.
[data]
Optional. Initial JSON object to be used while starting the model.
[options.forceStart]
Optional. Defaults to false
. In case of true
and install
middleware was
called before it starts new instance even there are active instances available.
It also replaces current modelInstanceId
to the new instance id in the cookies.
Also note, if middleware wasn't used then this flag has no effect.
Example
NOTE: If you'e used
install
middleware and want to start an instance of the model from the Expressrequest
object
let initialData = {
name: "blah"
};
let options = {
forceStart: true
};
req.start(initialData, options);
NOTE: If you've not used
install
and want to handle your own way of starting model instances then you should've deployed your model before callingstart
, like below –
import cg from `choreographer-express`;
let initialData = {
name: "blah"
};
let options = {
forceStart: true
};
cg.deploy('some-conf.conf')
.then(cg.start('someModelName', initialData, options)
.then((res) => {
console.log(`someModelName and started ...`)
})
.catch((err) => {
console.err (`something went wrong`)
}));
completeTask (taskName, [modelInstanceId], [data])
Completes a task with any input data required for the task to be completed in CG.
In case, a modelInstanceId
is not provided, this method assumes install
middleware was called earlier.
taskName
Required. Name of the task.
[modelInstanceId]
Optional, only required when install
middleware was not used to setup CG.
[data]
Optional. JSON object to be used as variables while completing the task.
Example
req.completeTask('askName', { data: "some"})
moveToTask (taskName, [modelInstanceId])
Converts a completed task to an active task with its field values as default. Field values would be the values that were provided at the time of marking this task as complete. In case, a modelInstanceId
is not provided, this method assumes install
middleware was called earlier.
Note: Response will give you new instance id. Use new instance id to work on new active task.
taskName
Required. Name of the task.
[modelInstanceId]
Optional, only required when install
middleware was not used to setup CG.
Example
cg.moveToTask('askName', 'instanceId')
addVariables ([modelInstanceId], data)
Adds new variable into given modelInstanceId
. The data
should be a valid JSON
object.
[modelInstanceId]
Optional, only required when install
middleware was not used to setup CG.
[data]
Optional. JSON object to be used as variables while completing the task.
Example
req.addVariables({
"var1" : "some-value"
});
variables([modelInstanceId])
Returns list of available variables for a given modelInstanceId
.
Example
req.variables();
[modelInstanceId]
Optional, only required when install
middleware was not used to setup CG.
instance([modelInstanceId])
Returns complete status information about a given modelInstanceId
.
[modelInstanceId]
Optional, only required when install
middleware was not used to setup CG.
Example
req.instance();
getDefinition([modelName])
Returns model definetion for the given modelName
.
[modelName]
Optional, only required when install
middleware was not used to setup CG.
Example
//When install middleware is used
req.getDefinition();
//when install middleware is not used
cg.getDefinition('someModelName');
configure (options)
You can configure the SDK at your own by calling this function and pass options
–
options
here has same properties as in install(options)
Below is a complete example of configure
with custom settings –
const triggerFunc = (req) => {
return req.isLoggedIn == true;
};
cg.configure({
serviceUrl: 'http://cgdev.exzeo.com',
newInstanceTrigger: triggerFunc,
cookieSettings: {
name: 'someName',
maxAge: 60 // 60 minutes
}
});