In the second part of this two part blog post, I will describe the actual creation of the API definition in API Platform Cloud Service (shortened to APIPCS), the service callout to an external microservice (conveniently located in the Oracle Application Container Cloud Service) using a custom Groovy script policy and testing the flow created. The first part discussed the use case for which we used Oracle API Platform Cloud Service (shortened to APIPCS from now on) as an outbound API Gateway, offering lookup services and centralizing outbound access. This part also described a simple Node.js microservice we created to perform the translation of an internal identification into the API key required by the external API.

Exposing the API in Oracle's API Platform Cloud Service

With the lookup microservice up and running, now our attention can be turned to the actual configuration of the API in Oracle’s API Platform Cloud Service.

The APIPCS has a cloud based configuration environment where API configurations may be maintained. These definitions may also be controlled by invoking REST APIs on the APIPCS, but that is beyond the scope of this blog.

The steps in the request and response paths for this API are actually quite straightforward:


4. Implementing the API request flow

 

Starting at the top, there is an API Request policy which is a purely declarative action defining the endpoint that the APIPCS will be listening for inbound requests.

Based on a custom HTTP header on the inbound API request (X-APIKEY-USER), the next Groovy Script policy extracts its value and uses this as the representation of the internal identification for which we need to perform the lookup of the external API key using a so-called “callout”.

The Redaction policy following this step allows us to reshape the outbound request, in this case we are removing the custom HTTP header “X-APIKEY-USER” as we do not want to expose our internal identifications to the external API application …

After removing the unwanted custom header from the outbound request, the only action that needs to be done is inserting the external API Key in the outbound request.

After this, the final step in the request flow is also a declarative action defining the (in our caser external) endpoint that needs to be invoked for this api, https://overheid.io/api.

 

For our specific use case, we did not need to alter the response payload in anyway. So in this case no other policies are required and the default placeholders suffice:

 


5. Implementing the API response flow

Implementing the actual lookup

The actual lookup of the API key is performed as a Groovy Script action, retrieving its input identification from the custom HTTP header and invoking our microservice. The response for this callout will be stored in the HTTP context in an attribute called “APIKEY”:

System.out.println("LOOKUP-APIKEY: ENTER")

try {
      // Use header X-APIKEY-USER for identifying the key owner
      String user = (String)context.clientRequest.getHeader("X-APIKEY-USER")
      String apiKeyRequestUrl = "https://<<yourhost>>.oraclecloud.com/apikey/" + user

      System.out.println("LOOKUP-APIKEY: invoking retrieval for URL " + apiKeyRequestUrl)
      // Execute callout to retrieve the APIKEY and store the result in the context attribute APIKEY
      oracle.sdp.daf.action.api.ExternalCalloutBuilder apikeyCallout = context.createCallout()
      apikeyCallout.withRequestUrl(apiKeyRequestUrl)
      apikeyCallout.withRequestMethod("GET")
      apikeyCallout.build().send("APIKEY")
      System.out.println("LOOKUP-APIKEY: callout completed, set APIKEY as context attribute for response")
} catch(Exception e) {
  e.printStackTrace()
  throw e
}
System.out.println("LOOKUP-APIKEY: EXIT")

 

Removing the custom HTTP Header

Manipulation of (outbound) HTTP headers is a simple and declarative task in Oracle’s APIPCS:


6. removing custom header (not exposing private parts)

 

Retrieving and Injecting the API key

As the response from the callout is added as an attribute to the context, we still need to retrieve it and parse it to extract the actual API key value we need to add as an outbound request header ‘ovio-api-key’:

 

System.out.println("INSERT-APIKEY: ENTER")
try {
      oracle.sdp.daf.action.api.HttpResponse resp = (oracle.sdp.daf.action.api.HttpResponse) context.getAttribute("APIKEY")
      Map apikeyResponse = [:]
      if ( resp != null){
        def body = resp.getBodyAsType(String.class)
        System.out.println("INSERT-APIKEY: response from APIKEY retrieval: " + body)
        def parser = new groovy.json.JsonSlurper()
        apikeyResponse = (Map)parser.parseText(body)
        String apiKey = apikeyResponse["apikey"] ? apikeyResponse["apikey"] : "no-apikey-found"
        System.out.println("INSERT-APIKEY: extracted APIKEY: " + apiKey)
        context.getSouthboundCallout().withHeader("ovio-api-key" , apiKey)
        System.out.println("INSERT-APIKEY: inserted APIKEY into outbound call")
      }
} catch(Exception e) {
    e.printStackTrace()
    throw e
}
System.out.println("INSERT-APIKEY: EXIT")

Testing the API

And finally, after publishing the API definition from the management server to the gateway(s), we have arrived in the testing phase. Using the POST operation on the Node.js API the external API key has been stored inside the microservice and we are ready to invoke our internal endpoint to verify whether it correctly returns the expected data. But first, what is the expected data?

Again, Postman comes to the rescue … in this case, we do need to provide the ovio-api-key as the header:


7. directly invoking the external API

Next up, the invocation through APIPCS; as you can see from the previous request and the configuration described in the previous steps, the resource path (/kvk/62021397/0000) needs to be added onto the internal endpoint (/openkvk). From the request to APIPCS you can also see that the header provided this time is the custom X-APIKEY-USER and its value is the internal id:


8. Successful API invocation through APIPCS

Invoking the APIPCS implementation with an unknown internal identification results in an error message and HTTP 401 status being returned:


9. Failed API invocation through APIPCS (unknown user)

 

Conclusion

In this blog I have shown how you can use the API Platform Cloud Service as an outbound gateway. Not directly the first scenario you think about when considering an API Gateway, but still a use case for which APIPCS can offer certain advantages as centralization of translation services etc.

Final words

The proof of concept was performed on a pre-release version of APIPCS, which means that the functionality may have changed as compared to the GA release. Specifically, APIs used in the Groovy scriptlets may have been modified or may be exposed no longer …

“Maison Prettyboy” (first picture) is the name of a fictive ladies only club, run by F. Jacobse & Tedje van Es, the massively popular libertarians as created in the late seventies and early eighties by Dutch comedians Kees van Kooten en Wim de Bie.  Also, it has become my favourite test case for looking up the Chamber of Commerce Data

Over de auteur

Deel deze pagina