mattbriggs

Function to Microservice with the Nintex Workflow Platform

Blog Post created by mattbriggs Employee on Feb 17, 2017

One way of looking at extending the Nintex Workflow Platform is to focus on the smallest unit of processing: the function.

 

This series of posts will look at how you can approach your function as a portable unit in the Nintex Workflow Platform. I'm going to look at defining the boundaries of your function, what you need to host your function, how the Nintex Workflow Platform can help delivery your function to workflow designers in your enterprise, and how you can set up the interfaces to your function to deliver your solution to targets inside and outside of your network.

 

Table of Contents

Smallest Meaningful Process

You can think of your function has a self-contained thing in the Nintex Workflow Platform. As a self-contained thing it is portable. All that you need to execute your function is a runtime. The function can execute inside of the Nintex Workflow Platform within a workflow, or it can run outside of the Nintex Workflow Platform as a web service that can be incorporated back into your workflows using the Web request action.

 

Inside the Nintex Workflow Platform

If you're working with a SharePoint instance that doesn't have an internet connection (for security reasons or maybe it is beyond the reach of the Internet) you can place your function into the SharePoint runtime. You have two options for this: inline functions or custom workflow actions.

 

Inline functions

In any text input that supports Inserting reference fields, an inline function can be entered that will resolve at workflow runtime. You can create your function, add your function the DLLs that contain your function namespace to your SharePoint environment, and then register the function using the Nintex Workflow Administration tool.

 

Workflow actions

Workflow actions appear in the toolbox in the workflow designer. A builder of workflows can drag and drop the action onto the control flow of the workflow, double-click the action to configure the action, and then access the action when running the workflow. You can add your function to your a custom workflow action project using the Nintex Workflow SDK and give builders of workflows access to the processing of your function within their workflows using the workflow designer.

 

Outside Nintex Workflow Platform

You can host your function external to the SharePoint runtime. For instance you can provision your function as an endpoint to a web service running in the cloud, and then you can access the endpoint using the the Web request action. This has the benefit of locating your code in a single accessible location. If you maintain the endpoint contract, you can update your code, or even swap out the entire code base of your function without disturbing the delivery of your function. From your service, users can access the processing of your function from each of Nintex workflow products, such as Nintex Workflow for Office 365 and Nintex Workflow Cloud, using the Web Request action. 

 

Wrapping Your Function and Supporting Complexity

Another factor in considering in the portability of your function is that you have two main ways of adding and then wrapping any complexity supporting your function:

  • using user defined actions to contain a workflow supporting your function
  • adding a RESTful interface to your a workflow supporting your function

 

With Nintex Workflow 2013/2016, you can place a container around your custom action and its supporting actions as a user defined action that will show up in the Workflow Designer like any other action. You can add a custom action containing your function to a workflow that may add a Beacon action for monitoring the use of your function using Nintex Hawkeye, a function that writes to a log, and logic to handle errors or unexpected events.To interact with the user defined action, a user just needs to know the input parameter and the expected return. 

 

With Nintex Workflow 2013 Enterprise Edition or Nintex Workflow Cloud, you can add a RESTful endpoint that can accept a JSON payload contain workflow variables. The workflow's complexity supporting your function can be concealed behind the REST interface. To interact with the external-start enabled workflow, a user just needs to know the endpoint, the input payload, and the expected return.

 

Let's turn back to the console application as the place to develop your a process that you would like to share with users of your custom inline function, actions, and services.

 

Rise of the Lowly Console Application

 

A function in its most primitive form is a fragment of code that takes an input, performs some processing on this input, and then produces a return. Nearly every book on the syntax of a computer programming language begins with the "Hello Word" example. Often in the introduction on how the language implements functions, the primer includes a variety of the hello world function where you pass input into the function, and then produce the output, of "Hello <parameter>."

 

For example in JavaScript this might look like:

 

var hello = function (input) {
    var output = "Hello " + input;
    alert(output);
}

 

Function Console Application

 

A console application can be run on your local machine.

 

