Appmixer CLI

Appmixer command-line tool.

Use the Appmixer CLI tool to interact with the Appmixer engine remotely from the command line. It can be used to list flows, start/stop flows but more importantly, to develop and publish custom components.

Installation

  • Download and install NodeJS: https://nodejs.org (version >8 is required)

  • npm install -g appmixer

Help

Display the command options with the -h option:

$ appmixer -h
Usage: appmixer [options] [command]
Appmixer command line interface.
Options:
-v, --version output the version number
-h, --help output usage information
Commands:
download|d Download component.
flow|f Flow commands.
init|i Initialize component.
login|l Login into Appmixer API.
logout|o Logout from Appmixer API.
pack|p Pack component into archive.
publish|pu Publish component.
remove|rm Remove component.
test|t Test component, authentication module, ...
url|u <url> Set Appmixer API url.
help [cmd] display help for [cmd]
Go to https://docs.appmixer.com/appmixer/ to find more information.

Each command has its own help information:

$ appmixer flow -h
Usage: appmixer flow <command>
Flow commands.
Options:
-h, --help output usage information
Commands:
start|s <flowId> Start flow.
stop|t <flowId> Stop flow.
remove|r <flowId> Remove flow.
ls|l [flowId] Ls flow.
help [cmd] display help for [cmd]

Initialization

First set the Appmixer API URL. This is the URL of your hosted Appmixer engine instance or your own custom URL where the self-managed engine is located. If you have a trial package or local installation, you can use http://localhost:2200.

$ appmixer url https://api.appmixer.com

Login to your Appmixer account and enter your password:

$ appmixer login david@client.io
prompt: password:
Login successful.

Creating Custom Components

Generate a sample component

The best way to start implementing your own custom components is to use the generator tool to generate a sample component. This gives you the basic skeleton of your component/service that you can later tweak. Use the appmixer init example command to generate a sample component:

$ appmixer init example
Usage: appmixer init example <type> [path]
Options:
--vendor [vendor] Your vendor name.
--verbosity Verbosity level of the generated output log. Number in [0 - 2] range. Defaults to 1.
-h, --help output usage information
Examples:
$ appmixer init example no-auth
Environment Variables:
AM_GENERATOR_COMPONENT_PATH Components base directory. [path] argument overrides this variable if used.

As you can see, we have to give this command a type of example we want to generate. We will start with the most simple service type that does not use any authentication (OAuth1, OAuth2, API keys). In other words, the component will not ask the user to connect any account in the Inspector panel when using the component in a flow.

$ appmixer init example no-auth
Created directory structure ./appmixer/myservice/mymodule/MyComponent
Creating component appmixer.myservice.mymodule.MyComponent
Created component manifest file ./appmixer/myservice/mymodule/MyComponent/component.json.
Created component package file ./appmixer/myservice/mymodule/MyComponent/package.json.
Created component behaviour file ./appmixer/myservice/mymodule/MyComponent/MyComponent.js.
Created service manifest file ./appmixer/myservice/service.json.
Created quota module file ./appmixer/myservice/quota.js.
Example successfully generated.
my-components
└── appmixer
└── myservice
├── mymodule
│ └── MyComponent
│ ├── MyComponent.js
│ ├── component.json
│ └── package.json
├── quota.js
└── service.json
You can now use appmixer pack appmixer/myservice && appmixer publish commands to upload it.

The command prints all the generated files and the directory structure. Note that we have just generated a working component with the myservice.mymodule.MyComponent type.

Pack your component

Now we're ready to pack our service (i.e. create a zip archive with all the generated files) using the appmixer pack appmixer/myservicecommand:

$ appmixer pack appmixer/myservice
Packing component directory: /Users/daviddurman/Projects/appmixer/my-components/appmixer/myservice
Files found in /Users/daviddurman/Projects/appmixer/my-components/appmixer/myservice
- mymodule
- quota.js
- service.json
You are in a directory with service.json file.
I'm going to create directory structure based on name in your service.json file.
3866 total bytes
appmixer.myservice.zip

You can pack the entire service or just the module or even individual components by providing the path to the appmixer pack command.

The pack command generated the appmixer.myservice.zip file in the current directory.

Publish your component

The last step is to publish our component for our users to use. This is done using the appmixer publish command:

$ appmixer publish appmixer.myservice.zip
Publishing archive: /Users/daviddurman/Projects/appmixer/my-components/appmixer.myservice.zip
Published.

