Achieving Awesome Reuse with Shared Flows and Flow Hooks

Introduction

Share Flows support DRY (Don't Repeat Yourself) by providing a reusable sequence of policies, the Shared Flow, that can be used by API proxies, either through a FlowCallout policy or configured as a Flow Hook.

Flow Hooks are merely a way to “hook” an existing Shared Flow to a particular “flow” (Pre or Post flows in Proxy or Target) across all proxies in an environment, without having to add it to the consuming API proxy.

It is important to note that the shared flow and policies can change independent of the API proxy that is using it.

There is no Shared Fault Flow. The Shared Flow executes within the consuming API proxy flow, therefore all faults must be managed in the consuming API proxy Fault Rules. But guess what, you can put Flow Callouts to Shared Flows there and finally be able to provide consistent and consolidated fault handling for all your API proxies!

Beyond reuse and consistency, API design simplification is a huge benefit, since a single Flow Callout can execute multiple policies in a Shared Flow.

The examples below are just a start, what other reuse cases do you have?

Objectives

  • to define reusable flows of policies that can be used by API proxies within an environment.
  • to contrast when to configure a Shared Flow as a Flow Hook.

Overview

Shared Flows allow the API team to focus on the core aspects of the API, the gist of the API. The new API can then be augmented with Shared Flows or simply take advantage of a deployed Flow Hook.

Typical use cases for Shared Flows are:

  • API security - ensure API Key is handled consistently
  • Logging - common logging
  • Fault Handling - finally a way to consistently handle faults across all proxies!

Typical use cases for Flow Hooks are:

  • CORS - Add CORS with no effort to API developers

Alternatives to Shared Flows

  • Build time inclusion of common policies from source code repository
  • API proxy templates or design patterns provided in source code repository that developers use to jump start a similar design (e.g. Node.js based proxy to database).
  • Proxy Chaining

Examples

Verify API Key in Shared Callout

This example shows a Shared Flow to ensure consistency on the use of and API key across all proxies. The flow executes 2 policies a Validate API Key using X-APIKey header and an Assign Message to remove sensitive header information, a step often overlooked.

The Shared Flow named ValidateAPIKey

The shared flow

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<SharedFlow name="default">
    <Step>
        <Name>Verify-API-Key</Name>
    </Step>
    <Step>
        <Name>AM-Remove-Sensitive-Headers</Name>
    </Step>
</SharedFlow>

The Verify API Key policy

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<VerifyAPIKey async="false" continueOnError="true" enabled="true" name="Verify-API-Key">
    <DisplayName>Verify API Key</DisplayName>
    <Properties/>
    <APIKey ref="request.header.X-APIKey"/>
</VerifyAPIKey>
The Assign Message policy
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<AssignMessage async="false" continueOnError="false" enabled="true" name="AM-Remove-Sensitive-Headers">
    <DisplayName>AM - Remove Sensitive Headers</DisplayName>
    <Properties/>
    <Remove>
        <Headers>
            <Header name="x-apikey"/>
        </Headers>
    </Remove>
    <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
    <AssignTo createNew="false" transport="http" type="request"/>
</AssignMessage>

Using the Flow Callout Policy

Use in the Proxy PreFlow

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ProxyEndpoint name="default">
    <Description/>
    <FaultRules/>
    <PreFlow name="PreFlow">
        <Request>
            <Step>
                <Name>FC-ValidateAPIKey</Name>
            </Step>
        </Request>
    <Response/>
</PreFlow>
...

The FlowCallout policy

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<FlowCallout async="false" continueOnError="false" enabled="true" name="FC-ValidateAPIKey">
    <DisplayName>FC - ValidateAPIKey</DisplayName>
    <FaultRules/>
    <Properties/>
    <SharedFlowBundle>ValidateAPIKey</SharedFlowBundle>
</FlowCallout>

Fault Handling with Flow Callouts

This example shows how you can use Shared Flows in Fault Rules

<ProxyEndpoint name="default">
    <Description/>
    <DefaultFaultRule name="DefaultFaultRule">
        <Step>
            <FaultRules/>
            <Name>FC-DefaultFaultRule</Name>
        </Step>
        <AlwaysEnforce>true</AlwaysEnforce>
    </DefaultFaultRule>
    <FaultRules>
        <FaultRule name="FaultRules">
            <Step>
                <!-- Put all your Fault Rules in one Shared Flow -->
                <Name>FC-FaultRules</Name>
            </Step>
        </FaultRule>
    </FaultRules>

The Shared Flow for FaultRules

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<SharedFlow name="default">
    <Step>
        <Condition>fault.name = "FailedToResolveAPIKey" or fault.name = "InvalidApiKey"</Condition>
        <Name>AM-Fault-API-Key</Name>
    </Step>
</SharedFlow>

CORS in Flow Hook

This example shows how to configure Flow Hooks to support CORS. Recall that to fully support CORS, the pre-flight OPTIONS request must be processed in the Proxy PreFlow and CORS headers added in the Proxy PostFlow

The Shared Flow in the CORSPreFlow bundle

<SharedFlow name="default">
    <Step>
        <Condition>(request.verb = "OPTIONS")</Condition>
        <Name>JS-Extract-CORS-Headers</Name>
    </Step>
    <Step>
        <Condition>(request.verb = "OPTIONS")</Condition>
        <Name>RF-CORS-Pre-Flight</Name>
    </Step>
</SharedFlow>

The Shared Flow in the CORSPostFlow bundle

<SharedFlow name="default">
    <Step>
        <Name>AM-Add-CORS-Headers</Name>
    </Step>
</SharedFlow>

The configuration of the Flow Hooks

4371-screen-shot-2017-02-22-at-32543-pm.png

Useful links

http://apigee.com/docs/enterprise/content/shared-flows

http://apigee.com/docs/enterprise/content/flow-hooks

Comments
davissean
Staff

It may be useful for us to think about how this ties in with CI processes, and how shared flows can be tested and promoted between environments in isolation.

nmunro
New Member
@Kurt Kanaskie

Good article!

One thing I have noticed that's not clear here, or in the docs, is that the menu to create new shared flows is missing from "new" Edge. It's currently only available from "classic" (or it's hidden well!)

kurtkanaskie
Staff

Thanks @Neil Munro, I'm told we are planning to turn it on in New Edge on Jan 18th or maybe the week after.

@Sean Davis - the maven deploy plugin V1.1.4 now supports Shared flow deployments just like API Proxy. With this - you can now have the code in Version control and deploy to any given envirionment and plug it as part of your CI/CD process

Not applicable

Great article @Kurt Kanaskie

Not applicable

Good post.

How the flow is set-up for the fault rules will cause the DefaultFault to always be honored over the custom message from the other Fault Rules. You should remove the AlwaysEnforce stanza to cause the messages to be honored.

kurtkanaskie
Staff

Hi @Vern Burton, thanks for the comment.

I omitted some details. Please note that there is a Flow Callout FC-DefaultFaultRule to a shared flow in the DefaultFaultRule. In that shared flow I have additional policies, such as adding CORS and most importantly an Assign Message that sets the standard error response structure.

In the FaultRules section the AM-Fault-API-Key policy just sets variables. Then in the FC-DefaultFaultRule this Assign Message sets the standard error response structure.

<AssignMessage async="false" continueOnError="false" enabled="true" name="AM-SetStandardFaultResponse">
    <DisplayName>AM-SetStandardFaultResponse</DisplayName>
    <Properties/>
    <Set>
        <Payload contentType="application/json">
        {
           "code": "{flow.errorCode}",
           "userMessage": "{flow.errorUserMessage}",
           "systemMessage": "{flow.errorSystemMessage}",
           "info": "http://developer.company.com/docs/errors#{flow.errorCode}"
        }
        </Payload>
        <StatusCode>{flow.errorStatusCode}</StatusCode>
        <ReasonPhrase>{flow.errorReasonPhrase}</ReasonPhrase>
    </Set>
    <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
    <AssignTo createNew="false" transport="http" type="response"/>
</AssignMessage>

You can read more about this fault handling approach here: https://community.apigee.com/articles/23724/an-error-handling-pattern-for-apigee-proxies.html

aneeshananthakr
New Member

Hi,

I have a use case to create a Shared Flow for logging (Syslog server).

What is the best suggested way to pass the Message (to be logged into Syslog) into the Shared Flow from Main Flow?

I see that FlowCallout policy has a <Properties> tag. Can I use it to set a property which can then be accessed from MainFlow?

Thanks,

Aneesh.

Hi @AneeshAnanthakrishnan - can you post this as a new question please ?

Version history
Last update:
‎11-04-2016 05:03 PM
Updated by: