CirrusWave documentation


cirruswave

  • cirruswave is a complete microservices development platform for nodejs that enables development and testing.
  • CirrusWave offers several products to help accelerate development of enterprise grade microservices
    The products are applications that help program managers and developers gather requirements, analyze the existing solutions, break them into logical services, generate mind-map of resources. Developers can then develop the API for all these servcies, add business logic and data necessary, get the applications to be ready for deployment. Below is the documentation for the product usage
  • These products share a common platform
    The platform provides underlying capabilities. While the products enable you to develop these services easily, advanced users might like the flexibility of directly using the platform. The platform documentation is given further below.
Monolith to Microservices
  • Template for analyzing and mapping out monolith
  • Microservice to resource mapping and API generation
  • Config driven security & run time validation
  • API access log support
  • Analytics and Visualization of Microservice usage
  • Deploy containers and/or cloud
Cloud Containerization product
  • Template driven description of application assets
  • Consolidated generation of App installation scripts and container readiness
  • Image creation for containerized deployment
  • CICD readiness
  • Package deployment to containers
Legacy to Microservices
  • Legacy Code Reflection
  • Template driven approach to exposing legacy functionality
  • Legacy Language Bridges
  • REST API conversation of Legacy capabilities
  • Migration to cloud
Connected Data Catalog
  • Connections to diverse data sources
  • Provide secure access to data
  • Automatic analysis of data
  • Extraction of meta-data
  • Support for annotated meta-data
  • Catalog for the data and meta-data
  • Index for the catalog with search and discovery
M2M - Monolith to Microservices
  • To Generate new project, add services
  • cirruswave -g -t excelbased -r gettemplate cold start a project with a default excel template and begin to edit it
  • cirruswave -g -t excelbased -r createapilist -x <excelfile.xlsx> create a list of API signatures from mindmap and add them to the excel spreadsheet for edit and review
  • cirruswave -g -t excelbased -r generateproject -x <excelfile.xlsx> generate the code and all necessary artifacts for the microservices based on excel template
  • cirruswave -g -t newproject To generate a new project ready for either application or system services to be added
  • cirruswave -g -t addnewservice To generate a new microservice to an existing project run this from the project home directory
  • cirruswave -g -t openapi -j <openapi_swaggerfileexample.json> To generate a new project from a Swagger / OpenAPI JSON file
All products. M2M, L2M, CCP, CDC
  • Helper commands
  • cirruswave -g -t schema -j <example.json> -o <schemaexample.json> generate schema from example.json and store it in schemaexample.json
  • cirruswave -g -t encrypt -E <encryption secret phrase> -S <String to encrypt> --generate encrypted string given the secret phrase and a string to be encrypted. Note any special characters need to be escaped
All Products. M2M, L2M, CCP, CDC
  • To Containerize
  • cirruswave -c -s generate -j <appserviceconfig.json> Step 0: Generate configfile for the current project
  • cirruswave -c -s generate -j <appserviceconfig.json> -i <ipvalue> Step 0a: Generate configfile for the current project with logging to elk stack at the given ip
  • cirruswave -c -t deploymenttarget -j <appserviceconfig.json> -s generate Step 1: Add to configfile - compute ip information the pem file location and public dns (ip v4) info
  • cirruswave -c -s prepare -j cr.json -f <yourprojectdeployconfig.json> Step 2: Prepare the necessary files
  • cirruswave -c -s createimages -e docker -f <yourprojectdeployconfig.json>[ -p <pswd>] Step 3: Create the necessary imagefiles - environment options available are [docker, aws, azure] and an optional password for the container registry which overrides password in cr.json
  • cirruswave -c -t deploymenttarget -j <appserviceconfig.json> Step 4: Add targets to deployment scripts - compute ip information the pem file location and public dns (ip v4) info
  • cirruswave -c -s deploy -e docker -f <yourprojectdeployconfig.json>[ -p <pswd>] Step 4a: Deploy the images to the target compute machines - environment options available are [docker, aws, azure] and an optional password for the container registry which overrides password in cr.json
  • cirruswave -c -m incremental -s deploy -e docker -f <yourprojectdeployconfig.json>[ -p <pswd>] Step 4b: Redeploy (mode incremental) images to target compute machines - environment options [docker, aws, azure] and an optional password for the container registry which overrides password in cr.json
  • cirruswave -c -m local -s deploy -e docker -f <yourprojectdeployconfig.json>[ -p <pswd>] Step 4c: Deploy and run in local docker environment (mode local) images to target compute machines - environment options [docker] and an optional password for the container registry which overrides password in cr.json
  • cirruswave -c -s enterprise -j <ejsonfile.json> -P <projectname> -i <ipvalue> Step 4d: Generate container deployment configfile for the current enterprise project with logging to elk stack at the given ip. Note either project name or jsonfile can be given. It will interactively ask for service details if jsonfile is not given
All Products. M2M, L2M, CCP, CDC
  • To Setup system services:
  • cirruswave -g -t keymgr System service KeyMgr issues keys and grants access to services. Services with security set to 'basic' or 'accessky' will need acckey and secretekeys to authnticate. Services set with 'jwt' will require jwt to be passed in or generated using the keymgr. When jwt is passed in, set 'jwtexternal' to true and setup 'validatesecurity' callback to do custom validation of the claims. Set up credentials for AWS s3 where keys are stored.
  • cirruswave -g -t workflow System service workflow provides capabilities for business logic to drive the microservices. Each workflow consists of a plan with serveral tasks that are executed according to the business logic. The plans and state of the workflow plans are stored in AWS s3.
  • cirruswave -g -t connector -z [ s3, azblob, mssql, pgsql, mysql, oracledb, snowflake, azcosmosdb, n4jsvc, esservice, rabbitmq, wsoc, jira, sftp, ftp, email] offers connectors to important data sources and provides uniform REST API access to all of them. You can create multiple connections to the securely to all of the data sources.
  • cirruswave -g -t wsocserver System service wsocserver provides websocket server service for sending messages over stateful socket connections to clients
  • cirruswave -g -t converter System service converter provides converters from various formats like HTML, EDI, CSV, JSON to other formats like CSV, JSON. Each converer is available as a separate route in the converter service
CirrusWave version management
  • Update to the latest version of CirrusWave
  • cirruswave -V Get the version information on CirrusWave commandline app (global)
  • cirruswave -s update -m local Update to the latest CirrusWave platform
  • cirruswave -s update -m global Update to the latest version of CirrusWave command line product
