1

I have an angular-5 component with the following form:

    <form (ngSubmit)="onSubmit()" #contactForm="ngForm">
      <div class="form-group">
        <label for="name">Name</label>
        <input type="text" class="form-control" placeholder="Your first name" id="name" required
               [(ngModel)]="model.name" name="name" #name="ngModel"/>
        <div [hidden]="name.valid || name.pristine"
             class="alert alert-danger">
          Name is required
        </div>

        <label for="number">Number</label>
        <input type="text" class="form-control" placeholder="Your phone number" id="number"
               [(ngModel)]="model.number" name="number"/>

        <label for="email">Email</label>
        <input type="text" class="form-control" placeholder="Your email address" id="email" required
               [(ngModel)]="model.email" name="email" #email="ngModel"/>
        <div [hidden]="email.valid || email.pristine"
             class="alert alert-danger">
          Email is required
        </div>

        <label for="comment">Comment</label>
        <textarea type="text" class="form-control" placeholder="Your enquiry" id="comment" required
                  [(ngModel)]="model.comment" name="comment" #comment="ngModel"></textarea>
        <div [hidden]="comment.valid || comment.pristine"
             class="alert alert-danger">
          You need to say something
        </div>
      </div>
      <button type="submit" class="btn btn-success">Submit</button>
    </form>

There's other stuff around it, but this is the essence.

This is handled by the typescript component:

import { Component, OnInit, OnDestroy } from '@angular/core';
import { ContactPostService } from "../contact-post.service";
import {Contact} from "../contact";

@Component({
  selector: 'app-contact-form',
  templateUrl: './contact-form.component.html',
  styleUrls: ['./contact-form.component.css']
})
export class ContactFormComponent implements OnInit, OnDestroy {

  model: Contact = new Contact();

  submitted = false;

  constructor(private postService: ContactPostService) {}

  onSubmit() {

    console.log('from the form: ' + this.model.name + ', ' + this.model.number + ', ' + this.model.email + ', ' + this.model.comment);

    this.postService.saveContact(this.model)
      .subscribe(data => {
        console.log(data);
      });
    this.submitted = true;
  }

  ngOnInit() { }

  ngOnDestroy() { }

  newContact() {
    this.model = new Contact();
  }

}

Then there is the service referred to that does the actual posting:

import { Injectable } from '@angular/core';
import { HttpClient, HttpErrorResponse, HttpHeaders } from '@angular/common/http';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import { Contact } from './contact';
import { ErrorObservable } from 'rxjs/observable/ErrorObservable';
import { catchError } from 'rxjs/operators';

@Injectable()
export class ContactPostService {

  private API_ENDPOINT = 'https://ovo5xmxf7e.execute-api.ap-southeast-2.amazonaws.com/prod/ContactFormLambda';

  constructor(private http: HttpClient) {}

  saveContact(form: any) {
    console.log('from the form: ' + form.name + ', ' + form.number + ', ' + form.email + ', ' + form.comment)

    let contact: Contact = {
      subject: 'Enquiry from ZenithWebFoundry',
      name: form.name,
      number: form.number,
      email: form.email,
      comment: form.comment
    };

    return this.http.post(this.API_ENDPOINT, contact)
      .pipe(
        catchError((error) => this.handleError(error))
      );
  }

  private handleError(error: HttpErrorResponse) {
    if (error.error instanceof ErrorEvent) {
      console.error('An error occurred:', error.error.message);
    } else {
      console.error(
        `Backend returned code ${error.status}, ` +
        `body was: ${error.error}`);
    }
    return new ErrorObservable(
      'Something bad happened; please try again later.');
  }
}

Basically, its to post four fields and a subject value to a lambda, I have written in AWS. I have tested the Lambda from the gateway and I know that it works (I get the emails that it sends. What seems to be the problem is the API gateway for the Lambda. As soon as I enable CORS, I get the following errors in the client console (Chrome Developer Tools)

POST https://ovo5xmxf7e.execute-api.ap-southeast-2.amazonaws.com/prod/ContactFormLambda 500 () /contact:1 Failed to load https://ovo5xmxf7e.execute-api.ap-southeast-2.amazonaws.com/prod/ContactFormLambda: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://zenithwebfoundry.com' is therefore not allowed access. The response had HTTP status code 500. main.630e523b47c705dd5494.bundle.js:1 Backend returned code 0, body was: [object ProgressEvent]

I find that the OPTIONS works fine:

Request

URL:https://ovo5xmxf7e.execute-api.ap-southeast-2.amazonaws.com/prod/ContactFormLambda
Request Method:OPTIONS
Status Code:200 
Remote Address:54.230.243.44:443
Referrer Policy:no-referrer-when-downgrade

Response Headers

access-control-allow-headers:Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token
access-control-allow-methods:DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT
access-control-allow-origin:*
content-length:0
content-type:application/json
date:Tue, 06 Feb 2018 10:05:33 GMT
status:200
via:1.1 6884828476070d32978b45d03c1cc437.cloudfront.net (CloudFront)
x-amz-cf-id:DQ4SqBJgRRU9HG4jOLu03Jvg555B9Jv_J3KH9oczNWojhiIN14aCwA==
x-amzn-requestid:450ff8a0-0b25-11e8-850f-b3335987eeef
x-cache:Miss from cloudfront

Note how it returns with the "access-control-allow-origin:*" header response, so I would have thought that the POST following this would be OK, but the POST fails with the errors above

I started with this setup, just to allow any origin:

Enable CORS

And got a success message:

enter image description here

Same thing happened when I changed out '*' with my domain origin 'http://zenithwebfoundry.com'

So how do you set up your gateway with CORS so that the POST is not blocked? What am I doing wrong?

1 Answer 1

2

I have a partial answer to my question that I can usefully share. Basically when you Enable CORS in the API gateway, it adds the headers

access-control-allow-headers:Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token
access-control-allow-methods:DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT
access-control-allow-origin:*

to the Options response for you. The problem i was having was that the gateway was adding the header, but only for 200 OK, If the Lambda responded with a 500, the headers were not added, and the ajax client would throw the error.

It turned out that while the error was being thrown, the real problem that prevented the email from working was that the form submission had bugs in it that prevented the lambda from working, producing the 500, and triggering the ajax error condition. I have updated the question with the working code.

Now, it seems, I have the opposite problem, even though I have CORS enabled for my domain, the email is still being sent from a non-whitelisted domain (localhost in this case). The ajax error is thrown, sure, but the email still gets sent. I would have thought that the gateway would prevent passage of the command to the lambda in that case.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.