Some Hints and Tips when using Oracle Functions

January 27, 2020 | 3 minute read
Angelo Santagata
Architect
Text Size 100%:

Introduction

I recently completed a blog post on how to extend Oracle SaaS using VBCS and Oracle Functions and am in the process of publishing the code. Whilst I was writing this piece of code I learnt a lot about Functions and ran into many situations which I think a lot of other developers would run into . This blog post collates them into a single blog post (which I may update regularly) and Im hoping it is useful to you all.

How to expose Functions as REST Services

Functions themselves are exactly what they say "functions" , small pieces of code which do "something" . Oracle Functions themselves are not REST aware in that they don't have "out of the box " support for REST but you can easily access a function from a REST client by using the Oracle API gateway.

The general steps are:

  1. Deploy your Function
  2. Create the API gateway. The gateway should be deployed into the same VCN, and subnet, as the Oracle Functions application. If you don't have this then you will need to setup some network routes so that API Gateway can call the Functions which unless is absolutely required is a unnecessary overhead..
  3. Create a API Gateway deployment 
  4. Within the deployment add your paths, one per REST Verb/URI,  and map it to the function

Voila, job done.

If you want to support multiple versions of your functions then the easiest thing to do is create multiple entries for the functions with different paths, e.g.

e.g.

/cart/v1    -> Maps to OCID1

/cart/v2    -> Maps to OCID2

/cart/latest    -> Maps to OCID2

In the above example /cart/v2 and /cart/latest both point to the same function.

The other gotcha you may face, is that you've forgotten to expose ports in the VCNs security list, e.g. port 443 for SSL.

How to expose custom HTTP Error codes from Oracle Functions

The scenario here is that you want to return a custom error code from Oracle Functions, e.g. HTTP-401 (Un-Authorized) or HTTP-404 (Not Found). When reading the documentation you might think the right solution is to use a custom output event e.g. line 3 below

      OutputEvent out = OutputEvent.fromBytes(
            OutputEvent.fromBytes(("Not found : ").getBytes(), // Data
            OutputEvent.SUCCESS,     // Set the status code here?
            "text/plain",            // Content type
            Headers.fromMap(customHeaders)  // and additional custom headers on output
        );

This is not correct, if you want to return a custom error code then the function needs to return SUCCESS (the function succeeded but with a functional error) and then use the gateway to return a custom header.  e.g.

 public OutputEvent handleRequest(InputEvent rawInput, HTTPGatewayContext hctx)  
 {
        // process request
        // Do something which causes a not found error
        LOGGER.info("NotFoundException Error ");
        int SC_NOTFOUND=401;
        int CT_TEXT_PLAIN="text/plain";
        hctx.setStatusCode(SC_NOTFOUND);
        return OutputEvent.fromBytes(("Not found : ").getBytes(),
               OutputEvent.Status.Success,
               CT_TEXT_PLAIN    // Content type
               );
 }

Storing secure "things" in Functions Configurations

In my recent POC I needed to store the OAuth secret somewhere so that an IDCS security function could retrieve it. Initially I thought just storing it in the Oracle Functions configuration variables would be OK, but after speaking to a "security conscious" buddy of mine (Olaf!), we decided it was not.

You'll see from this example (and NO these are not real client ids or secrets), that all the configuration variables are displayed in clear text. Not good if your storing something which is supposed to be secret, or at the very least restricted.

The solution was to use the Oracle Key Management Services in OCI instead. With Oracle KMS you can define a Keystore and ask KMS to "encrypt" your secret data and then using the oracle OCI functions you can decrypt the data on the fly.

For more information see this blog article Secure storage of confidential configuration data in Oracle Functions using Oracle OCI Key Management Services

Watch your memory

When developing Functions you need to look at the memory consumption of what your developing. Java is quite memory hungry and whilst it will work fine with 128Mb of memory (the default) , once you start using frameworks like Jersey or better still Apache Http Client, you may find that the service runs a little slowly. This may be because the garbage collector is running around and slowing things down. 

You can increase memory to 1GB and for myself I tend to allocate 256Mb for java functions.

schema_version: 20180708
name: saasopportunitiesfn
version: 0.0.139
runtime: java
build_image: fnproject/fn-java-fdk-build:jdk11-1.0.104
run_image: fnproject/fn-java-fdk:jre11-1.0.104
cmd: com.example.saas.fn.cloudnativesaas.SaaSOpportunitiesFunctions::handleRequest
memory: 256
timeout: 60

That's it for now, but I'll be updating this blog article with more tips as and when I find them!!

Angelo Santagata

Architect

25+ years of Oracle experience, specialising in Technical design and design authority of Oracle Technology solutions, specialising in integrating technology with Oracles SaaS products.

Extensive credible communication skills at all levels, from hard core developers to C-Level executives.

Specialities: Oracle Fusion Apps Integration, Oracle Cloud products, SaaS Integration architectures, Engaging with SIs & ISVs, Technical Enablement, Customer Design Reviews,  advisory and project coaching.

TOGAF 9 Architect and Oracle Cloud Infrastructure Architect Certified


Previous Post

Secure storage of confidential configuration data in Oracle Functions using Oracle OCI Key Management Services

Angelo Santagata | 4 min read

Next Post


API Platform CS - Compressed payload handling

Andy Knight | 3 min read