Launch Sripts
  • Generate scripts to launch
  • cirruswave -g -t runallscripts -j appserviceconfig.json Generates shell scripts to run all services locally. After this you can do 'bash launchscripts/runallservices.sh' which runs the services and ctrl+c will kill all of them
  • cirruswave -g -t deploymentscripts -j appserviceconfig.json -i loggingip Generates shell scripts for building and running in containers. logging ip is optional. This commands generates the following scripts
  • bash launchscripts/buildcontainer.sh Generates the deploymentconfig.json file, getting the project ready for image preparation, build and push images to container registry pointed to by cr.json
  • All the generated scripts are in launchscripts folder
  • bash launchscripts/runcontainerlocal.sh pull images from container registry and run them locally
  • bash launchscripts/runcontainerremote.sh pull images from container registry and run them. This will ask for deployment target information. You can clear existing targets, add new targets etc.
Deployment modes
  • Customizable deployments modes
  • cirruswave -g -t createdeploymentmode -j appserviceconfig.json -m [dev, qa, test, prod] mode can be any string. Generates deploymentmode/<mode> directory where all the customized configs are stored
  • cirruswave -g -t deletedeploymentmode -j appserviceconfig.json -m [dev, qa, test, prod] a specific mode and the associated files can be deleted
  • cirruswave -g -t setmode -j appserviceconfig.json -m [dev, qa, test, prod] Containerized commands will be ready for deployment with this mode
  • cirruswave -g -t restoredefaultmode -j appserviceconfig.json default mode is restored. In general all deployment should be done after setmode
  • createdeploymentmode - needs to be done to update whenevver new system services like adding new connections, workflow etc. are configured
  • setmode - Before generating deployment scripts make sure you are in the right mode by doing setmode command
  • cirruswave platform features
  • npm enabled microservices platform
  • Optional JSON Schema based validation of url params, query params, request body and response<
  • Optional accesskey based security with built in validation of keys
  • KeyMgr service to help with issuing developer accesskey and secret key
  • Automatic documentation of the services
  • Test framework to enable easy testing of the microservice
  • Documentation for cirruswave is organized into two parts:
  • Documentation
    This describes how developers can use the service. Includes installation instructions, Getting started, Advanced topics like schema validation of REST API, detailed options for securing REST API, setting up for autodocumentation and enabling testing tools.
  • Tools
    Details of the tools for the microservices. Includes access to the tools, how to use the testing and documentation tools for the system services and microservices developed.
  • To create a microservice using cirruswave the following steps are required
  • Service Config
    This file contains a list of services, the configuration for each of the service and branding information used in the service tools
  • Application Config
    For each service there is one appconfig file. This file contains the configuration for each route (REST endpoint)
  • Launch script
    A NodeJS file to launch each of the named microsservice(s) listed in the service config file
  • App service configuration is a json file that contains each service as an object. There are two objects.
  • about
    Contains the branding information for the services
  • services
    contains all the service objects with a unique name
  • Each service object has a name and the following fields
  • protocol
    Protocol for this service. It can be either http or https. If https is provided, it's expected that you generate ssl certifcate and specify the path to this .crt file.
  • port
    A unique portnumber where the service can be reached. e.g. 4003 for keymgr
  • hostname
    The hostname where this service is located. examples are domainname like cirruswave.com or localhost
  • certPath
    Optional field that specifies where the ssl certificate is located. This is required if protocol is https.
  • description
    One or two sentences that best describe the service. This will be displayed in the autogenerated documentation for the service which is rendered on <protocol>://<hostname>:<port>/documentation
  • configfilepath
    path where the configfile is located. The path can be relative to the application directory or absolute path. It shoudl also include the file name. Details are described in the App Configuration section below
  • security
    This specifies the level of security to enable for this service. The possible values are nokey - this is least secure option. Anyone can call this service, appkey - the service is accessible by passing the appkey, basic - key based authorization but requires ssl encryption of the channel to ensure security, acckey - this is the most secure way. In this each user is given a key called acckey and a secret key which plays the role of a password.
  • key
    service key (a.k.a appkey) that's autogenerated if one is not supplied. See below in security for how this is used
  • init
    This is an optional object. It defines the initialization options for the service and the class and function where these options are passed at the time of launching the service. This object is defined in detail below.
  • When present 'init' object describes the intialization parameters and initialization function that will be invoked with the init object at the time of launching the service
  • class
    Either absolute path or relative path (relative to the application service directory where the class with the initialization function
  • function
    The initialization function. This function receives one object called initoptions as defined by optionsschema.
  • optionschema
    This is jsonschema object for the initoptions. The service validates the input initoptions against this schema.
  • options
    The default values for the initoptions object, if it's not passed when invoking the startservice function to launch the service. This object needs to conform to the optionschema.
  • Branding information is described by 'about' object
  • faviconurl
    url to the asset that would represent a favicon
  • imageurl
    url to the asset that would represent your brand logo
  • name
    A name that repsents your service, company. This would be shown next to the logo image
  • url
    website for your service or company. The logo is hyperlinked to this url
  • description
    Brief text describing your service
  • An example serviceconfig with three services. These are also available in the examples directory in cirruswave under node_modules
  • {
      "about": {
        "faviconurl": "/images/bridge.png",
        "imageurl": "/sampleservice/images/bridge.png",
        "name": "SampleService",
        "url": "/documentation",
        "description": "Sample services provided as documentation"
      },
      "logenable":{
        "eshostname":"http://localhost"
      },
      "services": {
        "sampleservice": {
          "init":{
            "class": "sampleservice.js",
            "function": "initialize"
          },
          "protocol": "https",
          "port": 8888,
          "hostname": "localhost",
          "certPath": "security/sampleservice",
          "description": "REST END POINT For Sample Service with no security restrictions",
          "configfilepath": "./appconfig.json",
          "security": "nokey"
        },
        "sampleserviceappkey": {
          "protocol": "https",
          "port": 8889,
          "hostname": "localhost",
          "certPath": "security/sampleservice",
          "description": "REST END POINT For Sample Service that uses appkey that can be specified at the time of deployment or will be autogenerated",
          "configfilepath": "./appkeyconfig.json",
          "security": "appkey",
          "key": "c82b3b0d9eae07a481e9651c6854c3b6"
        },
        "sampleservicebasic": {
          "protocol": "https",
          "port": 9997,
          "hostname": "localhost",
          "certPath": "security/sampleservice",
          "description": "REST END POINT For Sample Service with user specfic keys generated by keymgr service and uses http basic acess authentication protocol",
          "configfilepath": "./acckeyconfig.json",
          "security": "basic"
        },
        "sampleserviceacckey": {
          "protocol": "https",
          "port": 9998,
          "hostname": "localhost",
          "certPath": "security/sampleservice",
          "description": "REST END POINT For Sample Service with user specific keys using custom HMAC based authentication",
          "configfilepath": "./acckeyconfig.json",
          "security": "accesskey"
        },
        "sampleservicejwt": {
          "protocol": "https",
          "port": 9999,
          "hostname": "localhost",
          "certPath": "security/sampleservice",
          "description": "REST END POINT For Sample Service with JWT",
          "configfilepath": "./acckeyconfig.json",
          "security": "jwt",
          "jwtexternal": true,
          "validatescope": {
            "class": "sampleservice.js",
            "function": "ssvalidateservice"
          }
        },
        "taskserver": {
          "protocol": "https",
          "port": 9600,
          "hostname": "localhost",
          "certPath": "security/taskserver",
          "description": "REST Endpoint for workflow service. Not secure and is only for testing purposes",
          "configfilepath": "./taskserver.json",
          "security": "nokey"
        }
      }
    }
    
  • App config specifies contains the service name and details of each route
  • servicename
    name of the service.
  • routes
    Array of individual route objects. Each route object is defined below.
  • Each route object specifies the route, REST API method and where the route is defined
  • route
    Routepath which contains url path to the resource and params separated by :. e.g. /sampleservice/something/:value1/:value2
  • type
    REST API method. Supported methods are GET, POST, PUT, DELETE. This also supports special method called static which can be used to serve static files like html,images css, client-side js files.
  • routeclass
    Either absolute path or relative path (relative to the application service directory where the class with the route function. If static files are served, this acts as a path to the directory where the static files are requested from
  • routefunction
    The function which implements the route.(not used in case of static type) This function takes two parameters. req which is the request object and res which is the response object. These two objects are defined below in detail
  • configured
    This should be set to true for all routes that are tested and are ready to be called. If set to false, the route will be ignored.
  • An example application config that corresponds to the service config given above. The route schema for params and body are also specified. Details of schema specification and auto validation are defined further below in the documentation. These are also available in the examples directory in cirruswave under node_modules
  • {
      "loglevel": "trace",
      "servicename": "sampleservice",
      "routes": [
        {
          "route": "/images",
          "type": "static",
          "configured": true,
          "routeclass": "./images",
          "description": "app specific images are served from the directory ./images under route /sampleservice/images"
        },
        {
          "route": "/sampleservice/images",
          "type": "static",
          "configured": true,
          "routeclass": "./images",
          "description": "app specific images are served from the directory ./images under route /sampleservice/images"
        },
        {
          "route": "/",
          "type": "get",
          "configured": true,
          "routeclass": "./sampleservice.js",
          "routefunction": "Root",
          "description": "Your first Microservice end point"
        },
        {
          "route": "/values/:value",
          "type": "get",
          "configured": true,
          "routeclass": "./sampleservice.js",
          "routefunction": "RouteGetSomething",
          "description": "A room with a view",
          "paramschema": {
            "type": "object",
            "required": [
              "value"
            ],
            "properties": {
              "value": {
                "description": "value e.g. any string",
                "type": "string"
              }
            }
          },
          "examples": [
            {
              "param": "/values/samplestring"
            }
          ]
        },
        {
          "route": "/values/:value",
          "type": "post",
          "configured": true,
          "routeclass": "./sampleservice.js",
          "routefunction": "RoutePostSomething",
          "description": "post example",
          "paramschema": {
            "type": "object",
            "required": [
              "value"
            ],
            "properties": {
              "value": {
                "description": "value e.g. any string",
                "type": "string"
              }
            }
          },
          "bodyschema": {
            "type": "object"
          },
          "examples": [
            {
              "param": "/values/samplestring",
              "payload": {
                "data": "test data for post"
              }
            }
          ]
        },
        {
          "route": "/values/:value",
          "type": "delete",
          "configured": true,
          "routeclass": "./sampleservice.js",
          "routefunction": "RouteDeleteSomething",
          "description": "delete example",
          "paramschema": {
            "type": "object",
            "required": [
              "value"
            ],
            "properties": {
              "value": {
                "description": "value e.g. any string",
                "type": "string"
              }
            }
          },
          "examples": [
            {
              "param": "/values/samplestring"
            }
          ]
        },
        {
          "route": "/values/:value",
          "type": "put",
          "configured": true,
          "routeclass": "./sampleservice.js",
          "routefunction": "RoutePutSomething",
          "description": "put example",
          "paramschema": {
            "type": "object",
            "required": [
              "value"
            ],
            "properties": {
              "value": {
                "description": "value e.g. any string",
                "type": "string"
              }
            }
          },
          "bodyschema": {
            "type": "object"
          },
          "examples": [
            {
              "param": "/values/samplestring",
              "payload": {
                "data": "test data for put"
              }
            }
          ]
        }
      ]
    }
  • The request object
  • body
    json object with the payload. Will contain the valid payload in case of PUT and POST methods
  • params
    object with name, value pairs, where each name corresponds to the param name or query parameters
  • The response object
  • status
    status function takes statuscode. The status codes are standard REST status codes. It's a chainable alais of Node's response.statusCode
  • json
    json function sends a json response
  • The following are some of the places where json-schema can be used.
  • exports.initialize = function()
    {
        console.log("initialized");
    }
    exports.Root = function(req,res)
    {	
        res.status(200).json({"return value ": "Your first successful Microservice End Point"})
    }
    exports.RouteGetSomething = function(req,res)
    {
        console.log(JSON.stringify(req.params));
        res.status(200).json({"params":req.params});
    }
    exports.RoutePostSomething = function(req,res)
    {
        res.status(200).json({"params=":req.params,"body":req.body});
    }
    exports.RouteDeleteSomething = function(req,res)
    {
        res.status(200).json({"params":req.params});
    }
    exports.RoutePutSomething = function(req,res)
    {
        res.status(200).json({"params=":req.params,"body":req.body});
    }
    
    
  • The format of the params and body in case of POST and PUT methods, initoptions, and even response json, can be specified as json-schema object. This helps in documenting the REST API signatures. cirruswave automatically validates the params and body portions of the request at runtime against the schema and generated errors.
  • optionschema
    If you have an init section in defining a service in serviceconfig, you can add optionschema section defining the constraints on the json that can be passed.
  • paramschema
    This may be present in each route. params and queries are covered by this. In general, it's advised that you follow the REST API convension of resourceurl format.
  • bodyschema
    This may be present in each route but only for REST methods POST or PUT. This defines the json-schema for the payload that needs to be passed in the request body.
  • responseschema
    This may be present in each route. This defines the json-schema for the json added to the response. This is not important to have and can only serve to enforce the schema during development phase as it's part of the response object.
  • As mentioned before in the appserviceconfig section, key based security comes in three forms 1. no key, 2. appkey, 3. basic and 4.acckey
  • nokey
    This is simple. Anyone can call the API. If your API is public then this is a fine option.
  • appkey
    The key in appserviceconfig can have a secret key value. If you don't specify one, a random key will be generate for you and added to your appserviceconfig when the service is first launched. Anyone who has access to the key value, can pass it in the http header under the name <servcicename>-api-key e.g. if you have a service by name sampleservice the key will be in the header under name sampleservice-api-key
  • basic
    This takes in an access key and a security key, in place of user name and password. The combination of the two keys will be encoded using base64 as per the Basic access authentication protocol. Each developer that is given access to the api will be issued an accesskey and a secretkey. These keys are issued by keymgr service and also authenticated by keymgr. See systemservice keymgr below for details on usage and also how to generate the authorization header to call the service.
  • acckey
    This provides the highest form of security. Currently only hmac authentication header is supported. This means, it's encrypted and signed. Each developer that is given access to the api will be issued an accesskey and a secretkey. These keys are issued by keymgr service and also authenticated by keymgr. See systemservice keymgr below for details on usage and also how to generate the basic or hmac auth header to call the service.
  • SSL certificates are needed when you use https as the protocol in appserviceconfig. The following outlines how you accomplish this
  • Production certifcate
    For your domain you have to get an ssl certicate. Talk to your IT department about this or consult a certifcate authority like verisign
  • Test Certificate
    In node_modules/cirruswave/security directory there is file clientcert.sh. You can use this to generate the test ssl certificate. 'bash clientcert.sh -n purpleguard -d localhost -o <servicename>' will generate <servicename>.crt and <servicename>.key. Note purpleguard is the test certificate authority.
  • Storing the certificates
    The certicate (.crt, .key) files needs to be placed where your cirruswave can access it on your service's behalf
  • Enable SSL
    In the appserviceconfig set 'protocol' to https and set 'certPath' to the fully qualified name to the .crt file
  • CirrusWave offers various standard services out of the box which helps accelerate development, deployment and securing microservices
  • keymgr
    helps provide programatic authentication and authorization for application services
  • connector
    helps connect to desparate data sources abd access data from any service in a uniform manner
  • converter
    offers document conversion service from one format to another. As an example, you an send an EDI document and translate it to JSON, extract tables and lists from HTML documents into json document, from the json convert to CSV for uploading to a sql database
  • workflow
    full featured workflow development framework based on json and designed to work with REST api and microservices. Enterprises can now focus on business logic they need to do in the application services instead of the logistics of wiring the microservices
  • System service 'keymgr' helps you to provide key management services for your client and also enables automatic key validation.
  • 'keymgr' service offers routes to allocate keys to clients and grant them access to various services.
  • 'keymgr' service provides routes to revoke keys, get keys on behalf of a client, check grants etc.
  • cirruswave platform provides automatic validation of keys using keymgr service for the application services that have the 'security' set to 'basic' or 'acckey'.
  • You have to provide the front-end to authenticate your clients and manage keys
  • Following are important routes for the 'keymgr' service. There are a lot more routes for which please refer to the config given further below.
RoutemethodDescriptionParameterspayloadresponse
/clients/:clientidGETGet client info from clientid
{"chlientid":"[any integer]"}
{"acckey":"[access key]","secret":"[secret key]", "services":"[array of services that this acceky is granted access to]"}
/clients/:clientidPUTAllocate Keys for a client identified by clientid
{"chlientid":"[any integer]"}
{"acckey":"[access key]","secret":"[secret key]", "services":"[array of services that this acceky is granted access to]"}
/grants/:servicename/acckeys/:acckey/POSTGrant access to service identified by service name for the acckey
{"servicename":"[name of the service to grant access to]", "acckey":"[access key]"}
{"acckey":"[access key]","secret":"[secret key]", "services":"[array of services that this acceky is granted access to]"}
/grants/:servicename/acckeys/:acckey/GETCheck acckey has access to the service
{"acckey":"[access key]"}
{"acckey":"[access key]","secret":"[secret key]", "services":"[array of services that this acceky is granted access to]"}
/grants/acckeys/:acckey/GETGet services acckey has access to
{"acckey":"[access key]"}
[array of services that this acceky is granted access to]
  • Here is the config file for 'keymgr' service which lists the routes and what they are used for. Each route in this is described in detail.
  • {
      "servicename": "keymgr",
      "routes": [
        {
          "route": "/clients/:clientid",
          "configured": true,
          "type": "get",
          "routeclass": "./apikeymgr.js",
          "routefunction": "RouteGetClientFromClientid",
          "description": "Get client info from clientid1",
          "paramschema": {
            "required": [
              "clientid"
            ],
            "type": "object",
            "properties": {
              "clientid": {
                "description": "the clientid",
                "type": [
                  "integer",
                  "string"
                ]
              }
            }
          },
          "examples": [
            {
              "param": "/clients/1"
            },
            {
              "param": "/clients/a1"
            }
          ]
        },
        {
          "route": "/clients/:clientid",
          "configured": true,
          "type": "put",
          "routeclass": "./apikeymgr.js",
          "routefunction": "RouteAllocateAccessKeys",
          "description": "Allocate Keys for a client identified by clientid",
          "paramschema": {
            "required": [
              "clientid"
            ],
            "type": "object",
            "properties": {
              "clientid": {
                "description": "the clientid",
                "type": "integer"
              }
            }
          },
          "examples": [
            {
              "param": "/clients/1"
            }
          ]
        },
        {
          "route": "/clients/:clientid",
          "configured": true,
          "type": "delete",
          "routeclass": "./apikeymgr.js",
          "routefunction": "RouteRevokeClient",
          "description": "Delete a client identified by clientid",
          "paramschema": {
            "required": [
              "clientid"
            ],
            "type": "object",
            "properties": {
              "clientid": {
                "description": "the clientid",
                "type": "integer"
              }
            }
          },
          "examples": [
            {
              "param": "/clients/1"
            }
          ]
        },
        {
          "route": "/acckeys/:acckey/",
          "configured": true,
          "type": "get",
          "routeclass": "./apikeymgr.js",
          "routefunction": "RouteGetClientFromAcckey",
          "description": "Get client info from acckey",
          "paramschema": {
            "required": [
              "acckey"
            ],
            "type": "object",
            "properties": {
              "acckey": {
                "description": "access key of the client",
                "type": "string"
              }
            }
          },
          "examples": [
            {
              "param": "/acckeys/"
            }
          ]
        },
        {
          "route": "/grants/check",
          "configured": true,
          "type": "post",
          "routeclass": "./apikeymgr.js",
          "routefunction": "RouteCheckAccessOneService",
          "description": "Authenticate and Check acckey has access to the service",
          "bodyschema": {
            "required": [
              "headers",
              "servicename"
            ],
            "type": "object",
            "properties": {
              "headers": {
                "description": "headers",
                "type": "object",
                "required": [
                  "authorization"
                ],
                "properties": {
                  "authroization": {
                    "type": "string",
                    "description": "auth header basic or hmac"
                  },
                  "date": {
                    "type": "string"
                  }
                }
              },
              "servicename": {
                "description": "The service name",
                "type": "string"
              }
            }
          },
          "examples": [
            {
              "param": "/grants/check",
              "payload": {
                "headers": {
                  "authorization": "auth header basic or hmac",
                  "date": "date"
                },
                "servicename": "sampleserviceacckey"
              }
            }
          ]
        },
        {
          "route": "/grants/checkjwt",
          "configured": true,
          "type": "post",
          "routeclass": "./apikeymgr.js",
          "routefunction": "RouteCheckJWTAccessOneService",
          "description": "Check JWT to see if the service has access to the service, if servicename is not given it expects to just decode the token and return.",
          "bodyschema": {
            "required": [
              "headers"
            ],
            "type": "object",
            "properties": {
              "headers": {
                "description": "headers",
                "type": "object",
                "required": [
                  "authorization"
                ],
                "properties": {
                  "authroization": {
                    "type": "string",
                    "description": "auth header bearer with jwt"
                  }
                }
              },
              "servicename": {
                "description": "the name of the service",
                "type": "string"
              }
            }
          },
          "examples": [
            {
              "param": "/grants/checkjwt",
              "payload": {
                "headers": {
                  "authorization": "auth header bearer with jwt"
                },
                "servicename": "sampleservicejwt"
              }
            }
          ]
        },
        {
          "route": "/grants/:servicename/acckeys/:acckey/",
          "configured": true,
          "type": "get",
          "routeclass": "./apikeymgr.js",
          "routefunction": "RouteGetAccessOneService",
          "description": "Check acckey has access to the service",
          "paramschema": {
            "required": [
              "servicename",
              "acckey"
            ],
            "type": "object",
            "properties": {
              "servicename": {
                "description": "the name of the service",
                "type": "string"
              },
              "acckey": {
                "description": "the acckey",
                "type": "string"
              }
            }
          },
          "examples": [
            {
              "param": "/grants/machineconfig/acckeys/"
            }
          ]
        },
        {
          "route": "/grants/:servicename/acckeys/:acckey/",
          "configured": true,
          "type": "post",
          "routeclass": "./apikeymgr.js",
          "routefunction": "RouteGrantAccess",
          "description": "Grant access to service for acckey",
          "paramschema": {
            "required": [
              "servicename",
              "acckey"
            ],
            "type": "object",
            "properties": {
              "servicename": {
                "description": "the name of the service to grant access to",
                "type": "string"
              },
              "acckey": {
                "description": "the acckey",
                "type": "string"
              }
            }
          },
          "examples": [
            {
              "param": "/grants/machineconfig/acckeys/acckeyvalue"
            }
          ]
        },
        {
          "route": "/grants/:servicename/acckeys/:acckey/",
          "configured": true,
          "type": "delete",
          "routeclass": "./apikeymgr.js",
          "routefunction": "RouteRevokeAccess",
          "description": "Revoke access to service for acckey",
          "paramschema": {
            "required": [
              "servicename",
              "acckey"
            ],
            "type": "object",
            "properties": {
              "servicename": {
                "description": "the name of the service to grant access to",
                "type": "string"
              },
              "acckey": {
                "description": "the acckey",
                "type": "string"
              }
            }
          },
          "examples": [
            {
              "param": "/grants/machineconfig/acckeys/acckeyvalue"
            }
          ]
        },
        {
          "route": "/grants/acckeys/:acckey/",
          "configured": true,
          "type": "get",
          "routeclass": "./apikeymgr.js",
          "routefunction": "RouteGetAccessServices",
          "description": "Get services acckey has access to",
          "paramschema": {
            "required": [
              "acckey"
            ],
            "type": "object",
            "properties": {
              "acckey": {
                "description": "the acckey",
                "type": "string"
              }
            }
          },
          "examples": [
            {
              "param": "/grants/acckeys/acckeyvalue"
            }
          ]
        },
        {
          "route": "/acckeys/:acckey/jwt",
          "configured": true,
          "type": "post",
          "routeclass": "./apikeymgr.js",
          "routefunction": "RoutePostJWT",
          "description": "Create JWT given acckey and secret. Use normal route to create access key and secret key for a given client id. Then you can use these to procure the Json Web Token. Pass the token in http header as 'Authorization: Bearer ' when using curl or postman or use the test framework to pass the token",
          "paramschema": {
            "required": [
              "acckey"
            ],
            "type": "object",
            "properties": {
              "acckey": {
                "description": "the acckey",
                "type": "string"
              }
            }
          },
          "bodyschema": {
            "required": [
              "secretkey"
            ],
            "type": "object",
            "properties": {
              "secretkey": {
                "description": "Secret key for authentication, corresponding to the acckey",
                "type": "string"
              },
              "secret": {
                "description": "Secret to sign the JWT with",
                "type": "string"
              },
              "expires": {
                "description": "expiry of this jwt in seconds, default is 3600 secs (1 hour)",
                "type": "integer",
                "minimum": 60,
                "maximum": 2592000
              },
              "sub": {
                "description": "subject matter for this JWT",
                "type": "string"
              },
              "claims": {
                "type": "object",
                "properties": {
                  "services": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "scope": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "examples": [
            {
              "param": "/acckeys/acckeyvalue/jwt",
              "payload": {
                "secretkey": "secretkey",
                "secret": "helloworld",
                "expires": 600,
                "sub": "TestofJWT",
                "claims": {
                  "services": [
                    "sampleservicejwt"
                  ],
                  "scope": [
                    "read:foo",
                    "write:bar"
                  ]
                }
              }
            },
            {
              "param": "/acckeys/acckeyvalue/jwt",
              "payload": {
                "secretkey": "secretkey",
                "expires": 600,
                "sub": "TestofJWT"
              }
            }
          ]
        },
        {
          "route": "/jwts/:jwt",
          "configured": true,
          "type": "get",
          "routeclass": "./apikeymgr.js",
          "routefunction": "RouteVerifyJWT",
          "description": "Verify JWT and return the payload",
          "paramschema": {
            "required": [
              "jwt"
            ],
            "type": "object",
            "properties": {
              "jwt": {
                "description": "JWT token value",
                "type": "string"
              },
              "secret": {
                "description": "Optiommal query parameter secret to sign the JWT with",
                "type": "string"
              }
            }
          },
          "examples": [
            {
              "param": "/jwts/jwtoken?secret=helloworld"
            },
            {
              "param": "/jwts/jwtoken"
            }
          ]
        }
      ],
      "loglevel": "trace"
    }
  • Workflow service
  • Workflow service organizes the logic that wires and connects various microservices under a plan
  • A plan consists of various tasks that can be executed asynchronously.
  • A plan also consists of flow of execution of the tasks
  • Task is either a service or a REST endpoint
  • A service is defined as either systemservice or application service. Service is identified by name, route and method which is one of GET, POST, PUT, or DELETE.
  • A REST endpoint is identified by a url and method (GET, POST, PUT, DELETE)
  • Workflow service provides constructs to define the logical flow of execution of services like nextTasks, synch
  • Each plan consists of various tasks. Tasks execute specific methods on either a microservice or a REST endpoint
    • plan
    • Plan has the following attributes
    • priority - priority of the plan a number between 0 and 1000. Lower the number higher the priority
    • interval - 0 for non-repeating plans. A number greater than 0 represents the interval milliseconds that the job or plan repeats. Note the plan will repeat only at the next interval opportunity after it completes execution
    • start - the starting task for the plan. This is the task that will execute when the plan status is changed to start
    • taskjson - an object that has named tasks. Each entry is an object with a name. Structure of a task is described further below
    • example - Below is a very simple plan. This plan has two tasks task0 andn task1. It starts with task0 and on successful completion (meaning http status response code 200) of task0, will execute the nextTasks list. In this case it will execute task1
    • {
        "planname": "plan1",
        "start": "task0",
        "priority": 100,
        "interval": 0,
        "taskjson": {
          "task0": {
            "service": "taskserver",
            "servicepath": "task0",
            "method": "GET",
            "nextTasks": [
              "task1"
            ]
          },
          "task1": {
            "service": "taskserver",
            "servicepath": "task1",
            "method": "GET"
          }
        }
      }
    • Taskjson
    • Each task in taskjson name with a value which is json. A task has the following attributes
    • service - the name of the service e.g. converter
    • servicepath - the path to the particular route e.g. /converter/v1/htmltojson
    • url - the url to the REST end point if service and servicepath are not set. e.g. https://localhost:4008/converter/v1/htmltojson
    • method - the REST method GET, POST, PUT, DELETE
    • nextTasks - array of tasks that can be executed after this task completes successfully
    • arrStatus - a task is successfully completed if it responds with a status 200. If for some reason the task responds with other status codes indicating success, these can be listed in this array. e.g. [201, 202]
    • switch - in place of nextTasks, you can provide a switch statement. Array of conditionals that are evaluated and whichever evaluates to true, the nexsTasks associated with this item are triggered
    • {
        "switch": [
          {
            "field": "address.city",
            "op": "==",
            "value": "NewYork",
            "nextTasks": [
              "task1",
              "task3"
            ]
          },
          {
            "default": true,
            "nextTasks": [
              "task2"
            ]
          }
        ]
      }
  • switch statement for nextTasks
exampleresponse or outputvar
{
  "switch": [
    {
      "field": "address.city",
      "op": "==",
      "value": "issaquah",
      "nextTasks": [
        "task00",
        "securetask1",
        "securetask2"
      ]
    },
    {
      "default": true,
      "nextTasks": [
        "task1"
      ]
    }
  ]
}
{
  "address": {
    "street": "2345 wisteria lane",
    "city": "issaquah"
  }
}
{
  "switch": [
    {
      "var": "task0response.address.city",
      "op": "==",
      "value": "issaquah",
      "nextTasks": [
        "task00",
        "securetask1",
        "securetask2"
      ]
    },
    {
      "default": true,
      "nextTasks": [
        "task1"
      ]
    }
  ]
}
{
  "task0response": {
    "address": {
      "street": "2345 wisteria lane",
      "city": "issaquah"
    }
  }
}
  • Here is the config file for 'keymgr' service which lists the routes and what they are used for. Each route in this is described in detail.
  • {
      "servicename": "keymgr",
      "routes": [
        {
          "route": "/clients/:clientid",
          "configured": true,
          "type": "get",
          "routeclass": "./apikeymgr.js",
          "routefunction": "RouteGetClientFromClientid",
          "description": "Get client info from clientid1",
          "paramschema": {
            "required": [
              "clientid"
            ],
            "type": "object",
            "properties": {
              "clientid": {
                "description": "the clientid",
                "type": [
                  "integer",
                  "string"
                ]
              }
            }
          },
          "examples": [
            {
              "param": "/clients/1"
            },
            {
              "param": "/clients/a1"
            }
          ]
        },
        {
          "route": "/clients/:clientid",
          "configured": true,
          "type": "put",
          "routeclass": "./apikeymgr.js",
          "routefunction": "RouteAllocateAccessKeys",
          "description": "Allocate Keys for a client identified by clientid",
          "paramschema": {
            "required": [
              "clientid"
            ],
            "type": "object",
            "properties": {
              "clientid": {
                "description": "the clientid",
                "type": "integer"
              }
            }
          },
          "examples": [
            {
              "param": "/clients/1"
            }
          ]
        },
        {
          "route": "/clients/:clientid",
          "configured": true,
          "type": "delete",
          "routeclass": "./apikeymgr.js",
          "routefunction": "RouteRevokeClient",
          "description": "Delete a client identified by clientid",
          "paramschema": {
            "required": [
              "clientid"
            ],
            "type": "object",
            "properties": {
              "clientid": {
                "description": "the clientid",
                "type": "integer"
              }
            }
          },
          "examples": [
            {
              "param": "/clients/1"
            }
          ]
        },
        {
          "route": "/acckeys/:acckey/",
          "configured": true,
          "type": "get",
          "routeclass": "./apikeymgr.js",
          "routefunction": "RouteGetClientFromAcckey",
          "description": "Get client info from acckey",
          "paramschema": {
            "required": [
              "acckey"
            ],
            "type": "object",
            "properties": {
              "acckey": {
                "description": "access key of the client",
                "type": "string"
              }
            }
          },
          "examples": [
            {
              "param": "/acckeys/"
            }
          ]
        },
        {
          "route": "/grants/check",
          "configured": true,
          "type": "post",
          "routeclass": "./apikeymgr.js",
          "routefunction": "RouteCheckAccessOneService",
          "description": "Authenticate and Check acckey has access to the service",
          "bodyschema": {
            "required": [
              "headers",
              "servicename"
            ],
            "type": "object",
            "properties": {
              "headers": {
                "description": "headers",
                "type": "object",
                "required": [
                  "authorization"
                ],
                "properties": {
                  "authroization": {
                    "type": "string",
                    "description": "auth header basic or hmac"
                  },
                  "date": {
                    "type": "string"
                  }
                }
              },
              "servicename": {
                "description": "The service name",
                "type": "string"
              }
            }
          },
          "examples": [
            {
              "param": "/grants/check",
              "payload": {
                "headers": {
                  "authorization": "auth header basic or hmac",
                  "date": "date"
                },
                "servicename": "sampleserviceacckey"
              }
            }
          ]
        },
        {
          "route": "/grants/checkjwt",
          "configured": true,
          "type": "post",
          "routeclass": "./apikeymgr.js",
          "routefunction": "RouteCheckJWTAccessOneService",
          "description": "Check JWT to see if the service has access to the service, if servicename is not given it expects to just decode the token and return.",
          "bodyschema": {
            "required": [
              "headers"
            ],
            "type": "object",
            "properties": {
              "headers": {
                "description": "headers",
                "type": "object",
                "required": [
                  "authorization"
                ],
                "properties": {
                  "authroization": {
                    "type": "string",
                    "description": "auth header bearer with jwt"
                  }
                }
              },
              "servicename": {
                "description": "the name of the service",
                "type": "string"
              }
            }
          },
          "examples": [
            {
              "param": "/grants/checkjwt",
              "payload": {
                "headers": {
                  "authorization": "auth header bearer with jwt"
                },
                "servicename": "sampleservicejwt"
              }
            }
          ]
        },
        {
          "route": "/grants/:servicename/acckeys/:acckey/",
          "configured": true,
          "type": "get",
          "routeclass": "./apikeymgr.js",
          "routefunction": "RouteGetAccessOneService",
          "description": "Check acckey has access to the service",
          "paramschema": {
            "required": [
              "servicename",
              "acckey"
            ],
            "type": "object",
            "properties": {
              "servicename": {
                "description": "the name of the service",
                "type": "string"
              },
              "acckey": {
                "description": "the acckey",
                "type": "string"
              }
            }
          },
          "examples": [
            {
              "param": "/grants/machineconfig/acckeys/"
            }
          ]
        },
        {
          "route": "/grants/:servicename/acckeys/:acckey/",
          "configured": true,
          "type": "post",
          "routeclass": "./apikeymgr.js",
          "routefunction": "RouteGrantAccess",
          "description": "Grant access to service for acckey",
          "paramschema": {
            "required": [
              "servicename",
              "acckey"
            ],
            "type": "object",
            "properties": {
              "servicename": {
                "description": "the name of the service to grant access to",
                "type": "string"
              },
              "acckey": {
                "description": "the acckey",
                "type": "string"
              }
            }
          },
          "examples": [
            {
              "param": "/grants/machineconfig/acckeys/acckeyvalue"
            }
          ]
        },
        {
          "route": "/grants/:servicename/acckeys/:acckey/",
          "configured": true,
          "type": "delete",
          "routeclass": "./apikeymgr.js",
          "routefunction": "RouteRevokeAccess",
          "description": "Revoke access to service for acckey",
          "paramschema": {
            "required": [
              "servicename",
              "acckey"
            ],
            "type": "object",
            "properties": {
              "servicename": {
                "description": "the name of the service to grant access to",
                "type": "string"
              },
              "acckey": {
                "description": "the acckey",
                "type": "string"
              }
            }
          },
          "examples": [
            {
              "param": "/grants/machineconfig/acckeys/acckeyvalue"
            }
          ]
        },
        {
          "route": "/grants/acckeys/:acckey/",
          "configured": true,
          "type": "get",
          "routeclass": "./apikeymgr.js",
          "routefunction": "RouteGetAccessServices",
          "description": "Get services acckey has access to",
          "paramschema": {
            "required": [
              "acckey"
            ],
            "type": "object",
            "properties": {
              "acckey": {
                "description": "the acckey",
                "type": "string"
              }
            }
          },
          "examples": [
            {
              "param": "/grants/acckeys/acckeyvalue"
            }
          ]
        },
        {
          "route": "/acckeys/:acckey/jwt",
          "configured": true,
          "type": "post",
          "routeclass": "./apikeymgr.js",
          "routefunction": "RoutePostJWT",
          "description": "Create JWT given acckey and secret. Use normal route to create access key and secret key for a given client id. Then you can use these to procure the Json Web Token. Pass the token in http header as 'Authorization: Bearer ' when using curl or postman or use the test framework to pass the token",
          "paramschema": {
            "required": [
              "acckey"
            ],
            "type": "object",
            "properties": {
              "acckey": {
                "description": "the acckey",
                "type": "string"
              }
            }
          },
          "bodyschema": {
            "required": [
              "secretkey"
            ],
            "type": "object",
            "properties": {
              "secretkey": {
                "description": "Secret key for authentication, corresponding to the acckey",
                "type": "string"
              },
              "secret": {
                "description": "Secret to sign the JWT with",
                "type": "string"
              },
              "expires": {
                "description": "expiry of this jwt in seconds, default is 3600 secs (1 hour)",
                "type": "integer",
                "minimum": 60,
                "maximum": 2592000
              },
              "sub": {
                "description": "subject matter for this JWT",
                "type": "string"
              },
              "claims": {
                "type": "object",
                "properties": {
                  "services": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "scope": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "examples": [
            {
              "param": "/acckeys/acckeyvalue/jwt",
              "payload": {
                "secretkey": "secretkey",
                "secret": "helloworld",
                "expires": 600,
                "sub": "TestofJWT",
                "claims": {
                  "services": [
                    "sampleservicejwt"
                  ],
                  "scope": [
                    "read:foo",
                    "write:bar"
                  ]
                }
              }
            },
            {
              "param": "/acckeys/acckeyvalue/jwt",
              "payload": {
                "secretkey": "secretkey",
                "expires": 600,
                "sub": "TestofJWT"
              }
            }
          ]
        },
        {
          "route": "/jwts/:jwt",
          "configured": true,
          "type": "get",
          "routeclass": "./apikeymgr.js",
          "routefunction": "RouteVerifyJWT",
          "description": "Verify JWT and return the payload",
          "paramschema": {
            "required": [
              "jwt"
            ],
            "type": "object",
            "properties": {
              "jwt": {
                "description": "JWT token value",
                "type": "string"
              },
              "secret": {
                "description": "Optiommal query parameter secret to sign the JWT with",
                "type": "string"
              }
            }
          },
          "examples": [
            {
              "param": "/jwts/jwtoken?secret=helloworld"
            },
            {
              "param": "/jwts/jwtoken"
            }
          ]
        }
      ],
      "loglevel": "trace"
    }
  • appserviceconfig.json
  • Create an appserviceconfig.json
  • The sampleservice listens to port 8888
  • create a folder called security add a self-signed certificate called sampleservice.crt and .key files
  • create a folder called images and add favicon.png to this directory
  • {
      "about": {
        "faviconurl": "/images/favicon.png",
        "imageurl": "/sampleservice/images/favicon.png",
        "name": "SampleService",
        "url": "/documentation",
        "description": "Sample services provided as documentation"
      },
      "services": {
        "sampleservice": {
          "init":{
            "class": "sampleservice.js",
            "function": "initialize"
          },
          "protocol": "https",
          "port": 8888,
          "hostname": "localhost",
          "certPath": "security/sampleservice",
          "description": "REST END POINT For Sample Service with no security restrictions",
          "configfilepath": "./appconfig.json",
          "security": "nokey"
        }
      }
    }
    
  • appconfig.json
  • Create an appconfig.json
  • Add the static route for images/favicon.png
  • Add 4 routes for GET, POST, PUT and DELETE methods
  • {
      "loglevel": "trace",
      "servicename": "sampleservice",
      "routes": [
        {
          "route": "/images",
          "type": "static",
          "configured": true,
          "routeclass": "./images",
          "description": "app specific images are served from the directory ./images under route /sampleservice/images"
        },
        {
          "route": "/sampleservice/images",
          "type": "static",
          "configured": true,
          "routeclass": "./images",
          "description": "app specific images are served from the directory ./images under route /sampleservice/images"
        },
        {
          "route": "/",
          "type": "get",
          "configured": true,
          "routeclass": "./sampleservice.js",
          "routefunction": "Root",
          "description": "Your first Microservice end point"
        },
        {
          "route": "/values/:value",
          "type": "get",
          "configured": true,
          "routeclass": "./sampleservice.js",
          "routefunction": "RouteGetSomething",
          "description": "A room with a view",
          "paramschema": {
            "type": "object",
            "required": [
              "value"
            ],
            "properties": {
              "value": {
                "description": "value e.g. any string",
                "type": "string"
              }
            }
          },
          "examples": [
            {
              "param": "/values/samplestring"
            }
          ]
        },
        {
          "route": "/values/:value",
          "type": "post",
          "configured": true,
          "routeclass": "./sampleservice.js",
          "routefunction": "RoutePostSomething",
          "description": "post example",
          "paramschema": {
            "type": "object",
            "required": [
              "value"
            ],
            "properties": {
              "value": {
                "description": "value e.g. any string",
                "type": "string"
              }
            }
          },
          "bodyschema": {
            "type": "object"
          },
          "examples": [
            {
              "param": "/values/samplestring",
              "payload": {
                "data": "test data for post"
              }
            }
          ]
        },
        {
          "route": "/values/:value",
          "type": "delete",
          "configured": true,
          "routeclass": "./sampleservice.js",
          "routefunction": "RouteDeleteSomething",
          "description": "delete example",
          "paramschema": {
            "type": "object",
            "required": [
              "value"
            ],
            "properties": {
              "value": {
                "description": "value e.g. any string",
                "type": "string"
              }
            }
          },
          "examples": [
            {
              "param": "/values/samplestring"
            }
          ]
        },
        {
          "route": "/values/:value",
          "type": "put",
          "configured": true,
          "routeclass": "./sampleservice.js",
          "routefunction": "RoutePutSomething",
          "description": "put example",
          "paramschema": {
            "type": "object",
            "required": [
              "value"
            ],
            "properties": {
              "value": {
                "description": "value e.g. any string",
                "type": "string"
              }
            }
          },
          "bodyschema": {
            "type": "object"
          },
          "examples": [
            {
              "param": "/values/samplestring",
              "payload": {
                "data": "test data for put"
              }
            }
          ]
        }
      ]
    }
  • sampleservice.js
  • Create the file that implements business logic - sampleservice.js
  • Each of the routes simply responds with the params and body of the request
  • exports.initialize = function()
    {
        console.log("initialized");
    }
    exports.Root = function(req,res)
    {	
        res.status(200).json({"return value ": "Your first successful Microservice End Point"})
    }
    exports.RouteGetSomething = function(req,res)
    {
        console.log(JSON.stringify(req.params));
        res.status(200).json({"params":req.params});
    }
    exports.RoutePostSomething = function(req,res)
    {
        res.status(200).json({"params=":req.params,"body":req.body});
    }
    exports.RouteDeleteSomething = function(req,res)
    {
        res.status(200).json({"params":req.params});
    }
    exports.RoutePutSomething = function(req,res)
    {
        res.status(200).json({"params=":req.params,"body":req.body});
    }
    
    
  • sampleservice_index.js
  • Create a javascript that launches the sampleservice - sampleservice_index.js
  • var app = require("cirruswave");
    app.startservice("sampleservice", __dirname, "appserviceconfig.json");
    
    
    
    
  • Invoke a service REST endpoint
  • CirrusWave provides helper functions to invoke any rest api or cirruswave service
  • There are two main functions to invoke REST api. Wofklow service internally also uses the same functions to chian tasks
  • ExecuteTask and PromiseTask - Both take a task object like the workflow, if successful return data in the response or error if error
  • PromiseTask
  • Takes a single object task as parameter
  • {
      "service": "servicename",
      "servicepath": "route",
      "appserviceconfig": "path to appserviceconfig.json",
      "payload": "the body of the request"
    }
  • then(data) - where data is the response object from the service
  • catch(err) - where err is the error object. It has the status and the message
    • example - simple promise
    • The snippet below a simple example of how PromiseTask can be invoked
    • const app = require("cirruswave");
      
      var task = {
          "service": "sampleservice",
          "servicepath": "/values/sample",
          "appserviceconfig": "./appserviceconfig.json",
          "payload": {
              "data": {
                  "foo": "bar",
                  "bar": "foobar"
              },
              "test": " This is a test"
          },
          "method": "POST"
      }
      app.PromiseTask(task)
          .then(data => {
              console.log(JSON.stringify(data, 0, 2));
          })
          .catch(err => {
              console.log(JSON.stringify(err, 0, 2));
          })
      
      
    • example - promise all
    • The snippet below is an example of PromiseTask invoked with multiple payloads. The code executes the task in parallel for multiple payloads and combines the responses in an array. Helps you execute something when all the promises are resolved.
    • const app = require("cirruswave");
      
      var payloads = [
          { "foo": "bar1" },
          { "foo": "bar2" },
          { "foo": "bar3" }
      ]
      var promises = [];
      for (var p of payloads) {
          var task = {
              "service": "sampleservice",
              "servicepath": "/values/sample",
              "appserviceconfig": "./appserviceconfig.json",
              "payload": p,
              "method": "POST"
          }
      
          promises.push(app.PromiseTask(task));
      }
      Promise.all(promises)
          .then(data => {
              console.log("promiseall example")
              console.log(JSON.stringify(data, 0, 2));
          })
          .catch(err => {
              console.log(JSON.stringify(err, 0, 2));
          })
      
      
      
    • example
    • The snippet below a chianed execution of PromiseTask. Here it returns a promise to another promise, creating a chain of promises
    • const app = require("cirruswave");
      var task1 = {
          "service": "sampleservice",
          "servicepath": "/values/sample",
          "appserviceconfig": "./appserviceconfig.json",
          "payload": {
              "promise": "first one"
          },
          "method": "POST"
      }
      var task2 = {
          "service": "sampleservice",
          "servicepath": "/values/sample",
          "appserviceconfig": "./appserviceconfig.json",
          "payload": {
              "promise": "2nd one one"
          },
          "method": "POST"
      }
      
      app.PromiseTask(task1)
      .then(data1 => {
          console.log("chained promise example chain1 starting")
          console.log(JSON.stringify(data1, 0, 2));
          console.log("chain1")
          return app.PromiseTask(task2);
      })
      .then(data2 => {
          console.log("chained promise example chain2 starting")
          console.log(JSON.stringify(data1, 0, 2));
          console.log("chain2")
      })
      .catch(err => {
          console.log(JSON.stringify(err, 0, 2));
      })