In our example, we are looking at a console application that converts JSON to XML, or XML to JSON. The console application takes in a local file, and save a local file. The meat of the functioning is contained in its own class.

 

In this sense the console application focuses on the delivery of a single bit of processing. It may have supporting methods, but is basically a stateless, static 'chunk' of processing. Input goes in, is processed, and the product of the processing returned.

 

In creating your function, encapsulate in a class. This is not full on object orientation, but in this case you are not creating something as thoughtful or heavy weight as an object model, but rather creating a tiny fragment of processing in response likely to some need. The mode here is a more retrograde, back to the days of BASIC's GOTO and essentially procedural. You are keeping it simple. Complexity will come in this approach in at higher-levels where it may be more easily managed.

 

Set Up

  • Visual Studio

 

Steps

  1. Create a console application.
  2. Add the Newtonsoft JSON.NET library to the project references. 
  3. Create a class with a static method that accepts a value and produces a return.
  4. Instantiate the class in Program.cs in the Main() method.
  5. Pass the input into your object, and then handle the return.

 

Code (C#) Sample for a Function in a Console Application

Program.cs

using System;
using System.IO;

namespace JsonConverter
{
    class Program
    {
        /// <summary>
        /// A console application that converst from XML to JSON, or form JSON to XML.
        /// </summary>
        static void Main()
        {
            string inputtext = File.ReadAllText(@"/input.txt"); // add pathname to input file

               var conversion = new JsonConverterAction();
               string convertedtext = conversion.ConvertIt(inputtext);
               Console.Write(convertedtext);
               File.WriteAllText(@"/output.txt", convertedtext); //add pathname to output file
        }
     
    }
}

JsonConvertAction.cs

using System;
using System.IO;
using System.Xml;
using System.Xml.Linq;
using Newtonsoft.Json;

/// <summary>
/// Converts text form JSON to XML or from XML to JSON. The converter detects the first character in the string and then converst to XML or JSON.
/// <parameter>Input string (in either JSON or XML format.</parameter>
/// </summary>
namespace JsonConverter
{
    class JsonConverterAction
    {
        public string ConvertIt(string inputText)
        {
            var convertedtext = inputText.Trim();
            var firstChar = inputText[0].ToString();
            switch (firstChar)
            {
                case "1":
                case "<":
                    convertedtext = XmlToJson(convertedtext);
                    break;
                case "2":
                case "{":
                    convertedtext = JsonToXml(convertedtext);
                    break;
                case "3":
                case "[":
                    convertedtext = JsonToXml(convertedtext);
                    break;
                default:
                    convertedtext = JsonToXml(convertedtext);
                    break;
            }
            return convertedtext;
        }

        //Converts a JSON string to XML.
        public string XmlToJson(string inputXMLasString)
        {
            try
            {
                var outputJsonAsString = "";
                var xmldoc = new XmlDocument();
                xmldoc.LoadXml(inputXMLasString);
                outputJsonAsString = JsonConvert.SerializeXmlNode(xmldoc);

                return outputJsonAsString;
            }
            catch (Exception ex)
            {
                var expectmessage = ex.ToString();
                var
                    returnmessage = "JSON not valid. " + expectmessage;
                return returnmessage;
            }
        }

        //Converts an XML string to JSON.
        public string JsonToXml(string inputJSONasString)
        {
            try
            {
                var outputXmlAsString = "";
                XNode node = JsonConvert.DeserializeXNode(inputJSONasString, "Root");
                var stringWriter = new StringWriter();
                var xmlTextWriter = new XmlTextWriter(stringWriter);
                node.WriteTo(xmlTextWriter);
                outputXmlAsString = stringWriter.ToString();
                return outputXmlAsString;
            }
            catch (Exception ex)
            {
                var expectmessage = ex.ToString();
                var returnmessage = "JSON not valid. " + expectmessage;
                return returnmessage;
            }
        }
    }
}

 

 

Division of Concern

When developing an application, programmers often resort to the console application. We craft our function to operate in a predictable way and make sure it does what it is supposed to do: when you feed it a set of inputs, the function produces a range of usable outputs. We may optimize performance at this level, as well, or refactor the function as we refine our understanding of the problem and how the function delivers a solution. We want the function to produces what we expect it to produce. Developing a complex program is typically an aggregation of problems solved at this foundational level. More abstract constructs such as abstraction, encapsulation, and even object orientation work to extend and reuse solutions created at this primary level.

 

Beginning with a focus on a function that will work well as a portable function in the Nintex Workflow Platform, that is a static function that takes in a single input and produces a single output, helps you to maintain a focus on the division of concern. This function does this. Once this concern has been addressed in code, you can move to higher-level logic using Nintex Workflow. You can then add supporting logic such as handling state, errors, and monitoring tasks with other actions in the Nintex toolbox.

 

You can wrap this logic in a User Defined Action, or provide an interface through External Start. Or you can place your function in the cloud add your supporting logic in Nintex Workflow Cloud, and make it accessible via an External Start Event. When you couple this with cloud products such as Microsoft Azure's Functions (aka serverless functions), you have a tool set that allows you to focus your problem solving skills on first creating a function that produces useful and expected outputs, and then to re-purpose this function to accomplish more complex tasks.

 

And then when you begin to create a number of functions that have RESTful endpoints, you are beginning to create something that resembles a microservices platform. 

 

Functions with RESTful Endpoints are Microservices

A microservice is an element of a microservices architecture. A single service is a block in this complex pattern. At a basic level, a Nintex Workflow with a RESTful endpoint wrapping a function is an independent process accessible through a language-agnostic API. You can fire your function using Postman, JavaScript, Python, even a commandline utility such as cURL. As long as the interface remains the same, you can update the underpinnings or even refactor the entire workflow. The single service can serve as a modular block in a complex structure that emerges organically and rapidly from solving stakeholder problems and reusing your existing solutions.

 

A discussion of microservices typically talks about how to transition from a monolithic system that already exists. A process of building upward from function, to restful endpoints, to defined services may be thought of as a system of organic growth.

 

Where to Put Your Portable Function In the Nintex Workflow Platform

Option

Description

Function Console Application

A console application can be run on your local machine. It may prompt you for input, and then it will perform it's process, and return the result.

Inline Function with Nintex Workflow 2013

You can add an inline function in Nintex Workflow and Forms from the Insert Reference window in the designer. The function looks something like, fn-functioname(input).

Create a Custom Action in Nintex Workflow 2013

You can add an action in Nintex Workflow from the Workflow actions toolbox, and then configure the action in the designer. To create this, you will need to use the Nintex Workflow 2013 SDK.

Add a User Defined Action with Nintex Workflow 2013

You can add a  User Defined Action (UDA) form the Workflow actions toolbox, and then configure the UDA in the designer. A UDA supports an Input parameter and produces a result as an output parameter.

Add External Start with Nintex Workflow 2013

You can programmatically trigger a site workflow, that has the External Start feature enabled, using a REST end point. 

Add a function to the Cloud using Windows Azure Serverless Functions

A RESTful client can make a call with the endpoint with a JSON payload { "name' : "<totranslate"> }, and will get the result as a return.s the payload value through the method for your function, and then return the output of your function.

Add a RESTful end point to your function in NWC

A Restful client can make the call to the endpoint in NWC using an External Start Event. The end point includes a URL, a token, and accept the JSON payload with the start workflow variables. You can review the endpoint in NWC, by clicking […] in the workflow list, and selecting External Start URL.

Function to Microservice with the Nintex Platform

This series of posts will look at:

  1. Adding your function to Nintex Workflow 2013 as an inline function
  2. Adding our function to Nintex Workflow 2013 as a custom workflow action
  3. Wrapping your action in a user-defined action in Nintex Workflow 2013
  4. Adding a RESTful endpoint to a Function in Nintex Workflow 2013
  5. Adding Your Function to the Cloud as a Serverless Function in Azure
  6. Adding an External Start Event to your function Nintex Workflow Cloud

Outcomes