Deploy and Interact with Serverless Functions using EXM’s SDK

Community Labs
4 min readDec 14, 2022

--

Written by Rohit Pathare

Execution Machine (EXM) is a developer platform that provides the ability to create and leverage blockchain-based (permanent) serverless functions without the need for knowledge of or access to blockchain technologies like wallets and tokens.

In an earlier article we understood how Execution Machine and its supporting technologies work.

In this article we will walkthrough a basic code example for deploying and interacting with serverless functions using EXM’s JavaScript SDK.

Basic Setup

We start off by creating an empty repository and install the Execution Machine package.

npm init -y
npm i @execution-machine/sdk

Defining the Function

After installing the package we create a file named function.js in our repository and write the logic of our function within it.

export function handle(state, action) {
state.users.push(action.input.name);
return { state }
}

The syntax for defining functions is based off of the standard implemented by SmartWeave for smart contracts in JavaScript. Every function has a state which is a JSON object of values stored in it and actions to interact with these values.

In our function, we want to add names to a users array which is done using the following line:

state.users.push(action.input.name);

When deploying our function we initialise an empty array named users that later helps our function to identify this state variable (variable stored in state of the function) during read and write calls. Upon initialisation the state looks like this:

{ users: [] }

Additionally, while writing to the function, we use a key named name to help the function identify what value we are feeding into the write operation. Both these definitions gain further significance when dealing with multiple values.

Handling the EXM API Token Safely

In order to use with EXM, we need a Token or Key which can be created here.

⚠️ The API_TOKEN is an identifier to our account and lets us access functions associated with it. Hence, it is vital to ensure this token is kept secret to prevent any spams and attacks to our functions. The best way to do so is using environment variables.

For setting up environment variables we install the dotenv package and create a file named .env with our API TOKEN as follows:

EXM_API_TOKEN='EXM_API_KEY_HERE'

To ensure these variables are not pushed to a github repository, add the following to a new file named .gitignore:

.env

Deploying our Serverless Function

Once we are setup to interact with EXM safely, we need a file named deploy.js to deploy our function on Arweave.

import { Exm, ContractType } from '@execution-machine/sdk';
import { readFileSync } from 'fs';
import dotenv from "dotenv";
dotenv.config();

// init new EXM instance
const exm = new Exm({ token: process.env.EXM_API_TOKEN });

// fetch function source
const functionSource = readFileSync('function.js');

// .deploy(source, initState, contractType)
const functionInst = await exm.functions.deploy(functionSource, { users: [] }, ContractType.JS);
console.log(functionInst);

For deploying our function, we need to pass in the function definition, initial state of function and function definition type as arguments. While deploying, we have stored in a variable and console logged the transaction as we are returned a functionId that is needed for further interacting with our serverless function for read and write operations.

We are essentially creating a script here that tells our computer how to deploy our function to the network. To run this script we simply run the following command in our terminal and our function will be deployed:

node deploy.js

In return we get the following object logged in the console:

{ id: 'UNIQUE_FUNCTION_ID' }

Writing to the Function

With the function deployed we can finally interact with it. To start off let’s add a value to the users array using a new file write.js.

import { Exm } from '@execution-machine/sdk';
import dotenv from "dotenv";
dotenv.config();

const exm = new Exm({ token: process.env.EXM_API_TOKEN });

const functionId = 'UNIQUE_FUNCTION_ID';

const inputs = [{ name: 'Open Sourcerer' }];

const writeTx = await exm.functions.write(functionId, inputs);
console.log(writeTx);

Our write transaction takes in two arguments. The functionId of the function we want to interact with and any inputs the function needs to process our request and update state.

We store the write transaction and log it to check the status and transaction Id. This is another script and can be run as follows:

node write.js

A successful write request returns an object with the status as SUCCESS.

{
status: 'SUCCESS',
data: {
pseudoId: 'txnId',
execution: {
state: [Object],
result: null,
validity: [Object],
exmContext: [Object],
updated: false
}
}
}

Reading values from the Function

We can read values from the users array using a read function defined as follows in read.js:

import { Exm } from '@execution-machine/sdk';
import dotenv from "dotenv";
dotenv.config();

const exm = new Exm({ token: process.env.EXM_API_TOKEN });

const functionId = 'UNIQUE_FUNCTION_ID';

const readTx = await exm.functions.read(functionId);
console.log(readTx);

This logs an object with the values we have written to the users array:

{ users: [ 'Open Sourcerer' ] }

Great job! If you need any help with the code, refer to the repository here.

Let’s Recap

Let us quickly recap what we did in this article.

We started off by creating an empty repository and installing the necessary. Then we wrote the logic for our function. For interacting with EXM we learnt to handle API keys safely. Once setup, we deployed our function and performed both write and read operations on it.

To learn more about EXM read their docs. For any help join the Discord or reach out on Twitter.

Fin.

--

--

Community Labs

Community Labs is a software development company and venture studio focused on the Arweave ecosystem.