Flow Masterclass: Create Declarative Flow Actions with Metaprogramming

Flow’s ability to directly use custom data types gives it the ability to work with data structured as apex objects. This is extremely powerful but still requires that the data structure exist in the form of an Apex Class. Usually that’s not a problem. But some interesting use cases involve the creation of lots of different data structures.

Suppose you have an AI that processes PDF documents that are derived from scans of paper forms. As part of the configuration, your AI is trained to recognize different form types. One ‘Mailing List’ form type might generate firstnames, lastnames, and addresses while an ‘Order’ form type might generate orderNumbers and orderQuantities.

You now want the ability to take the data from those scanned forms and use Flow to process it. That means that the user might, on flow screen 1, upload a PDF file. Then the file would get passed to the AI and get back a set of keys and values (example: ‘firstname’ : ‘Stephen’). If we can output these keys and values to Flow, then we can have the flow do things like create Contact records or send emails.

The straightforward way to do this would be to create one Apex class for the Mailing List form, and ‘auraEnable’ it so that it shows up in Flow as an Apex-defined Type:

We’d create a similar one for the Order form, and when the flow designer creates their flow, they’d simply select the one that was a match for the current job.

But we have a tougher challenge here, because we want the use to be able to freely (and without code) create lots of unique custom form types. In order to support that, we need to trigger each time a form type is changed, and automatically generate the appropriate Apex data type in the background.

This isn’t easy to do. It requires the use of a multistep process that involves:

  1. starting with a list of the names of the fields, do string manipulation in Apex to build up a string representing the Apex Class you want to generate
  2. programmatically assemble a zip file package of metadata, including a package.xml file
  3. Base64 encode the package and deploy it from apex using standard metadata deployment.

Fortunately, Andrew Fawcett yoda’ed the hell out of this problem back in the 2010’s. His MetadataService forms the backbone of our solution.

The solution has 2 parts:

  1. You use the GenerateCustomClasses code to take a list of string keys (technically it expects a Map<String, String> but only the keys are used) and generate two Apex classes.
  2. The two classes are a custom datatype (aka an Apex-defined type) and an invocable action called ProcessForm_[foo], where the full name is determined by an input to the GenerateCustomClasses code.

The GenerateCustomClasses code is set up as an invocable action but in practice it’s unlikely to be used declaratively. A more realistic scenario is to have the creation of some kind of data structure trigger this code to run and generate the two classes so that the data structure can be manipulated declaratively in Flow.

Note that because the generation process involves a metadata deployment call back into your org, you will need to add a remote site setting. The easiest way to find out what you need is to just run the flow and then copy out of the error message:

Install or View Source

To install, clone the repo at https://github.com/alexed1/FormToFlowMapper