Our component is now published and ready to be used:

Custom component published

Notice the labels and icons of the service in the component panel on the left and of the component in the Inspector selector match our definitions from the myservice/service.json and myservice/mymodule/MyComponent/component.json manifest files.

List all available components

To see all the available components uploaded to Appmixer, use the appmixer component ls command:

$ appmixer component ls
appmixer.actimo.contacts.CreateContact
appmixer.actimo.contacts.DeleteContact
appmixer.actimo.contacts.GetContact
appmixer.actimo.contacts.GetContacts
appmixer.actimo.contacts.UpdateContact
appmixer.actimo.groups.GetGroups
appmixer.actimo.messages.SendMessage
appmixer.apify.crawlers.Crawl
appmixer.asana.projects.CreateProject
appmixer.asana.projects.NewProject
appmixer.asana.tasks.CreateStory
appmixer.asana.tasks.CreateSubtask
appmixer.asana.tasks.CreateTask
appmixer.asana.tasks.NewComment
...

Remove your component

If you decide your component is no longer needed, you can remove your component from the system with the appmixer remove command:

appmixer remove appmixer.myservice.mymodule.MyComponent

The remove command lets you specify any portion of the fully qualified component type. For example, if you want to remove the entire service, you can do that with:

appmixer remove appmixer.myservice

It's important to note that removing a component that is used in any of the running flows will cause the flows to stop working. The flows will start generating errors that will be visible in the Insights section. The remove command does not automatically stop the flows. Always make sure the component is not used in any of the running flows before you remove it. IMPORTANT: Removing a component cannot be undone!

Updating your component

You can re-publish (appmixer publish) your component which effectively replaces the old component with the new one.

Note that re-publishing a component will not replace the component in a running flow. Flows wanting the new version of the component have to be stopped and started again to load the new version of the component.

Also note that if you "dramatically" change your component, e.g. removing ports, flows using the component type might require re-configuration since the ports that were used to connect to other components will not exist. The same goes for other major changes: changing output parameters that are used in connected components, changing inspector config and properties, etc.

Testing your component

Writing/updating code of your component, re-publishing it and re-configuring/restarting your flow every time you need to test your component would be a long process. Therefore, the Appmixer CLI tool provides a command to test your component locally on your machine, before publishing it to Appmixer. The appmixer test command allows you to test your component by sending messages to it, configuring properties and testing authentication methods:

$ appmixer test -h
Usage: appmixer test <command>
Dev tools for testing your files.
Options:
-h, --help output usage information
Commands:
dump|d <moduleName> Get stored authentication data from previous commands.
auth|a <authModuleFile> Authenticate service.
component|c <componentFile> Test component.
help [cmd] display help for [cmd]

We'll start by exploring the component testing tool:

