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:
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
Before you publish a component. Your user account has to have property vendor set to a string. The value depends on what vendor is used in component(s) you're about to publish. More about that in here. In the examples in this section we use appmixer as a vendor, but you should use your own. If your company is called acme then the vendor property should be set to acme as well. You can use Backoffice for that as shown in the next picture.
The last step is to publish our component for our users to use. This is done using the appmixer publish command:
Our component is now published and ready to be used:
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:
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:
$ 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:
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: