How to use an Apex-Defined Data Type to pass an HTTP response to a Flow?

Thanks so much, @rodrigo -- I still needed additional help in another forum before I could make use of your answer; I'd like to "explain it like I'm five" and add some additional details for others who come to this post as confused as me and can't quite get going with that answer alone.

Here are a few important things to know about Invocable Apex and Apex-Defined Data Types.

  1. The {get; set;} from the Car class example in the release notes isn't necessary, and fights with @InvocableVariable. Try leaving it off.
  2. Only standalone "outer" Apex classes seem to be recognized by the Flow Builder as allowable Apex-Defined Data Types -- not "inner" classes.
  3. Although Salesforce's official documentation about using @InvocableVariable adds this annotation to the attributes of an "inner class" hosted within an outer class possessing an @InvocableMethod-annotated method, this doesn't have to be the case.
    • Any "invocable" method is perfectly capable of returning a List<SomeStandaloneApexClass> as long as SomeStandaloneApexClass has at least one @InvocableVariable-annotated attribute.

This code allowed me to create a Flow Variable myVar1 whose data type was TestYesNoTwo. When I created a Flow Action that summoned getYesNo(), myVar1 was readily available for writing the action's Output to, and was easy to display on a Screen.

Screenshot: https://i.imgur.com/r9hVUBz.png

public class TestYesNoTwo {
    @AuraEnabled @InvocableVariable public String answer;
    @AuraEnabled @InvocableVariable public Boolean forced;
    @AuraEnabled @InvocableVariable public String image;

    public TestYesNoTwo() {}

    public TestYesNoTwo(String ans, Boolean frcd, String img) {
        answer = ans;
        forced = frcd;
        image = img;
    }
}
public class TestInvocableCallout {
    @InvocableMethod(label='Get YesNo' description='Returns a response from the public API YesNo.wtf')
    public static List<TestYesNoTwo> getYesNo() {
        List<TestYesNoTwo> yesNo = new List<TestYesNoTwo>();
        yesNo.add(new TestYesNoTwo('yes',False,'https://yesno.wtf/assets/yes/5-64c2804cc48057b94fd0b3eaf323d92c.gif'));
        return yesNo;
    }
}

Full tutorial for "admins and the devs who love them" here, if it helps people with a bit more context.


Ok... I didn't test integrating with the Flow... but as per InvocableMethod Annotation documentation that can be found here, it states:

If the return type is not Null, the data type returned by the method must be one of the following:

A list of a primitive data type or a list of lists of a primitive data type – the generic Object type is not supported.

A list of an sObject type or a list of lists of an sObject type – the generic sObject type is not supported.

A list of a user-defined type, containing variables of the supported types and with the InvocableVariable annotation. Create a custom global or public Apex class to implement your data type, and make sure your class contains at least one member variable with the invocable variable annotation.

I have changed your code slightly to add the @InvocableVariable to the variable as below:

public class TestYesNo {
    @InvocableVariable 
    public String answer;
    @InvocableVariable 
    public Boolean forced;
    @InvocableVariable 
    public String image;
}

I was able to then save the TestInvocableCallout class without any problem.

If you take a quick look at the InvocableVariable Annotation documentation here they use a different approach where they create an internal class with the member variables tagged as @InvocableVariable and use it as the List return type.

Hope that helps and let me know if you were able to integrate with the Flow :).