How to output data from a Flow Action

When I test my Flow Action, I’m not seeing the JSON object I return.

This action didn't return an output when it ran. Most often, this is because the action doesn’t return data or the returned data wasn’t used. In rare cases, it may also be that the output exceeded system limits.

I’ve looked at other forum posts, but they use the deprecated json() function. I think this is no longer necesssary in Remix (v2.17.0), though I did try that too. The Run Code examples seem to just return a simple JSON object:

  return {
    fulfillmentOrderSplits: JSON.stringify(fulfillmentOrderSplits),
  }

I’ve set up a return type in my .toml:

[[extensions]]
name = "My Flow Action (dev)"
handle = "my-flow-action"
type = "flow_action"
uid = "<redacted>"
description = "Do a thing"
runtime_url = "https://example.com/api/my-flow-action"
schema = "./schema.graphql"
return_type_ref = "ReturnType"

schema.graphql:

type ReturnType {
  message: String!
}

Here’s a stripped down version of my code:

export async function action(args: ActionFunctionArgs) {
    const {request, params} = args;
    return { message: "This is a returned message." };
}

I tried including a “Log output” object downstream of my action. I gave it a sample text message “Output message”, which is displayed but nothing else. When I tell it to show the input field {{ message }} it throws an error saying that’s not available:

"message" is invalid. Replace this variable.

Any guidance gratefully received.

Looks like you need to return a 200 status code and JSON object with a “return_value” key which then contains your object/message

@JordanFinners thanks, I did try that, but I still get the “didn’t return an output” message.

@James_Jace thanks, I’ve just tried that but again no luck. Here’s the function I wrote to try these excellent suggestions:

function returnMessage(message: string) {
    // return { return_value: { message } };
    return new Response(
        JSON.stringify({ message: message }),
        { headers: { "Content-Type": "application/json" } }
    );
}

I think my return_type_ref matches (schema in original post) exactly and I double checked the schema field and on-disk filename (both schema.graphql).

I’d appreciate any help. Please do help me verify my schema-to-action mapping. What do you need me to post?

Can you give this a try

export async function action(args: ActionFunctionArgs) {
    const {request, params} = args;
    return new Response(
        JSON.stringify({ return_value: { message: "This is a returned message." } }),
        { headers: { "Content-Type": "application/json", status: 200 } }
    );
}

Of course. Appreciate your help @JordanFinners. Sadly no output still and the same returned-no-output message in Step Data.

I tried it the way you said (200) and I also tried it quoted (“200”) because I think status expects a string.

export async function action(args: ActionFunctionArgs) {
    const {request, params} = args;
    return new Response(
        JSON.stringify({ return_value: { message: "This is a returned message." } }),
        { headers: { "Content-Type": "application/json", status: "200" } }
    );
}

I did a console.log() on my action’s output to confirm that it has a body (18 characters), status: 200 and flagged as application/json:

api/refresh-categories/action returned Response {
  size: 0,
  [Symbol(Body internals)]: {
    body: ReadableStream {
      _state: 'readable',
      _reader: undefined,
      _storedError: undefined,
      _disturbed: false,
      _readableStreamController: [ReadableStreamDefaultController]
    },
    type: 'text/plain;charset=UTF-8',
    size: 18,
    boundary: null,
    disturbed: false,
    error: null
  },
  [Symbol(Response internals)]: {
    url: undefined,
    status: 200,
    statusText: '',
    headers: { 'content-type': 'application/json' },
    counter: 0,
    highWaterMark: undefined
  }
}

I’m guessing it must be some problem with the GraphQL schema for ReturnType, but I can’t see it (still the same as my original message).

Can anyone recommend a well-formed example that I can download and run in place of my failing code to see an output?

If I can get anything to produce an output, I can work forward from there to isolate the problem.

@paul_n I carefully read your replies in another thread about this, but after days of testing, I still only get the same error message.

This action didn't return an output when it ran. Most often, this is because...

I’d really appreciate it if you could point up what I’m doing wrong here.

Hmm, reading that thread, can you try this?

export async function action(args: ActionFunctionArgs) {
    const {request, params} = args;
    return json({ return_value: { message: "This is a returned message." }});
}

And then ensure that the returned message is logged out or used in your flow?

Thanks @JordanFinners. I tried the code (no change, no output), but I’m afraid you’ll need to be more specific on “logged out or used in your flow”. How do I do either of those things? As I explained above, I tried using a Log output object, but I can’t refer to any of my output fields and I tried using console.log(), but that function (logically) only writes to my server’s log, not the output object.

You need to create flow that uses your action and then in Shopify Flow use the Log Output, this should be able to reference the result of your action if its all setup correctly
https://help.shopify.com/en/manual/shopify-flow/reference/actions/log-output

Right, thank you @JordanFinners. That was the missing piece. The Log Output object needs to log {{ message }}, but it has to do it within an extension-specific scope. Turns out that scope isn’t defined anywhere in schema.graphql or shopify.extension.toml: it’s a camel-case conversion of name (not handle).

So for “My flow action” (my-flow-action), the scope was myFlowAction, so I had to log (body of Log Output) {{ myFlowAction.message }}, then it worked.

1 Like

Awesome! Glad that got it working for you :smiley: