-3

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 = 'inquiry@precious-gemstones.com';
var SENDER = 'no-reply@precious-gemstones.com';

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?

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 soon.

Zoe
  • 27,060
  • 21
  • 118
  • 148
lorena
  • 386
  • 1
  • 2
  • 15
  • 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 Jan 04 '21 at 05:27
  • 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 Jan 04 '21 at 14:55

2 Answers2

2

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

samtoddler
  • 8,463
  • 2
  • 26
  • 21
  • Well, sadly, that is not the issue either. I have tried both ways multiple times (with and without the resource name). I will update again with the resource name - the error will be different, but it's still an error. – lorena Jan 04 '21 at 14:20
  • the above was based on the url you shared, if that's not the case. You should share your api gateway setup. – samtoddler Jan 04 '21 at 14:25
  • Here is the error now that it's updated, and i will update my original question to note the changes / APA setup. {"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]"} – lorena Jan 04 '21 at 14:58
  • as per this error seem like your API expects the requet body in json but it is being passed in the encoded url . So check your API deployment for the settings. – samtoddler Jan 04 '21 at 15:01
  • @lorena updated the answer with the issue you are facing and there is a corresponding developer thread attached for the solution – samtoddler Jan 04 '21 at 15:11
  • Thanks! That makes sense... I'll check it out once I am free from work, and once i get a chance to incorporate and update, I'll mark this answer correct if it solves the issue. – lorena Jan 04 '21 at 18:50
0

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.

George
  • 254
  • 2
  • 6
  • I am not sure that's the issue in this case, as my settings (for both methods) are as follows: Authorization NONE Request Validator NONE API Key Required false – lorena Jan 04 '21 at 04:15
  • Do you have stage in api gateway? – George Jan 04 '21 at 04:26
  • Yes - I just redeployed. Also, I did ensure that I selected the Invoke URL from the stage. – lorena Jan 04 '21 at 05:01