HTTP requests with Molnify

A guide to communicating with Molnify apps

In order for two applications to communicate, they need to pass messages or data back-and-forth. In a web context, this communication is most often done through API (Application Programming Interface) requests using HTTP (HyperText Transfer Protocol). As such, knowing how to communicate using HTTP to-and-from a Molnify application is neccessary in order to integrate a Molnify application into larger systems.

This guide will walk you through how to make HTTP requests in Molnify, and provide a solid foundation for making your own requests. It does so by discussing the http action and its options before expanding its scope to more complex examples such as authorization and transfer of data. A section on communication to a Molnify application is also included, and finally an example that showcases the other topics of the guide by sending emails about cats.

However, this is also an intermediate guide, and is aimed towards a reader who is familiar with the basics of Molnify and the basics of HTTP requests.

Sending data from Molnify

We will start with a few example requests, each focusing on a particular aspect of communication. We will be making use of httpbin.org as a simple and transparent interface to communicate with. In the Molnify application, we will be using the action to send an HTTP request, and various of its options to configure the request.

Simple request and response

An http action, defining type=http, name=simple-post, title=;My first POST request, url=http://httpbin.org/post and method=POST.

The above action makes a straightforward POST request. The provided action options do, in detail:

  • type: http. This specifies that the action will send an http request.
  • name: simple-post. This defines the internal name "simple-post" for the action. While not a strict requirement, it is recommended for this to be unique.
  • title: My first POST request. The "title" option is the text that is shown on the action button.
  • url: http://httpbin.org/post. This is the URL which we make the request to. The httpbin /post endpoint accepts any POST request, and returns the request's parameters in the response. However, we currently do not display the response anywhere.
  • method: POST. Specifies that the request should be a POST request. This line could be omitted in this example, since the default request method for the action is POST, but it is recommended to include for clarity.

If you upload an application with the above action to Molnify, and click on the button, you will not get any feedback other than the absence of an error message. This indicates that the action was a success (status code 200 or 201). But for most applications, we will recieve a response with data which the Molnify application must parse and act on.

To retrieve the HTTP response data, we do not need to modify the action. Instead, Molnify places any data in the response into the Molnify variable httpresponse, if present.

An input with ui string 'variable=httpresponse;hidden', an output with the formula 'IF(ISBLANK(B1), "No request made yet", B1), and an action to make a simple POST request to httpbin.org/post.

In our example, we add an input cell with the ui string variable=httpresponse. We also set it as hidden, as we do not intend to manually type in data here. Instead, we we turn cell B2 into an output, and set it to be equal to the input cell B1. Now, when we perform the HTTP request, the output displays the data which httpbin responds with.

A Molnify application where an output shows the value of the 'httpresponse' variable, before and after sending an HTTP request.

Authorization

Often, you will access a resource which is not publicly available. In those cases, the sender of the API request must authorize against the receiving server. Commonly, the process looks like follows:

  1. The sender authorizes, using e.g. a username and a password, and recieves a "bearer" token
  2. The sender provides the bearer token in the headers of any HTTP request(s) they make to the server
  3. The bearer token expires after a short while

Or sometimes, the generally less secure:

  1. The sender provides the base64-encoded username and password with every request (basic authorization)

Bearer authorization

Bearer authorization can be understood as "give access to the bearer of this token", and is frequently used in most kinds of APIs. The below implements the second step of bearer authorization.

An action with type=http, name=simple-auth, title="Perform bearer authorization", url=http://httpbin.org/bearer, method=GET, authorizationType=Bearer, token=B1 (a textarea input), and payload="".

The options authorizationType and token combine to form the request header: "Authorization" : authorizationType + " " + token. Note that the method option now specifies that the request is a GET request instead of the default POST request. We also must specify an empty payload, since Molnify by default otherwise sends the string "OK" as payload of the request. Finally, a textarea input is used to input the bearer token, for now.

We use the httpbin.org/uuid API endpoint to generate a semi-random token from an HTTP request. For an example on how to acquire a token from an endpoint which requires username and password authentication, see the Basic authorization example.

An action with type=http, name=simple-acquire-token, title="Acquire bearer token", url=http://httpbin.org/uuid, method=GET, and payload="".

The structure and components of the HTTP request action should be familar from the previous examples. However, it is of note that we here use the Molnify function FILTERJSON to read a value from the request response.

Now, combining the two previous steps gives us:

There is an important consideration now that we are making several HTTP requests from the same Molnify application: there are multiple requests being performed, but only one variable='httpresponse'. To work around this limitation, we define a JavaScript function in the application's metadata to save the parsed authentication token into the variable token-stored, if we have successfully parsed a token. Then, we call this save function whenever we parse a new token, through the ui string jsOnChange.

The JavaScript in the metadata is function save_token() { let tok = getValueForVariable('token'); if(tok !== '\u00A0') setValueForVariable('token-stored', tok); }. The variable "token" has value "\u00A0" - a non-breaking space - if its cell is empty.

The metadata JavaScriptAfterLoad executes the action to request an authentication token when the app is loaded: performActionWithName('simple-acquire-token');.

The Excel file for this example can be downloaded here.

Basic authorization

For basic authorization, the HTTP request must pass the base64-encoded value of "username:password" in the authorization header. This method, while generally considered less secure than Bearer authorization, can be found particularly within legacy systems and simple web services. The following example implements the basic authorization procedure.

There are a few notes not clear from the image:

  • The url is dynamically generated by the formula ="http://httpbin.org/hidden-basic-auth/"&B1&"/"&B2
  • The cell for the action's token is defined to be =B5
  • We eschew the use of the automatic action button, and instead define a new butting using an html output. This is so that we can combine the activation of the action with a JavaScript call.
  • The following JavaScript is included in the metadata, and defines the encode_token function which creates the base64-encoded token from the input username and password. function encode_token() { setValueForVariable('token', btoa(getValueForVariable('username') + ":" + getValueForVariable('password'))); }

