Ok, lets see if the eevblog AWS knowledge is good.. :-)
I have a lambda that looks up a DynamoDB table and returns a lists based on a value that is posted it. It is quite simple but i've run into a problem with CORS and im not sure how to fix it. I'd ideally like to be able to configure in the CF / SAM templates and just deploy it.. But i'm not sure what is stopping this from working.
The lambda is looks like this
import json
import boto3
from boto3.dynamodb.conditions import Key, Attr
from botocore.exceptions import ClientError
def lambda_handler(event, context):
dynamodb = boto3.resource("dynamodb")
table = dynamodb.Table('learning-values')
_class = "widgets"
body = json.loads(event['body'])
_subclass = body['widget']
try:
response = table.get_item(
Key={
'class': _class,
'subclass': _subclass
}
)
except ClientError as e:
print(e.response['Error']['Message'])
else:
item = response['Item']['data']['options']
return {
"statusCode": 200,
"headers":
{
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers": "Content-Type",
"Access-Control-Allow-Methods": "OPTIONS,POST,GET"
},
"body": json.dumps(
{
"message": item
I used Cloudformation to deploy the API. it creates it, and i'm able to post a value to it and get the expected list back. I have tested it using this small piece of python.
import requests, json, sys, base64
url = 'https://0r746huw6b.execute-api.ap-southeast-2.amazonaws.com/prod/widget' # learn11
widget = sys.argv[1]
payload = {"widget": widget}
header = {"Content-type": "application/json"}
r = requests.post(url, data=json.dumps(payload))#, headers=header)
items = r.json()['message']
print(items)
The response I get is like this
Z:\sam\learning\sandbox\widget>py testmessage.py shape
['round', 'square', 'triangle', 'diamond']
Z:\sam\learning\sandbox\widget>py testmessage.py smell
['fowl', 'stinky', 'nothing', 'fresh-linen', 'vanilla', 'tropical', 'cut-grass']
Z:\sam\learning\sandbox\widget>py testmessage.py colours
['red', 'green', 'blue', 'yellow', 'grey', 'black', 'white']
When i attempt to get that same data from javascript using this html. ( either hosted on S3, or locally) I get CORS errors in the browser.
widget.html:1 Access to XMLHttpRequest at 'https://0r746huw6b.execute-api.ap-southeast-2.amazonaws.com/prod/widget' from origin 'null' has been blocked by CORS policy: Request header field content-type is not allowed by Access-Control-Allow-Headers in preflight response.<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>
<body>
<p>Get Colours</p>
<div ng-app="myLearn" ng-controller="myLearnCtrl">
<h4>{{message}}</h4>
</div>
<script>
var app = angular.module('myLearn', []);
app.controller('myLearnCtrl', function($scope, $http) {
$http.post("https://0r746huw6b.execute-api.ap-southeast-2.amazonaws.com/prod/widget",{"widget":"colours"})
.then(function(response) {
$scope.message = response.data["message"];
});
});
</script>
</body>
</html>
The template i am using to deploy from is relatively simple.
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: '
Sample SAM Template for learning
'
Globals:
Function:
Timeout: 3
Api:
EndpointConfiguration: REGIONAL
Cors: '''*'''
Resources:
LearningAPI:
Type: AWS::Serverless::Api
Properties:
StageName: prod
LearningFunction3:
Type: AWS::Serverless::Function
Properties:
CodeUri: s3://XXXXXXX-lambda-packages/0ab6dbfb0a46f18f11e43af73ee5d578
Handler: app.lambda_handler
Runtime: python3.7
Events:
Learning:
Type: Api
Properties:
Path: /widget
Method: post
RestApiId:
Ref: LearningAPI