NAV Navbar
javascript

Introduction

Welcome to the Unity Platform SDK Documentation! Our goal is to provide any developer with an extensive set of tools to build new web applications, abstract data from existing architecture, and create powerful new experiences using the Unity Platform. You can check out our open source code on Github here.

About the Unity Platform

The Unity Platform journey began by providing a suite of applications that help reduce costs and risks involved with supply chain and project management. Unity does this by providing a uniform way of interconnecting existing systems or architecture, facilitating harvesting of data in high volumes for business analytics and intelligence. In doing so, Unity has helped leading organizations overcome the limitations of core legacy software and digitally transform.

Today, the Unity Platform is a comprehensive development environment that allows teams to build great software quickly and economically. Unity’s library of core development tools cover middleware, authentication, data abstraction, communication and much more, meaning that development teams can start writing business logic while Unity does the heavy lifting.

Benefits of the Unity Platform

Platform Orchestration

Unity utilizes Docker containers to isolate and efficiently manage each application. In doing so, we can boost development life cycles, reduce overall size of each application, and provide an added layer of security. We’ve chosen Kubernetes to orchestrate the Docker containers and ensure reliability plus scalability. A large benefit of using Kubernetes is that it comes with a rich ecosystem of tools that facilitate production operational management, as well as application development tooling.

One of these of these tools that is of particular note for Unity development is Minikube.

Extension Architecture

By leveraging GraphQL, Unity allows API consumers to make requests for custom payloads, related entities and multiple queries in a single API call. Unity builds upon GraphQL in ways that help accelerate development time and provide enterprise features, such as Role Based Access Control (RBAC). Unity can also automatically generated strongly typed where clauses in your schemas.

Additionally, extensions have the ability to:

Docker In Any Language

Our platform is language-agnostic due to the use of Docker, meaning we don’t constrict your development to one language (please note: currently there is only a Node.js SDK). Enjoy developing in your chosen language. Optionally, you can use the Node.js SDK to wrap around a CLI written in another language.

Security

Data sovereignty and security is inherent to each technology service provided by the Unity Platform. The Unity API provides a centralised point of control for Role Based Access Control (RBAC) and granular permissions in a multi-tenant environment. This means that all Queries and Mutations on the GraphQL API are secure by default and can be whitelisted to users across multiple authentication connections, provided by Auth0 (e.g. Active Directory or SAML 2.0). Permissions are grouped into internal security roles which apply to a tenant in the system, which can then be mapped to external security roles (which are also tenant scoped). Clients can choose any role names they like and apply permission sets to users/groups via their enterprise user directory so that they have full control and automatic user onboarding.

Omnichannel Communications

Unity provides a suite of tools that enable teams to communicate via multiple channels, accessible on a single viewing pane.

Examples of these channels that are provided and can be leveraged within the platform are:

Developer Tooling

Prerequisites / Setup

The Unity Platform brings together a collection of open-source tools that empower you to start building applications with very little time spent on infrastructure, authentication and security. You will however need to lay the foundations for these tools, which we have listed below:


Minikube

We use Minikube to run Kubernetes locally. Minikube is an open-source program intended to help developers build and test Kubernetes scenarios inside a single-node virtual machine. Installing Kubernetes is time-consuming and resource-intensive. With Minikube, you get a smaller working version of a single-node Kubernetes cluster on your personal computer.

Kubectl is a command line interface for running commands against Kubernetes clusters. You’ll need to understand how to use Kubectl in order to interact with Minikube.

Minikube Installation Guide

Kubectl reference


Docker

Docker is another open-source tool that is designed to simplify the management of applications. By isolating each application into its own “container” (similar to a Virtual Machine), development teams can undergo operations that target specific applications or tasks, without affecting the performance of other applications. To get started with Docker, check out their docs here.

Windows

https://docs.docker.com/v17.12/docker-for-windows/install/

Mac

https://docs.docker.com/v17.12/docker-for-mac/install/#download-docker-for-mac

Linux

https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-on-ubuntu-18-04


Node.js

We at Codafication are React and Node developers; leveraging these technologies allows us to turnover iterations rapidly. As Node is a JavaScript runtime, you can use the same language across both the frontend and backend, offering flexibility for development teams. You don’t need to use Node for your own development, however some of our tools make use of it. Node’s native package manager is NPM, which you may use if you like (we like to use Yarn). Check out the Node JS docs here.

https://nodejs.org/en/download/

Yarn

Yarn is a Javascript package manager that allows you to collaborate with other developers. We’ve chosen Yarn as it compiles modules neatly and offers user-friendly workspaces. You can get started with Yarn here.