The Excel file for this example can be downloaded here.

Payloads

When sending data with an HTTP request, you can send more-or-less anything that can be represented as a string, from plain text messages to entire webpages. However, one of the most common data formats is JavaScript Object Notation, abbreviated as JSON. When making an HTTP request, you may use the header "Content-Type" to specify how the reciever should parse the data you send, and you provide your data in the request's body.

The above example illustrates sending a simple payload, with a specific Content-Type. The Content-Type application/json is default in Molnify.

When constructing a request payload, you can use either the payload or the autoPayload action options. The autoPayload option parses all of the application's inputs and/or outputs into a JSON structure. On the other hand, specifying a payload requires more complicated formulas but yields finer control over the exact payload. If both options are present, then autoPayload overrides payload.

Sending data to Molnify

While a Molnify application can send data, it can also be invoked via its own API endpoint.

The following example application performs a very simple function: it sends an email with a fact to a recipient.

In the Molnify application sidebar, we can find information about the application's API endpoint. In particular, you can find its API key.

Each Molnify application has two endpoints: call and execute.

/call

The call endpoint parses the request payload as a description of the application's inputs, performs a calculation, and responds with the value of the inputs and outputs after the calculation. The request data is to be structured as a JSON so that the JSONPath inputs.['Sheet!Cell'] finds the value of each changed input. Additionally, the application's API key must be provided as the value of the Authorization header, i.e. do not prepend "Basic", "Bearer", or similar.

The following curl request performs a calculation for the example application: curl -X POST \
--url https://api.compute.molnify.com/api/call \
-H 'Content-Type: application/json' \
-H 'Authorization: 611124fe13a0e196a22be6f269f3754c2ab7b2c15952f3b23173f81d11a472dc' \
-H 'Application-ID: http-reciever' \
-d '{ "inputs": {"Sheet1!B1": "<your-email>", "Sheet1!B2": "This is a very interesting fact.."} }'

If you run the above statement in your terminal, you will recieve a result similar to: {"result":{"Sheet1!B4":"<div><h1>Hello!<\/h1><\/div><div>Here's a new fact for you:<br>This is a very interesting fact..<\/div><br><div>Best regards,<br>The Molnify HTTP reciever app<\/div>","Sheet1!B1":"<your-email>","Sheet1!B2":"This is a very interesting fact.."},"other":{"lastModified":1722351294324,"calculationTimeInMs":120,"cacheUsed":false}}

/execute

In order to perform an action from the application, we use the execute endpoint. For it, the data has a more complex structure, which is best illustrated via a curl invocation:

curl -X POST \
--url https://api.compute.molnify.com/api/execute \
-H 'Content-Type: application/json' \
-H 'Authorization: 611124fe13a0e196a22be6f269f3754c2ab7b2c15952f3b23173f81d11a472dc' \
-d '{ "actionId": 0, "requestID": "", "changes": [{"cell": "Sheet1!B1", "value": "<your-email>"}, {"cell": "Sheet1!B2", "value": "This is a very interesting fact.."}], "dateModified": 2483228800, "applicationID": "http-reciever" }'

Breaking this down:
  • The data-JSON contains the elements actionId, requestID, changes, dateModified, and applicationID
  • The actionId is the numerical index of the action, as it is read by Molnify when the Excel file is parsed. Recall that Molnify parses Excel files sheet-by-sheet, starting in the top-left of each sheet.
  • requestID is currently unused
  • The changes element is an array of changes, where each change has a cell and a value which the cell is changed to.
  • dateModified is time which the request was issued, represented as the number of seconds since the UNIX epoch. This is only used for caching- and sanity-purposes, and an approximate values is perfectly acceptable.
  • applicationID is the id of the Molnify application

If you run the curl command in your terminal (substituting the email address for your email address), then you should recieve an email with your fact within a few seconds.

Cat facts - a "practical" example

This section is an example of building an application which sends emails about cats. The example shows a method of sequencing API requests, and includes an API call with authorization to another Molnify application. While the example itself is simplistic for pedagogical reasons, it is easy to imagine more complex use cases where other APIs are employed together in a similar fashion.

First, we need some facts about cats. To generate them, we will be using the catfact.ninja API. The API endpoint which we will use is: curl -X 'GET' \
'https://catfact.ninja/fact?max_length=128' \
-H 'accept: application/json'

The endpoint returns facts structured as JSON, such as: {"fact":"In ancient Egypt, when a family cat died, all family members would shave their eyebrows as a sign of mourning.","length":110}

The call to the catfact API is fairly straightforward. When the request recieves a response, the cell B4 uses the Molnify function FILTERJSON to attempt to parse the response. If B4 successfully parses a cat fact, its value changes, and the custom JavaScript function save_fact will copy the fact to B5 for later use. The output cell B7 displays the fact, while we work on the emailing function.

Now, the sensible course of action would be to define an email action here, but we will make an API request to the app with the email action defined earlier. We create a second action to make this request.

The above shows the Excel model for the app, which also can be downloaded here.

The action to make an API request to the app for sending emails has been added, as well as structure to call the action when a new catfact is saved.

  • When a cat fact is parsed successfully, the jsOnChange ui string causes the JavaScript function send_email to be executed
  • The send_email function first ensures that values are updated properly - via a call to calculateButton - and then executes the action to send the email
  • The columns F and G contain metadata related to the styling of the app, which is not covered by this guide

The final cat-fact app can be found at https://app.molnify.com/app/catfact-demo.