0
votes

I've created websites with php web forms before, but I'm launching out to try to use a Lambda / API Gateway / SES combination in AWS while launching a website from S3, in order to create a dynamic submission form. If you'd like to take a quick look at the submission form (and error), it's here: https://precious-gemstones.com/about.html

Here is my javascript, which I've stored at the root level in my S3 bucket:

function submitToAPI(e) {
       e.preventDefault();
       var URL = "https://ryj32uh9ki.execute-api.us-east-1.amazonaws.com/email/email";

            var Namere = /[A-Za-z]{1}[A-Za-z]/;
            if (!Namere.test($("#name-input").val())) {
                         alert ("Name must be at least 2 characters.");
                return;
            }

            if ($("#email-input").val()=="") {
                alert ("Please enter your email.");
                return;
            }

            var reemail = /^([\w-\.]+@([\w-]+\.)+[\w-]{2,6})?$/;
            if (!reemail.test($("#email-input").val())) {
                alert ("Please enter a valid email address.");
                return;
            }

       var name = $("#name-input").val();
       var email = $("#email-input").val();
       var message = $("#message-input").val();
       var data = {
          name : name,
          email : email,
          message : message
        };

       $.ajax({
         type: "POST",
         url : "https://ryj32uh9ki.execute-api.us-east-1.amazonaws.com/email/email",
         dataType: "json",
         crossDomain: "true",
         contentType: "application/json; charset=utf-8",
         data: JSON.stringify(data),

         
         success: function () {
           // clear form and show a success message
           alert("Thank you for your inquiry!");
           document.getElementById("contact-form").reset();
       location.reload();
         },
         error: function () {
           // show an error message
           alert("Error; please try again.");
         }});
     }

Here is my Lambda function:

var AWS = require('aws-sdk');
var ses = new AWS.SES();
 
var RECEIVER = '[email protected]';
var SENDER = '[email protected]';

var response = {
 "isBase64Encoded": false,
 "headers": { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': 'precious-gemstones.com'},
 "statusCode": 200,
 "body": "{\"result\": \"Success.\"}"
 };

exports.handler = function (event, context) {
    console.log('Received event:', event);
    sendEmail(event, function (err, data) {
        context.done(err, null);
    });
};
 
function sendEmail (event, done) {
    var params = {
        Destination: {
            ToAddresses: [
                RECEIVER
            ]
        },
        Message: {
            Body: {
                Text: {
                    Data: 'name: ' + event.name + '\nemail: ' + event.email + '\nmessage: ' + event.message,
                    Charset: 'UTF-8'
                }
            },
            Subject: {
                Data: 'Gemstone inquiry: ' + event.name,
                Charset: 'UTF-8'
            }
        },
        Source: SENDER
    };
    ses.sendEmail(params, done);
}

And here is my html code snippet:

                        <div class="contact-form">
                            <form id="contact-form" method="post" action="https://ryj32uh9ki.execute-api.us-east-1.amazonaws.com/email/email">
                                <input name="name" type="text" class="form-control" placeholder="Your Name" required>
                                <br />
                                <input name="email" type="email" class="form-control" placeholder="Your Email" required>
                                <br />
                                <textarea name="message" class="form-control" required rows="10">Your Message</textarea>
                                <br />
                                <input type="submit" class="form-control submit" value="Send inquiry">
                            </form>
            </div>
            </div>
                </div>
            </div>
        </div>
    </div>
    <script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
    <script src="submitToAPI.js"></script>
</body>

Any ideas? Thanks so much for the help! UPDATE: My API Gateway info as seen from my Lambda trigger is as follows: API endpoint: https://ryj32uh9ki.execute-api.us-east-1.amazonaws.com/email/email API type: REST Authorization: NONE Method: POST Resource path: /email Stage: email

No keys or authorization required, and the setup works (I receive the email) when I test from Lambda. The test from the API Gateway post method is also successful. However, it doesn't work from my site, which leads me to believe it's something in my html / javascript code, and I shall review / revise that tonight or tomorrow - but any insights are appreciated!

2
Can you provide information about your API gateway setup? Do you have any api policy, any authentication enabled, vpc, is it private or public, any api keys, ...? The issue is with your api gateway, yet there are no information about how it was setup.Marcin
Hi, the thing is, the Lambda / API Gateway setup work fine when I test from either Lambda or API Gateway themselves. It's when I test from my site that I get this error: {"message": "Could not parse request body into json: Could not parse payload into json: Unrecognized token \'name\': was expecting \'null\', \'true\', \'false\' or NaN\n at [Source: (byte[])\"name=test&email=test%40yahoo.com&message=Your+Message\"; line: 1, column: 6]"} But no, there are no API keys required, no authentication, etc.lorena

2 Answers

2
votes

When you create a stage, the link displayed does not contain the resource part of the URL:

In the code your

aws api gateway URL : https://ryj32uh9ki.execute-api.us-east-1.amazonaws.com/email

the actual url you should be calling the code must be

api + your resource name : https://ryj32uh9ki.execute-api.us-east-1.amazonaws.com/email/<resource_name>

So if I am correct you are missing the resource name at the end of your api url.

For example I've this api gateway deployment

api url : https://asdasdsadsa.execute-api.eu-central-1.amazonaws.com/v1

actual URL which I am calling from my browser for my resource named myaccounts is like below:

api + resource : Request URL: https://asdasdsadsa.execute-api.eu-central-1.amazonaws.com/v1/myaccounts

If your method configuration looks like below means it doesnt have any authorization configured( I am assuming you dont have as per the question you described here)

enter image description here

EDIT

Seems from the error message you shared

{"message": "Could not parse request body into json: Could not parse payload into json: Unrecognized token 'name': was expecting 'null', 'true', 'false' or NaN\n at [Source: (byte[])"name=test&email=test%40yahoo.com&message=Your+Message"; line: 1, column: 6]"}

You have URL encoded data which is being sent to application/json type settings on the API gateway.

So you need to convert your URL encoded data to json format while calling the api endpoint

corresponding developer form thread : HOWTO: Mapping Template v3.0 to convert form POST data or GET query to JSON

0
votes

You need to disable authorization to you endpoint. How to open anonymous access to AWS API Gateway resource Or incorporate authorization to your endpoint into your script.