delishas
delishas

Reputation: 17

POST to API from React frontend is not working -- Error 400

I'm trying to send data to my Flask API to get data into my database, but I keep getting the following error: OPTIONS /createUser HTTP/1.1" 400

Reg.js

import React, { Component } from 'react';  

class Reg extends Component {  

  constructor() {  
    super();  

    this.state = {  
      FirstName: '',  
      LastName: '',  
      Email: '',  
      Password: '' 
    }  

    this.Email = this.Email.bind(this);  
    this.Password = this.Password.bind(this);  
    this.FirstName = this.FirstName.bind(this);  
    this.LastName = this.LastName.bind(this);   
    this.register = this.register.bind(this);  
  }  

  Email(event) {  
    this.setState({ Email: event.target.value })  
  }   

  Password(event) {  
    this.setState({ Password: event.target.value })  
  }  
  FirstName(event) {  
    this.setState({ FirstName: event.target.value })  
  }  
  LastName(event) {  
    this.setState({ LastName: event.target.value })  
  }  

  register(event) {  

    fetch('http://localhost:5000/createUser', {  
      method: 'post',  
      headers: {  
        'Accept': 'application/json',  
        'Content-Type': 'application/json',
        'Access-Control-Allow-Origin':'*' 
      },  
      body: JSON.stringify({  
        "FirstName": this.state.FirstName,  
        "Password": this.state.Password,  
        "Email": this.state.Email,  
        "LastName": this.state.LastName 
      })  
    }).then(function(res){
      return res.json();
    }).then(function(data){
      console.log(data);
    }).catch((error) => {
      console.log(error);
    });
  }  

  render() {  

    return (  
      <div>  
        <form className="form" id="addItemForm">
            <input type="text"  onChange={this.FirstName} placeholder="Enter First Name"/>
            <input type="text"  onChange={this.LastName} placeholder="Enter Last Name"/>
            <input type="text"  onChange={this.Email} placeholder="Enter Email"/>
            <input type="password"  onChange={this.Password} placeholder="Enter Password"/>
            <button  onClick={this.register}  color="success" block>Create Account</button>
        </form>
      </div>  
    );  
  }  
}  

export default Reg; 

This is what my Flask API has

@main.route('/createUser', methods=['POST', 'OPTIONS'])
def createUser():
    conn = connection()
    cur = conn.cursor()

    req = request.get_json()
    first = req.get('FirstName')
    last = req.get('LastName')
    email = req.get('Email')
    pw = req.get('Password')

    sql = "INSERT INTO User (first, last, emailAddress, password) VALUES (?, ?, ?, ?)"
    data = (first, last, email, pw)
    cur.execute(sql, data)

    conn.commit()
    cur.close()

    return 'Done', 201

I've tried changing my JSON in case it was malformed, but it didn't change anything. I also tried posting from postman and it works fine from there so I'm thinking its the javascript.

Upvotes: 0

Views: 867

Answers (4)

wiesson
wiesson

Reputation: 6822

From your error message error: OPTIONS /createUser HTTP/1.1" 400, the OPTIONS request is not handled correctly. I guess, Postman is not doing a OPTIONS request by default, so that case works for you. In addition, the route is not returning any json, so return res.json(); //error here fails if it's plain text.

I have modified your example with plain Flask methods. Note: I have also removed the 'Access-Control-Allow-Origin':'*' request header from the Javascript.

@main.route('/createUser', methods=['POST', 'OPTIONS'])
def createUser():
    # handle option request
    if request.method == "OPTIONS":
        response = make_response()
        response.headers["Access-Control-Allow-Origin"] = "*"
        response.headers[
            "Access-Control-Allow-Headers"
        ] = "Origin, Accept, Content-Type"
        response.headers["Access-Control-Allow-Methods"] = "POST,OPTIONS"
        response.headers["Access-Control-Allow-Credentials"] = "true"
        return response

    if request.method == "POST":
        # do your SQL stuff
        conn = connection()
        cur = conn.cursor()

        req = request.get_json()
        first = req.get("FirstName")
        last = req.get("LastName")
        email = req.get("Email")
        pw = req.get("Password")

        sql = (
            "INSERT INTO User (first, last, emailAddress, password) VALUES (?, ?, ?, ?)"
        )
        data = (first, last, email, pw)
        cur.execute(sql, data)

        conn.commit()
        cur.close()

        # make response
        response = make_response("{}")  # return empty JSON response
        response.headers["Access-Control-Allow-Origin"] = "*"
        response.headers[
            "Content-Type"
        ] = "application/json"  # set response type to JSON
        return response

    return "", 405  # method not allowed

And please don't save passwords in plaintext in your database :-)

Upvotes: 0

Patrick Hener
Patrick Hener

Reputation: 135

You can also trastically shorten your Code Part By using Name fields in your input Form Tags like name=Email and designing an universal change handler like so:

onChange(event) {  
    this.setState({ event.target.name: event.target.value })  
  }   

Upvotes: 0

Tokhtar Akhmetov
Tokhtar Akhmetov

Reputation: 1

Try to use this in the block when you retrieve data from the request. 400 error is usually a sign of that server can't get values from your POST request body.

req = request.json
first = req['FirstName']
last = req['LastName']

Upvotes: 0

atadnmz
atadnmz

Reputation: 311

Try to add CORS extension if you are using Chrome and you should enable CORS in backend like springboot @CrossOrigin(origins="http://localhost:3000")

Upvotes: 1

Related Questions