Java callout via Flow Hooks

Hi,

Been spending a few days trying to make this work, getting a little frustrated here 🙂

I am developing a "Java Callout" that I'd like to invoke from the Flow Hooks mechanism so this Java Callout runs for every API Proxy request/response. In this Callout, I have to:

  • Access request/response headers
  • Communicate with external server via REST.
  • Impact performance as little as possible.

I have a few questions:

I need to grab some headers that only exist in the Client request, before it is modified by any API Proxy,
But I am also interested in headers and body that will be sent to the client after the target backend server replies etc... In other words, I believe I have to use both Pre-Proxy and Post-Proxy Flowhooks.

I want to gather some data from the request, store it somewhere until the response arrives, gather some data from response, apply some logic, and communicate with external server.  This has to happen for each transaction on any API Proxy affected by the flow hook.

My questions:

  1. Is storing data on messageContext.setVariable("somekey", "somedata") the right way? Is messageContext unique per session?
  2. Should "executionContext.isRequestFlow()" be working for me? It always returns true.
  3. Running a debug session, I see variable and properties such as:
    proxy.flow.name / current.flow.name etc...
    Trying to access these from messageContext.getVariable("proxy.flow.name") or messageContext.getVariable("{proxy.flow.name}") (also current.flow.name) and other combinations never return a value.
    What am I doing wrong?

I have read the docs, I have seen the solution by @dino where a wrapper function first check the properties provided by the policy on instantiation, and it returns a curly braced string, fetch it using getVariable.  It doesn't work for me.

Thanks!
ED.

0 2 136
2 REPLIES 2

getting a little frustrated here 🙂

Sorry to hear that.


@razor wrote:

I need to grab some headers that only exist in the Client request, before it is modified by any API Proxy,
But I am also interested in headers and body that will be sent to the client after the target backend server replies etc... In other words, I believe I have to use both Pre-Proxy and Post-Proxy Flowhooks.

I want to gather some data from the request, store it somewhere until the response arrives, gather some data from response, apply some logic, and communicate with external server.  This has to happen for each transaction on any API Proxy affected by the flow hook.


 

  • Is storing data on messageContext.setVariable("somekey", "somedata") the right way? Is messageContext unique per session?

MessageContext is unique per inbound message (or request). There is no "session" concept in Apigee. It is ok to store values into the message context with .setVariable().  If you attach a Java callout that executes in the PRe-Proxy flow hook, and stores headers into context, then ... you will be able to retrieve those values later in a different policy that runs in the post-proxy flow hook. 

  • Should "executionContext.isRequestFlow()" be working for me? It always returns true.

Maybe because your Java callout is always attached to the request flow? I dunno, it's hard to say.  

  • Running a debug session, I see variable and properties such as:
    proxy.flow.name / current.flow.name etc...
    Trying to access these from messageContext.getVariable("proxy.flow.name") or messageContext.getVariable("{proxy.flow.name}") (also current.flow.name) and other combinations never return a value.
    What am I doing wrong?

I don't know. That should work. Variable names do not begin and end with curly braces. Getting "{proxy.flow.name}" is wrong. Retrieving the values of the bare names looks right to me. "current.flow.name" might return empty/null, if running in a flow hook!  The flow name is the name of the conditional flow.  In a flowhook you're not in a conditional flow. 


@razor wrote:

I have seen the solution by @dino where a wrapper function first check the properties provided by the policy on instantiation, and it returns a curly braced string, fetch it using getVariable. It doesn't work for me.


I'm sorry to hear that doesn't work for you. I know what you're referring to, and it's pretty basic stuff. Something else is wrong with what you are trying.

You didn't provide many specifics about what you are doing. The Java code and the policy configuration. So it's hard to diagnose. I suggest that you start from the basics. Just start with a very basic Java callout. If you want the "resolve properties to context variables" thing, then go ahead and add that. Take it one step at a time. You can start with this example: https://github.com/DinoChiesa/ApigeeEdge-JavaCallout101

Stepping back, aside from the specific challenges you are facing with the Java callout, I think maybe you are asking too much of the Java callout mechanism. The thing you are imagining , read request and response headers and then communicate with some other REST service, is best done in... an API Proxy.... or in an External service like one you might attach via ExternalCallout. The JavaCallout is not a good mechanism in which to wrap external communication. Don't do that. Use the JavaCallout to wrap compute tasks - like decoding, encoding, signing, decrypting, hashing, digests, and that sort of thing. Manipulating or analyzing the message context, including headers, payloads, etc. If you want to communicate to an external system, I suggest that you encapsulate all of that into a separate microservice, and connect to it from the API proxy via grpc. This is possible via the ExternalCallout policy. It will be fast.

What exactly are you doing with the "connect to an external rest service" anyway? What is the point of that thing?

I'll be honest here, I was able to solve most of the issues in some way or another - but forgot to update. I have a new question which I will soon post, but since you took the time to respond to me, it's only fair that I bring some closure and clarity to this threads topics.

So for completeness sake, here is what we ended up doing to overcome the issues:

Storing variables in messageContext

Storing data on messageContext works, I use the prefix to make sure we differentiate variables we store on the flow, and also when we retrieve:

messageContext.setVariable(prefix + varName, value);
I did have issues storing complete objects of classes we created. I had to resort to store strings, and create the object on the response phase. I don't recall exactly what was the issue, but create class Razor{} and trying to store an instance of that, did not work.
 
Detecting PreFlow, or Request flow.
boolean isPostFlow = messageContext.getVariable("current.flow.name") == "PostFlow";
boolean isErrorFlow = ((Boolean) messageContext.getVariable("is.error")) == true;
boolean isResponseFlow = isPostFlow || isErrorFlow;
 
The "current.flow.name" variable is null in request flow.  So I basically had to go by elimination. This is something that could be better, imho.
 
I couldn't get "executionContext.isRequestFlow()" to work.
 
As for Performance:
The JavaCallout solution turned out to be exactly what we needed performance wise.
We used java threadpool and got performance that is substantially better compared to JavaScript policy.  We want a solution that works on all Apigee flavors if possible. I think Java is supported by all Apigee flavors, X, Edge, Hybrid etc....

Thanks for the help, Hope to see you in the next question 🙂