TypeScript

Typescript is an extension to Javascript that adds static types, classes, modules, interfaces and generics. There are many benefits to using Typescript, notably the ability to reduce errors by implementing “static typing”, a feature that type checks as you write code. Typescript can compile down into regular Javascript; in doing so, it also types checks for errors. This also allows you to write code using functionality provided by newer versions of ecmascript and compile it to older versions. Check out their docs on getting started. here.


Tools

Codafication provides a set of tooling to assist development. There are tools dedicated to the setup of minikube and generation extension boilerplate based off a user-defined selection of technologies to help you integrate.

Create Extension CLI

Creates a basic frontend or backend extension, providing a selection of available technologies to be used or whatever

Minikube/kubectl setup scripts

Other Sections

Portal SDK

Unity’s front-end SDK is known as the Portal SDK. The Portal SDK is built in React JS and is designed to help save you time on building basic functions that drive building new web applications. Portal SDK handles authentication and user logins to the Unity Platform, and provide the following functionality:

UnitySDK - Frontend SDK

The UnitySDK wraps around your entire react application

import * as React from 'react'
import * as ReactDOM from 'react-dom'
import './index.css'
import App from './App'
import UnitySDK from '@teamcodafication/unity-portal-sdk'
ReactDOM.render(
  <UnitySDK redirect="quotes">
    <App />
  </UnitySDK>,
  document.getElementById('root') as HTMLElement
)

The frontend UnitySDK component wraps around your entire react application, providing a plethora of functionality that can be used within your application.

All authentication for your frontend extension is handled, including user login, token renewal and authorization for the included GraphQL Client which is used for making graphQL calls to the Unity platform.

Information about the current user and clients for GraphQL calls are passed down as props to the children, as such, it is recommended that your application stems from a base component from which these props can be used.

Prop Description
redirect The extension name as it appears in the url to redirect to. (Used to redirect on login)

Props passed to children

client & clientV2

Example Call

import { getUnityClientV2 } from "@teamcodafication/unity-portal-sdk";
import gql from "graphql-tag";

const getData = async (id, client) => {
  const query = gql`
    query user($id: ID!) {
      unityUser(id: $id) {
        user {
          id
          firstName
          lasttName
        }
      }
    }
  `;
  const results = await client.query({
    mutation,
    variables: {
      id
    }
  });

  return results;
};

Two graphQL clients are provided as props to child components wrapped in the UnitySDK Compoenents:

Methods

Method Description
query Returns a function that is used to do a GraphQL query call
mutate Returns a function that is used to do a GraphQL mutation call

Query and Mutation methods provided by the UnityClient both take virtually identical parameters:

Parameter Description
query A query or mutation as a standard GraphQL AST
arguments A JSON object (Shape dependant on Query/Mutation Input)

user

Users information takes the shape of a UnityUser.

Field Description
id The user's id - A UUID stored in Unity
firstName The user's first name
lastName The user's lastName
phoneNumber The user's phoneNumber
email The user's email
avatarUrl The Url of the user's avatar
company The user's current company
permissions A list of the user's permission

UnityBar

Including the UnityBar in your application


class App extends React.Component<any, State> {
  public render() {

    return (
      <>
        <UnityBar
          client={this.props.clientV2} // Passed down from SDK Wrapping component
          logo={{
            widthRatio: 4,
            marginLeft: 21,
            name: 'ExtensionName'
          }}
        />
        <YourReactApp />
      </>
    )
  }
}

The Unity platform contains a suite of modules that each serve a different function and can be easily interfaced across by the user. A UnityBar component is available for use, which provides the standard Unity navigation UI present across all core Unity applications. This is an easy way for your applications to remain visually consistent with the rest of the Unity platform.

Additionally, it provides functionality such as navigating between applications, User details, logout, integrations to support

Props

Details on the application's logo, specifically its positioning in the Unity Bar

Field Description
widthRatio A value to help resize the image
marginLeft The value of the logos's left margin
name The name of the extension - used to display the logo

client

An authenticated Unity Client, which is required to make requests to the Unity Platform.

This is given as a prop to children wrapped inside of the Unity SDK component; it can also be retrieved by importing the getUnityClient method.

getUnityClient

Import and usage

import { getUnityClientV2 } from "@teamcodafication/unity-portal-sdk";

const getData = async id => {
  const results = await getUnityClientV2().query({
    mutation,
    variables: {
      id
    }
  });
  return results;
};

