Google Cloud Functions for external testing of salesforce API endpoints

This will be some sort of unique use case which most of you will never meet in production but there’s a chance it might be useful for someone as is. Also it might be converted to more useful anonymous webform collecting variant.

Imagine a case when you have to give the access to salesforce to someone on the 3rd part without giving actual salesforce credentials. You can call it anonymous access. My case was a scenario when I developed a sophisticated integration with external system (1C:Enterprise platform) which must be run by a scheduler. But for testing purposes I had to give the ability to fire callout from Salesforce to 1C for an external developer who made a stuff on 1C part. Usually you perform such testing by yourself as it’s your part of integration. But he need to run this invocation too in order to profile his code. It looks that I can do it for him by request but he need to do that as many times as he want and when he want. Also final testing between all systems should be done on Salesforce production data with UAT 1C environment which will be converted to production version right after successful testing.

When I was thinking about possible solution I discovered a several ways to do this:

  • Create a temporary user in Salesforce for the external developer and allow him to run apex command via developer console
  • Expose VF/Lightning page with button to invoke apex code via community/site
  • Expose REST service via community/site
  • Create a proxy service which can be invoked from external and run inside this service a code with my personal credentials

Solution with user creation was too bad in security. I prefer to not give credentials to someone external if it’s not required for a business task.

Dedicated page required controller code, page and community/site + guest user profile configuration to expose it.

REST service exposed via site/community also requires community/site + guest user profile configuration.

So the last one seems most simple to me in terms of moving parts which has to be created.

The final solution looks like that

Production integration still aimed to be working by scheduler and the testing application requires 2 parts:

  • Salesforce REST endpoint
  • Google Cloud function

Apex RESTS endpoint is very simple

@RestResource(urlMapping='/testing-service')
    global class Test1CIntegration {
        // you know what to do with params
        // generate params list, dynamics queries, proxy param
        // to the external system as request header / param / body
        Map<String, Object> requestJSON;

        @HttpGet
        global static String getInvoicesInJSON() {
            handleRequestParams();
            // do someting with requestJSON
            return JSON.serialize([
                ...query...
                WHERE someField1 =: param1
                AND someField2 =: param2
                AND ...etc...
            ]);
        }

        @HttpPost
        global static SomeCoolWrapperClassObject sendInvoicesTo1C() {
            handleRequestParams();
            // do someting with requestJSON
            // actually send data and return 1C response
            return sendInvoicesTo1C();
        }

        private static void handleRequestParams() {
            requestJSON = (Map<String, Object>) JSON.deserializeUntyped(RestContext.request.requestBody.toString());
            for (String key : requestJSON.keySet()) {
                // generate params as you want
            }
        }
    }

The next part is Google Cloud Function. Instead of it you can use Amazon Lambda or any other similar product. I opted for Google Cloud just in order to practice with it.

So, let’s do it. First you need a Google Cloud Platform account. You will easily setup it by yourself. After setup just find out Cloud Functions in menu and go to it

Use HTTP trigger, it gives you an url which 3rd party person can use to invoke your code with curl or Postman or any other client tool for making requests (even web browser)

Then add required libraries via requirements.txt

I use requests for performing actual requests to Salesforce and simple-salesforce in order to login and get session id. Actually you can do all the stuff with simple-salesforce

add code to main.py

# main.py
from simple_salesforce import Salesforce
import requests
import datetime
import json


def main(initial_request):
    sf_url = 'https://myorg.my.salesforce.com/services/apexrest/testing-service'
    # request made by 3rd party user
    # you can put configuration parameters in here
    # and pass the to Salesforce
    request_json = initial_request.get_json()
    headers = sf_login()
    http_method = 'GET'
    if request_json is not None:
        http_method = 'POST'
    sf_response = requests.request(
        http_method, url=sf_url, json=request_json, headers=headers)
    # return SF response to a client
    return "Test sync run at " + datetime.datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S') + " (UTC)" + "\n Salesforce Response: " + sf_response.json()


def sf_login():
    # login to Salesforce
    salesforce = Salesforce(username='username',
                            password='pass',
                            security_token='token',
                            instance='https://myorg.my.salesforce.com',
                            sandbox=False,
                            version='47.0')
    # get session id and return it as auth header
    session_id = salesforce.session_id.split("!")[1]
    return {"Authorization": "Bearer " + session_id}

click create and that’s it. You cloud function ready to run. You’re so serverless!

Now external developer can use terminal with curl or Postman to perform request to your cloud function which fire SF integration

curl -X POST "https://us-central1-sftest-999.cloudfunctions.net/integration-1C-test" -H "Content-Type:application/json" --data '{"docType":"Invoice", "invoiceNumber": "i-9999"}'

You can also easily modify this code in order to run some anonymous form collection. You just need a form which will be hosted somewhere and use this proxy to post data to Salesforce.

[apex][google cloud functions][google cloud platform][integration][serverless]