How To Use Serverless Functions
In the article, we have explained the high-level basics of the Serverless Functions that allow to extend Rossum functionality without the setup and maintenance of additional services.
In this article, we will explain the Functions in more detail, lead you through the main configuration steps, and show sample code snippets of Functions.
At the end, you should be able to understand how the following sample functions work:
- Check Amount due equals sum of Total amount column
- Check Issue date cannot be after Due date
- Switch Total amount and Total base columns if necessary
- Translate line items descriptions
- Filter documents coming from emails
How The Functions Work
Each Function has to have a Hook object of function type. This Hook object is assigned to your Rossum queue and is run on various events happening with an annotation. Every time the triggering event occurs, the Function will be run. One Function can be triggered on multiple events, and you can also have more Function hooks attached to one Queue.
A Function can be triggered by one of the following actions:
- Annotation status changed
- Annotation content was extracted for the first time
- User updated the annotation data
- Annotation is being moved to exported state
Functions vs. Webhooks
Functions and Webhooks share the same basic setup with regards to API communication. Still, there are a few differences:
Functions | Webhooks |
---|---|
Don’t need server to be run on as they are executed within the Rossum platform | Need to be run on your own remote server |
Must be written in Python or JavaScript. | Code can be written in any programming language |
Cannot cache data in a database | Custom database can be setup on the server for caching relevant data and speeding up the data queries. Useful for vendor and product matching. |
In general, serverless functions are a good option if you want to:
- run a code without having your own server
- implement a functionality that can be implemented using JavaScript
- implement simple data updates on a document
The Functions are especially useful if you need to do data validation, checksums, cross-checks, or apply any other custom rules to the extracted data to notify the user about the incorrect input and prevent exporting incorrect data.
Access to internet
Serverless Functions can be configured to access internet. However such option is currently disabled by default for every function. Please let us know about your intentions at [email protected] if you would like to have the access enabled and read more about the access to internet.
The Core Functions Part
You can configure your Rossum Queue to use a Function as described in our previous article. But how should the code of the Function look like from a developer’s perspective?
The following section is obsolete - use Python TxScript
We now recommend to prefer Python to implement Serverless Functions. We also provide the Rossum Transaction Script runtime to make it easy to manipulate business transaction and document data from the Python code without extra boilerplate and helpers.
The most important part of every Function is the Hook request handler. The request handler is the main and mandatory function that accepts input from Rossum, runs the main logic, and produces output of the Function hook. It must be called as follows:
exports.rossum_hook_request_handler()
You can find the examples of the input request and output response format here. The request handler accepts the annotation content or annotation status data, depending on what action triggers the Function hook.
Within the request handler method, you can create any logic you would like to be applied to an annotation. In the Function code you will see in the Rossum UI by default, you can find the pre-defined logic that will display a warning in the user interface when any of the values in the Total base column is greater than 1,000,000.
As the Functions conduct very similar actions, we have prepared a couple of helper functions that you can use in your code. For example, if you want to iterate over the annotation content, you can use findBySchemaId()
function to search for datapoints with particular schema_ids:
const findBySchemaId = (content, schemaId) =>
content.reduce(
(results, dp) =>
dp.schema_id === schemaId ?
[...results, dp] :
dp.children ?
[...results, ...findBySchemaId(dp.children, schemaId)] :
results,
[],
);
Which will return one or multiple datapoints of the annotation data.
If you would like to show an error or warning to the user in the UI, you can use createMessage()
function:
const createMessage = (type, content, datapointId = null) => ({
content: content,
type: type,
id: datapointId,
});
Which can produce an error, information, or a warning message:
If you want to update a datapoint with a new value, you can use the createReplaceOperation()
:
const createReplaceOperation = (datapoint, newValue) => ({
op: 'replace',
id: datapoint.id,
value: {
content: {
value: newValue,
},
},
});
This function can overwrite the original value with a new one (or simply add a new value if there wasn’t any before).
For more technical information, see our API documentation.
Testing Custom Function
If you are struggling with testing the functions, follow this article.
Updated 2 months ago