Mr Optimism! I like your handle.
I’m sorry it’s not easier to discover these things, but yes there’s a very simple way to do that kind of thing. Apigee has a thing called a “message template” that allows you to do what you describe. Message templates are used in various places in various policies, but the most obvious and accessible place is in the AssignMessage policy. As an example, injecting or replacing an authorization header into the current message, with a value that consists of the string “Bearer” followed by the value of some variable, might look like this :
<AssignMessage name='AM-Apply-Authorization'>
<Set>
<Headers>
<Header name='authorization'>Bearer {variable-containing-token}</Header>
</Headers>
</Set>
</AssignMessage>
In message templates, any variable name within curly braces is replaced with the value of the named variable at runtime. Sometimes in my proxies I include this in the Response PostFlow to inject a response header telling the caller which proxy handled the request.
<AssignMessage name='##'>
<Set>
<Headers>
<Header name='apiproxy'>{apiproxy.name} r{apiproxy.revision}</Header>
</Headers>
</Set>
</AssignMessage>
But you can do more than just set headers. This works with the Payload too of course:
<AssignMessage name='AM-Response'>
<IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
<Set>
<Payload contentType='application/json'>{
"token" : "{variable-containing-token-here}"
}</Payload>
<StatusCode>200</StatusCode>
</Set>
</AssignMessage>
And you can also set arbitrary variables via templates:
<AssignMessage name='AM-Formatted-Time'>
<IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
<AssignVariable>
<Name>iso8601Format</Name>
<Value>yyyy-MM-dd'T'HH:mm:ss'Z'</Value>
</AssignVariable>
<AssignVariable>
<Name>formattedTime</Name>
<Template>{timeFormatUTCMs(iso8601Format,system.timestamp)}</Template>
<!-- eg, 2020-10-02T15:59:26Z -->
</AssignVariable>
</AssignMessage>
The above example shows off a static function that is available within the Template, in this case the function is timeFormatUTCMs, which accepts a format and a value of milliseconds-since-epoch and returns a formatted time string. There are other functions for substring, replacing text, computing SHA256 digests, calculating HMACs, evaluating xpath or jsonpath… Pretty nice set of capabilities.
The jsonpath function means that in your case you should be able to eliminate the ExtractVariables policy, and do what you want with two AssignVariable elements within AssignMessage:
<AssignMessage name='AM-Inject-Header'>
<AssignVariable>
<Name>json-path-1</Name>
<Value>$.access_token</Value>
</AssignVariable>
<AssignVariable>
<Name>extracted-token</Name>
<Value>BADDBEEF</Value>
<Template>{jsonPath(json-path-1,responseMessage.content)}</Template>
</AssignVariable>
<Set>
<Headers>
<Header name='authorization'>Bearer {extracted-token}</Header>
</Headers>
</Set>
</AssignMessage>
And (this is a bit meta) you can also refer to templates by variable name. So, you can do this:
<AssignMessage name='AM-Variable-From-Template'>
<AssignVariable>
<Name>new-variable</Name>
<Template ref='variable-containing-template'/>
<Value>unset</Value>
</AssignVariable>
</AssignMessage>
With this approach, you can define a template in an environment-scoped KVM, or in a properties file, and then refer to the variable containing that template like this. The new-variable gets set with the value resulting from evaluating the template stored in variable-containing-template .
The message template thing is pretty handy. Check it out.