Antipattern: Invoke Management API calls from an API Proxy

Edge has a powerful utility called “management APIs” which offers services such as:

  • Deploying or undeploying API Proxies
  • Configuring virtual hosts, keystores and truststores, etc.
  • Creating, deleting and/or updating entities such as KeyValueMaps, API Products, Developer Apps, Developers, Consumer Keys, etc.
  • Retrieving information about these entities

These services are made accessible through a component called Management Server in the Apigee Edge platform. These services can be invoked easily with the help of simple management API calls.

Sometimes we may need to use one or more of these services from API Proxies at runtime. This is because the entities such as KeyValueMaps, OAuth Access Tokens, API Products, Developer Apps, Developers, Consumer Keys, etc. contain useful information in the form of key-value pairs, custom attributes or as part of its profile.

For instance, you can store the following information in KeyValueMap to make it more secure and accessible at runtime:

  • Back-end target URLs
  • Environment properties
  • Security credentials of backend or third party systems

Similarly, you may want to get the list of API Products or developer’s email address at runtime. This information will be available as part of the Developer Apps profile.

All this information can be effectively used at runtime to enable dynamic behaviour in policies or custom code within Apigee Edge.

Antipattern

The management APIs are preferred and useful for administrative tasks and should not be used for performing any runtime logic in API Proxies flow. This is because:

  • Using management APIs to access information about the entities such as KeyValueMaps, OAuth Access Tokens or for any other purpose from API Proxies leads to dependency on Management Servers.
  • Management Servers are not a part of Edge runtime component and therefore, they may not be highly available.
  • Management Servers also may not be provisioned within the same network or data center and may therefore introduce network latencies at runtime.
  • The entries in the management servers are cached for longer period of time, so we may not be able to see the latest data immediately in the API Proxies if we perform writes and reads in a short period of time.
  • Increases network hops at runtime.

In the code sample below, the management API call is made via the custom JavaScript code to retrieve the information from the KeyValueMap:

var response = httpClient.send('https://api.enterprise.apigee.com/v1/o/org_name/e/env_name/keyvaluemaps/kvm_name')

If the management server is unavailable, then the JavaScript code invoking the management API call fails. This subsequently causes the API request to fail.

Impact

  • Introduces additional dependency on Management Servers during runtime. Any failure in Management servers will affect the API calls.
  • User credentials for management APIs need to be stored either locally or in some secure store such as Encrypted KVM.
  • Performance implications owing to invoking the management service over the network.
  • May not see the updated values immediately due to longer cache expiration in management servers.

Best practice

There are more effective ways of retrieving information from entities such as KeyValueMaps, API Products, DeveloperApps, Developers, Consumer Keys, etc. at runtime. Here are a few examples:

  • Use a KeyValueMapOperations policy to access information from KeyValueMaps. Here’s sample code that shows how to retrieve information from the KeyValueMap:
    <!-- /antipatterns/examples/2-6.xml -->
    <KeyValueMapOperations mapIdentifier="urlMap" async="false"
        continueOnError="false" enabled="true" name="GetURLKVM">
      <DisplayName>GetURLKVM</DisplayName>
      <ExpiryTimeInSecs>86400</ExpiryTimeInSecs>
      <Scope>environment</Scope>
      <Get assignTo="urlHosti" index="2">
        <Key>
          <Parameter>urlHost_1</Parameter>
        </Key>
      </Get>
    </KeyValueMapOperations>
    
  • To access information about API Products, Developer Apps, Developers, Consumer Keys, etc. in the API Proxy, you can do either of the following:
    • If your API Proxy flow has a VerifyAPIKey policy, then you can access the information using the flow variables populated as part of this policy. Here is sample code that shows how to retrieve the name and created_by information of a Developer App using JavaScript:
      <!-- /antipatterns/examples/2-7.xml -->
      print("Application Name ", context.getVariable(""verifyapikey. VerifyAPIKey.app.name"));
      print("Created by:", context.getVariable("verifyapikey. VerifyAPIKey.app.created_by"));
      
    • If your API Proxy flow doesn’t have a VerifyAPIKey policy, then you can access the profiles of API Products, Developer Apps, etc. using the Access Entity and Extract Variables policies:
      1. Retrieve the profile of DeveloperApp with the AccessEntity policy:
        <!-- /antipatterns/examples/2-8.xml -->
        <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
        <AccessEntity async="false" continueOnError="false" enabled="true" name="GetDeveloperApp">
          <DisplayName>GetDeveloperApp</DisplayName>
          <EntityType value="app"></EntityType>
          <EntityIdentifier ref="developer.app.name" type="appname"/>
          <SecondaryIdentifier ref="developer.id" type="developerid"/>
        </AccessEntity>
        
      2. Extract the appId from DeveloperApp with the ExtractVariables policy:
        <!-- /antipatterns/examples/2-9.xml -->
        <ExtractVariables name="Extract-Developer App-Info">
          <!--
            The source element points to the variable populated by AccessEntity policy.
            The format is <policy-type>.<policy-name>
            In this case, the variable contains the whole developer profile.
          -->
          <Source>AccessEntity.GetDeveloperApp"</Source>
          <VariablePrefix>developerapp</VariablePrefix>
          <XMLPayload>
            <Variable name="appld" type="string">
              <!-- You parse elements from the developer profile using XPath. -->
              <XPath>/App/AppId</XPath>
            </Variable>
          </XMLPayload>
        </ExtractVariables>
        

Further reading