3

I want to make an HTTP GET request to AGOL, but I want to route the request through a Python function.

Since I can't host the Python function on AGOL (more info here), I'd like to use AWS-Lambda instead.

HTTP GET requestAWS Lambda Python functionAGOL

What would it take to configure AWS Lambda so that it can serve as a middle tier between the HTTP GET request and AGOL?

4

Here's a sample AWS Lambda setup from a colleague:

  1. Create an AWS account (free).
  2. In AWS Lambda, create a new function.
    • Enter a function name and RuntimePython 3.7
  3. Write the function.
    • This sample script receives an ASSET_ID value from a URL, processes it with Python, and sends additional requests to AGOL. It returns a JSON dictionary.

from urllib.parse import urlencode
from urllib.request import Request, urlopen
import json


# Get a security token to append to all requests
def GetToken():
    username = '<my username>'
    password = '<my password>'

    url = 'https://www.arcgis.com/sharing/rest/generateToken' 
    post_fields = {'username': username,'password':password,'expiration':'60','client':'referer','referer':'http://www.arcgis.com','f':'json' }

    request = Request(url, urlencode(post_fields).encode())
    out = urlopen(request).read().decode()
    resp_dict = json.loads(out)
    # print (resp_dict['token'])
    return resp_dict['token']


# Query a feature service with a where clause returning all fields.  Function returns a json dictionary
def queryFeatureService(url,token,where):

    post_fields = {'token': token,'where':where,'outfields':'*','returngeometry':'false','f':'json' }

    request = Request(url, urlencode(post_fields).encode())
    out = urlopen(request).read().decode()
    resp_dict = json.loads(out)
    return resp_dict


# Get the zone value from the matching Active Transportation feature  
def GetZone(jsonFeatures,zoneField):

    for feature in jsonFeatures['features']:
        # print (feature['attributes']['ZONE_'])
        return feature['attributes'][zoneField]


# Query with ASSET_ID, returning the workorder record with a new "ZONE_" field added from the matching Transportation layer
# 'lambda_handler' is the main function for Lambda.  Code starts here when called
def lambda_handler(event, context):

    urlWorkorders = 'https://services.arcgis.com/Akv3yjcvcvmR0q1R/ArcGIS/rest/services/<my AGOL account name>/FeatureServer/0/query' 
    urlActiveTransportationPoints = 'https://services.arcgis.com/Akv3yjcvcvmR0q1R/ArcGIS/rest/services/Active_Transportation_Points/FeatureServer/0/query'

    token = GetToken()   
    ASSET_ID = event["queryStringParameters"]['asset_id']
  
    jsonWorkorder = queryFeatureService(urlWorkorders, token,"ASSET_ID = '" + ASSET_ID + "'")

    # JSON for the new "ZONE_" field, appends to return Workorder JSON object to give it this missing field
    fldZone = {'name':'ZONE_','type':'esriFieldTypeString','alias':'ZONE_','sqlType':'sqlTypeOther','length':15,'domain':None,'defaultValue':None}
    jsonWorkorder['fields'].append(fldZone)

    # Query the Active Transportation points with the same ASSET_ID
    jsonActiveTransportation = queryFeatureService(urlActiveTransportationPoints,token,"ASSET_ID = '" + ASSET_ID + "'")

    # Get the ZONE_ value
    zone = GetZone(jsonActiveTransportation,'ZONE_')

    # Set the ZONE_ value in the ZONE_ field that was added to workorders
    jsonWorkorder['features'][0]['attributes']['ZONE_'] = zone
    # return (jsonWorkorder)
    return {
    'statusCode': 200,
    'headers': {
    'Access-Control-Allow-Origin' : '*',
    'Access-Control-Allow-Headers' : '*'
        
        },
        'body': json.dumps(jsonWorkorder)
    }

  1. Choose Add TriggerAPI Gateway
  2. Choose Create a new API, REST API, SecurityOpen
  3. Open API Gateway: workorder-API hyperlink
  4. ActionsCreate methodGET ➔ configure as follows:
    • enter image description here
    • Save
  5. Click Method Request header link ➔ expand Query String Parameters
  6. Add query string "asset_id"

Conclusion:

It's a pretty interesting solution that could be useful for people who have similar requirements.


A note about security:

The AWS Lambda function specifies/stores the AGOL username and password. This freaked me out at first.

However, since the username and password are server-side, they are never exposed to the client user.

  • In theory, we could write this same function as an AJAX call in JavaScript, but we would need to embed the credentials in the web code, making it unsecure, so that's why a server-side function is needed.

  • Additionally, we could alter the Lambda function to pass an AGOL-registered app's clientID and Secret for more granular access control—which would not have my username and password embedded in the function.

  • More info here: ArcGIS Web AppBuilder (Developer Edition). See the "Provide an app ID for Web AppBuilder" section (not just limited to just WAB, but for any app that needs a ClientID and Secret).

0

Thanks for your answer above but do you need to install any specific libraries or other tools to get it to run in AWS?

1
  • I got help from a developer I know. So he'd have to answer that question.
    – User1973
    Jan 4 '21 at 1:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.