$ appmixer test component -h
Usage: appmixer test component [options] [componentDir]
Options:
-f, --transform [transform] specify transformer
-i, --input [input] input test message object (default: [])
-m, --mime [mime] mime type, application/json by default
-p, --properties [properties] component properties (JSON format)
-s, --no-state do not show component's state
-t, --tickPeriod [tickPeriod] tick period (in ms), default is 10000 ms
-h, --help output usage information
Examples:
Following example will send input message { "to": "your@email.com" } to component's input port 'in'.
You always have to specify to which input port you want to send message.
$ appmixer test component [path-to-your-component-directory] -i '{ "in": { "to": "your@email.com" } }'
This is how to specify transformer function from transformer file.
$ appmixer test component [path-to-component] -i '{}' -f './transformers#channelsToSelectArray'
How to set properties and tick period:
$ appmixer t c [path-to-component] -p '{ "channelId: "123XYZ" }' -t 2000
You can send more than one message:
$ appmixer t c [path-to-component] -i '{ "in": { "to": "first@email.com" }}' -i '{ "in": { "to": "second@email.com" }}'
You can run appmixer command in your component's directory:
$ appmixer test c
Directory has to contain component.json file and component's source code file.
If you're developing component that needs authentication, use 'appmixer test auth' before.
If you're developing Oauth2 component you might need to refresh access token before calling this command.
Use 'appmixer test auth refresh' for such purposes.
Some of the feature (context.store, context.componentStaticCall, ... will work only if you are logged in into Appmixer.
If you want to test them in your component, call appmixer login first.
For more information, checkout our documentation at:
https://docs.appmixer.com/appmixer/component-definition/authentication
https://docs.appmixer.com/appmixer/appmixer-trial/custom-component-helloappmixer

Let's say we want to send a message to our component and see how it reacts, i.e. what is the output of our component. We know our component has an input port called in and requires the sourceData property as part of the incoming messages (see the component.json file of your MyComponent, especially the inPorts section). We can use the test command for this:

$ appmixer test component appmixer/myservice/mymodule/MyComponent -i '{ "in": { "sourceData": "foo" } }'
Testing /Users/daviddurman/Projects/appmixer/my-components/appmixer/myservice/mymodule/MyComponent
Validating properties.
Test server is listening on 2300
Starting component.
Calling receive method with input message:
in:
-
properties:
correlationId: null
gridInstanceId: null
contentType: application/json
contentEncoding: utf8
sender: null
destination: null
correlationInPort: null
componentHeaders:
signal: false
content:
sourceData: foo
scope:
{"name":"component","hostname":"MacBook-Pro.local","pid":26397,"level":30,"msg":"{\"properties\":{\"correlationId\":\"8f2ce09e-3f6d-48dd-81bd-e80189f70bb4\",\"gridInstanceId\":null,\"contentType\":\"application/json\",\"contentEncoding\":\"utf8\",\"sender\":{\"componentId\":\"70eb49e9-88df-4d0e-9549-d4e4f0f755c0\",\"type\":\"appmixer.myservice.mymodule.MyComponent\",\"outputPort\":\"out\"},\"destination\":null,\"correlationInPort\":null,\"componentHeaders\":{},\"signal\":false},\"content\":{\"sourceData\":\"foo\"},\"scope\":{\"_walkthrough\":[{\"targetId\":\"70eb49e9-88df-4d0e-9549-d4e4f0f755c0\",\"links\":[]}]}} { componentId: '70eb49e9-88df-4d0e-9549-d4e4f0f755c0',\n flowId: 'c5d05118-13b5-4ec8-a8fe-2e6ef51fdd52',\n userId: '5da735715abc4a671dfb592f',\n componentType: 'appmixer.myservice.mymodule.MyComponent',\n type: 'data',\n portType: 'out',\n port: 'out',\n inputMessages: { in: [ [Object] ] },\n annotatedMsg: { sourceData: 'foo' } }","time":"2019-10-16T15:21:22.169Z","v":0}
Component sent a message to its output port: out
{ sourceData: 'foo' }
Component's receive method finished in: 45 ms.
Return value from receive method:
undefined
Component's state at the end:
State is empty, component did not store anything into state.
Stopping component.
Destroying component.

The command prints out a lot of useful information, for example the output of the component (see "Component sent a message to its output port: out"). Since our component just forwards the same data that it received, we see the same object we sent to it: { sourceData: 'foo' }.

Now suppose we have a bug in our code in MyComponent.js, a syntax error:

module.exports = {
receive(context) {
myBadError
context.sendJson(context.messages.in.content, 'out');
}
}

Now re-running the test gives us:

$ appmixer test component appmixer/myservice/mymodule/MyComponent -i '{ "in": { "sourceData": "foo" } }'
Testing /Users/daviddurman/Projects/appmixer/my-components/appmixer/myservice/mymodule/MyComponent
Validating properties.
Test server is listening on 2300
Starting component.
Calling receive method with input message:
in:
-
properties:
correlationId: null
gridInstanceId: null
contentType: application/json
contentEncoding: utf8
sender: null
destination: null
correlationInPort: null
componentHeaders:
signal: false
content:
sourceData: foo
scope:
[ERROR]: myBadError is not defined

Downloading your component

When your component is published, you can always download it back to your local file system. To download the source code of your component, use the appmixer download command:

$ appmixer download -h
Usage: appmixer download selector
Options:
-o, --out [dir] Where you want save it.
-h, --help output usage information
Examples:
Download all files for SendEmail component:
$ appmixer download vendor.google.gmail.SendEmail
Download only package.json file for SendEmail component:
$ appmixer download vendor.google.gmail.SendEmail/package.json
Download main SendEmail.js file only:
$ appmixer download vendor.google.gmail.SendEmail/SendEmail.js
Download all gmail components:
$ appmixer download vendor.google.gmail
Download auth.js file for gmail:
$ appmixer download vendor.google.gmail/auth.js
Download quota.js file for gmail:
$ appmixer download vendor.google.gmail/quota.js

In our case, the download command would look like:

$ appmixer download appmixer.myservice
$ ls
appmixer.zip
$ unzip appmixer.zip
$ tree appmixer/
appmixer
└── myservice
├── mymodule
│   └── MyComponent
│   ├── MyComponent.compiled.js
│   ├── MyComponent.js
│   ├── component.json
│   ├── package-lock.json
│   ├── package.json
│   └── sourcemap-register.js
└── service.json
3 directories, 7 files

Working With Flows

Listing Flows

You can list all your flows using the appmixer flow ls command:

$ appmixer flow ls
[Get Current Weather] : [a5769b32-8835-44ad-82e1-ece2874ea3e3] : [stopped]
[Uptime Monitor] : [5b5fd3a0-0ef2-4fc5-9a60-164f5e44c660] : [stopped]
[Daily Rainy Day Alert] : [ec1103e5-c66c-41c4-9223-029d2b328f5c] : [stopped]

If you want to see see just one flow and its stage (running/stopped), you can pass the ID of the flow in the flow ls command:

$ appmixer flow ls a5769b32-8835-44ad-82e1-ece2874ea3e3
Flow: a5769b32-8835-44ad-82e1-ece2874ea3e3
Stage: stopped

To see the flow descriptor of a flow (i.e. JSON object that represents the entire configuration of the components in the flow and their connections), add the --descriptor or -d flag:

$ appmixer flow ls a5769b32-8835-44ad-82e1-ece2874ea3e3 --descriptor
{
"5ba2740c-929b-4599-b09e-fc8f8d5dac82": {
"type": "appmixer.utils.controls.OnStart",
"label": "OnStart",
"source": {},
"config": {},
"x": 88,
"y": 110
},
"0f366972-08fe-4cd4-80c0-227cfb6db54b": {
"type": "appmixer.utils.weather.GetCurrentWeather",
"label": "GetCurrentWeather",
"source": {
"location": {
"5ba2740c-929b-4599-b09e-fc8f8d5dac82": [
"out"
]
}
},
"config": {
"transform": {
"location": {
"5ba2740c-929b-4599-b09e-fc8f8d5dac82": {
"out": {
"type": "json2new",
"lambda": {
"city": "Prague",
"units": "metric"
}
}
}
}
}
},
"x": 286,
"y": 110
},
"ab6a22f8-916d-4aab-a5e3-2abedc03917c": {
"type": "appmixer.utils.email.SendEmail",
"label": "SendEmail",
"source": {
"in": {
"0f366972-08fe-4cd4-80c0-227cfb6db54b": [
"weather"
]
}
},
"config": {
"transform": {
"in": {
"0f366972-08fe-4cd4-80c0-227cfb6db54b": {
"weather": {
"type": "json2new",
"lambda": {
"from_email": "info@appmixer.com",
"subject": "Appmixer: Current Weather",
"text": "Temperature: {{{$.0f366972-08fe-4cd4-80c0-227cfb6db54b.weather.main.temp}}} dgC\nPressure: {{{$.0f366972-08fe-4cd4-80c0-227cfb6db54b.weather.main.pressure}}} hPa\nHumidity: {{{$.0f366972-08fe-4cd4-80c0-227cfb6db54b.weather.main.humidity}}}%\nCloudiness: {{{$.0f366972-08fe-4cd4-80c0-227cfb6db54b.weather.clouds.all}}}%",
"to": ""
}
}
}
}
}
},
"x": 484,
"y": 110
}
}

Starting and Stopping Flows

You can start and stop flows using the appmixer flow start and appmixer flow stop commands:

$ appmixer flow start a5769b32-8835-44ad-82e1-ece2874ea3e3
Flow a5769b32-8835-44ad-82e1-ece2874ea3e3 successfully started.
$ appmixer flow stop a5769b32-8835-44ad-82e1-ece2874ea3e3
Flow a5769b32-8835-44ad-82e1-ece2874ea3e3 successfully stopped.

Removing Flows

To remove flows, use the appmixer flow remove command:

$ appmixer flow remove 2058a1ee-9c19-4e94-bd7a-0da7f9bed973
Flow 2058a1ee-9c19-4e94-bd7a-0da7f9bed973 successfully removed.

Note that the removed flow will be automatically stopped if it was running. Also note that this action cannot be undone.