You are also able to import a useable UnityClient, which is already authenticated, anywhere from within your application.

This is a function that returns a unityClient.

Unity SDK

Unity’s back-end SDK is known as the Unity SDK and is built using Node.js, a JavaScript runtime which allows JavaScript to be used for back end development. The Unity SDK has an extensive list of methods that enable developers to integrate into the Unity Platform.

Unity Client

The UnityClient handles the communication with the UnityPlatform. It also forms the basis of the architecture surrounding typical backend extensions, it is based off of graphql-yoga, a fully-featured GraphQL Server, which is itself also based on express, a very popular web framework for node.

It provides a suite of functionality for both communicating with the Unity Platform and exernal sources. This Includes:

Configuration

You will need to configure the Unity SDK before getting started. Please take the time to carefully read the methods below for setting up your access to the SDK. There are some basic requirements that you will need to get started

Example Configuration

import { Unity } from "@teamcodafication/unity-sdk";
import { env } from "./config";

const unity = new Unity({
  name: "extensionName",
  gatewayUrl: "http://core-kernel:8080",
  localSchemaUrl: "http://extensionName:8080",
  localPort: 8080,
  authenticationSecret: env.GENERIC_EXTENSION_SECRET
});

export default unity;
Field Description
name The name of the extension
gatewayUrl the location of the core-kernel that will be communicating with the extension. When the SDK is running inside of Unity, this will be"http://core-kernel:8080", otherwise it will be a full address if the SDK is running externally
localSchemaUrl The endpoint from which the GraphQL scheme will be served, typically "http://<extensionName>:8080"
localPort The local port, typically 8080
authenticationSecret A pre-shared key that is used by the extension to authenticate with the Unity platform for all requests and actions

GraphQL Client

Accessing the graphQLClient

export const graphqlClient = unity.client;

The UnityClient provides a graphql client which can be used to make graphQL requests. It is recommended that this be exported from the same location that the UnityClient is configured so that it can be accessed independently of the entire Unity instance. Authentication to the platform is already handled, being based off the configuration of the UnityClient.

request

Example graphqlRequest

const query = `
  query ($where: JSON) {
    allUnityUsers(where: $where) {
      users {
        firstName
        lastName
        email
        tenants {
          id
        }
        permissions
      }
    }
  }
`

const variables = {
  where: {
    firstName: {
      eq: "INSERT_FIRST_NAME"
    }
  }
}

const result = await graphqlClient.request(query, variables);

Used to make standard GraphQL requests. Both Queries and Mutations are supported.

Parameter Description
query The query/fields requested
variables A JSON object of the input for the query/mutation

rawRequest

const query = `
  query ($where: JSON) {
    allUnityUsers(where: $where) {
      users {
        firstName
        lastName
        email
        tenants {
          id
        }
        permissions
      }
    }
  }
`

const variables = {
  where: {
    firstName: {
      eq: "INSERT_FIRST_NAME"
    }
  }
}

const [data, extensions] = await graphqlClient.rawRequest(query, variables);

The request method will return the data or errors key from the response. If you need to access the extensions key you can use the rawRequest method

Parameter Description
query The query/fields requested
variables A JSON object of the input for the query/mutation

setHeader

Sets a single header for the GraphQL client

Parameter Description
key The header name
value The value of the header

setHeaders

Sets multiple headers for the GraphQL client. Takes an array of objects as an input.

Parameter Description
key The header name
value The value of the header

GraphQL Queries and Mutations

GraphQL is a modern querying language for API’s that is designed to accelerate web application development. As GraphQL doesn’t carry its own database, you will need to provide your own code and data to make requests to. GraphQL has the following definitive features:

Data Shape: when performing queries or mutations, you’ll notice that requests will be returned in the same structure that you made them. This will make it very easy for you to learn GraphQL if you haven’t used it before.

Single “Smart” Endpoint: Utilizing GraphQL means that you’ll be exposed to a singular endpoint, therefore your requests will need to follow a pre-defined type system to describe data. This in turn makes it easier to specify the exact data you need, aggregate data from multiple sources, and prevents over-fetching.

Strongly Typed: GraphQL is created by first defining “types”. Types are used to define sets of data or available fields in your server, so each GraphQL query will correspond to a type.

Inputs/Arguments can be provided in queries and mutations for narrowing down queries and as an input for modifying data respectively.

Nested Fields: GraphQL allows you to make requests to nested fields, hence making your requests very specific. Please note, you will not be able to provide arguments to nested fields for querying.

unity.setQueries({
  getHelloWorldMessage: {
    resolve: () => {
      const message = `Hello World!`;
      return {
        message: message
      };
    },
    type: new GraphQLObjectType({
      name: "HelloWorldMessage",
      fields: {
        message: {
          type: new GraphQLNonNull(GraphQLString)
        }
      }
    })
  }
});

Creating Queries and Mutations

setQueries

Use setQueries when you would like to fetch and read data. Unlike a Rest API, GraphQL allows a user to restrict fields in order to retrieve available fields with a shorter response time. You may also fetch related data in a single request. For example, if you would like to find a report, the details of the user that created the report and the company information of the user, you can do so.

setMutations

unity.setMutations({
  createItem: mutationWithClientMutationId({
    name: "CreateItem",
    inputFields: {
      item: { type: new GraphQLNonNull(CreateItemInput) }
    },
    outputFields: {
      item: { type: ItemGraphqlType }
    },
    mutateAndGetPayload: async input => {
      const item = createItem(input);

      return { item };
    }
  })
});

Use setMutations when you would like to modify data. It's important to remember that while you could theoretically use queries to modify data, it’s useful to adhere to a strict syntax when performing data writes. This will help reduce errors and provide an easy-to-follow framework.

GraphQL Extensions

unity.setLinks([
  {
    extendType: "Item",
    with: {
      field: "createdBy",
      ofType: "User",
      resolve: {
        queryName: "user",
        args: { id: "userId" }
      }
    }
  }
]);

Due to the modular nature of the Unity Platform, and GraphQL's requirement for one endpoint, GraphQL Schemas from each external extension are all collated into a central location in the platform. Collating these schemas on the fly allows for the ability to extend schemas and types.

setLinks is used, as the name suggests, to set links between GraphQL Schemas originating from two separate extensions.

This can be used to create schemas containing related types, nesting related data inside of eachother. This allows for the retrieval of multiple datasources in a single query, rather than having to make multiple API calls in order to fetch relevant information.

Example of setting a type extension

