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

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:

$ 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:

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.

Last updated