unity.setTypeExtensions([
  {
    extendType: {
      isInput: false,
        name: 'ItemType' // The target type to extend
      },
      with: {
        field: 'customData', // The name of the new field
        ofType: 'ItemCustomData' // Name of the
      }
    }]

setTypeExtensions

setTypeExtensions is similar to setLinks in that it allows you to extend GraphQL types. It however does not link two extensions' data together; it simply adds additional fields to the base Type. For example, if you would like to add custom data to dynamic fields, use setTypeExtensions.

setTypes

setTypes is used to send standalone GraphQL types to the Unity Platform. These can then be used to extend types from other extensions through setTypeExtensions.

REST Endpoints

Example endpoint

unity.post("/endpoint", (req, res) => {
  res.send("Hello World");
});

Example call to a private rest endpoint

const exampleCall = async () => {
  const response = await fetch(
    "https://<CloudDomain>/graphql/v2/exampleExtension/endpoint",
    {
      method: "POST",
      body: myBody, // string or object
      headers: {
        authorization: authToken // Only required if private
      }
    }
  );

  return response;
};

An example POST

unity.post("/location", handleFn);

An example private GET

unity.privateget("/location", handleFn);

Example call to a public GET endpoint

const exampleCall = async () => {
  const response = await fetch(
    "https://<CloudDomain>/graphql/v2/public/exampleExtension/retrieveForm",
    {
      method: "GET",
      body: myBody // string or object
    }
  );

  return response;
};

Alongside graphQL, the Unity SDK allows you to serve REST endpoints. These can be public endpoints which can be called from anywhere without requiring any unity-based authorization, or they can be private, with calls requiring an authorization header. Both GET and POST requests are able to be created.

To create a rest endpoint using the SDK, two paramaters are required:

Parameter Description
location The uri of the endpoint
handler A handler function which takes a request and response object

These rest endpoints are provided through the use of the express package.

Due to the modular nature of the Unity Platform, each endpoint sits behind the owning extension's name.

Private Endpoints

Private endpoints, as the name suggests, are private and require an authorization token to be present in the header of each request

The URL of a private endpoint https://<CloudDomain>/graphql/v2/<extensionName>/<endpoint>

post

Allows you to create a private POST rest endpoint that you can connect to externally

get

Allows you to create a private GET rest endpoint that you can connect to externally

Public Endpoints

Are able to be called without any authorization token

The URL of a public endpoint https://<CloudDomain>/graphql/v2/public/<extensionName>/<endpoint>

publicPost

Allows you to create a private POST rest endpoint that you can connect to externally

publicGet

Allows you to create a private GET rest endpoint that you can connect to externally

Web Hooks

Webhook implementation in Unity will differ from traditional webhooks. In Unity, a webhook is a way for you to subscribe to certain Unity events; when an event is triggered, we will send a HTTP POST/PATCH/PUT payload to the URL of your choice. Webhooks can be used to trigger external workflows, mirror Pulse data, download Virtual Assist sessions, etc. Please note that Unity events are mutations, so if you have multiple extensions, you can create webhooks for your mutations.

Traditional webhooks will hit the specified endpoint with a fixed payload. For example, an "item" is created, and the endpoint would be pinged with a payload specifying the ID of the created item. Webhooks in Unity allow you to specify a variable payload by providing a GraphQL query to be executed upon the event occurring - it is the result of this that will be sent to the webhook endpoint.

This is beneficial because in a traditional webhook system, unless you only require the ID to perform your task, generally you have to perform a follow-up query as the first operation to pull the required information about the event target - with the GraphQL-powered payload you can usually eliminate the requirement for another query by having it send all of the required data up-front.

Logic Hooks

Example Before Hook

unity.beforeHook("createItem", processWorkflows);

Example After Hook

unity.afterHook("SubmitItem", processWorkflows);

Logic hooks are a way of "Subscribing" to a mutation occuring within the platform. They allow you to register a Mutation name to listen to, and then a function to be executed upon that mutation occuring. There are two different types of logic hooks, one occurs before the mutation runs, the other occurs after it has finished.

Before Hook

Before Hooks trigger before an action is taken. Returning a promise from the handler can block the mutation from running, alternatively, returning nothing will allow the hook to run asynchronously with no impact to the mutation.

You can prevent the action from taking place if an error is thrown in the handler.

Field Description
mutation The name of the mutation to hook
handler a function which handles the hook

After Hook

After hooks trigger after an action is taken, returning the result of the action. Much like the Before Hook, you can also return a promise from the handler to delay returning result, this however, does not impact the mutation.

Throwing an error within the handler does not stop or rollback any action taken before this.

Field Description
mutation The name of the mutation to hook
handler a function which handles the hook

Services

The Unity SDK provides a variety of third party services in the form of SMS, VOIP, email and URL shortening. We encourage you to utilize these services for automating tasks, reminders and enabling better communication across internal and external parties.

To configure these services, please reach out to the team at Codafication at support@codaficaiton.com to get started. Once configured, these services can be called anywhere in your extension by accessing the unityClient.


SMS and VOIP

import { unity } from "../../server";

const sendSms = async (phoneNumber, message) => {
  return await unity.services.sendSms(phoneNumber, message, {
    from: "Name"
  });
};

We’ve chosen Twilio for SMS and VOIP calling within the platform. The Twilio client helps maintain audio quality by using WebRTC to connect calls to and from your web browser and can be ported to international numbers if required. Unity carries its own Twilio Client, but you can connect your own client if you’d prefer.

Field Description
phoneNumber Recipient's phone number
message The message to send
from The sender's name

Email

import { unity } from "../../server";

const sendEmail = async (email, files) => {
  return await unity.services.sendEmail({
    email,
    files: attachments
  });
};

We can configure any required outbound emails to send via Sendgrid, or Office 365 SMTP.

unity.services.sendEmail takes an object containing the information required to send an email as a parameter

Object Fields

Key Description
email The email to send
files An array of attachments to send
email object
Key Description
from The email address the email will originate from
subject Email Subject
to The recipient email address
cc CC Recipients
bcc BCC Recipients
text Content of the email in text
html Content of the email in html
Attachment object
Key Description
content The attachment's content as a readStream
contentType The type of content as a string
filename The file name as a string

Url Shortening

import { unity } from "../../server";

const generateShortLink = async longLink => {
  return await unity.services.generateShortLink(longLink);
};

Bitly improves the customer experience by turning long, unsightly links into concise, clickable links. Bitly is also a great way to ensure that links being sent to customers are secure and reliable by encrypting with HTTPS.

Starting the backend server

Suggested Layout

unity.postPublic("/publicPost", postHandler);
unity.get("/privateGet", getHandler);

unity.setQueries({ ...schema.queries });
unity.setMutations({ ...schema.mutations });

unity.setTypeExtensions([...typeExtensions]);
unity.setLinks([]);

unity.start();

Once everything is configured, you can start your backend with the start function. Provided everything has been configured correctly, your extension should connect with the Unity Platform, and all Queries and Mutations set should be become available in the developer portal.