React frontend response error from flask backend - python

I'm creating a react app that utilizes a flask backend that serves as a REST API. Unfortunately, I've been having issues with the fetch command, in that it always seems to say fetch failed loading: [method]. The backend seems to handle the request fine.
127.0.0.1 - - [20/Jul/2021 21:10:35] "GET /api/login HTTP/1.1" 200 -
I've tried the request in postman and it works fine. I'm using a proxy for HTTP://localhost:5000 in my package.json so I don't think this is a CORS problem, and I've also tried using flask_cors to no avail. Has anyone experienced something like this before with fetch API? I'm fairly new to javascript so there may be something I'm not noticing.
Thanks.
Users.py (blueprint)
from . import bp
from flask import jsonify, request, make_response
#bp.route('/login', methods=['GET'])
def login():
return jsonify({'status': 'success'})
init.py (blueprint)
from flask import Blueprint
bp = Blueprint('rest', __name__)
from . import users
init.py (app)
def create_app():
from .config import Config
app = Flask(__name__)
app.config.from_object(Config)
mail = Mail(app)
from .models import db, Visitor, User
db.init_app(app)
migrate = Migrate(app, db)
#app.shell_context_processor
def make_shell_context():
return {"config": Config, "db": db, "Visitor": Visitor, "User": User}
#jwt.init_app(app)
app.register_blueprint(api_bp, url_prefix='/api')
return app
Request (from react button event handler)
export default function LoginUser(props) {
const [user, setUser] = useState({})
function handleChange(e) {
const { name, value } = e.target
switch (name) {
case 'email':
setUser({ ...user, email: value });
break;
case 'password':
setUser({ ...user, password: value });
break;
default:
break;
}
}
function handleSubmit(e) {
fetch('/api/login').then(res => res.json()).then().catch(error => console.log('error'))
}
return (
<Form>
<Form.Group className="mb-3" controlId="LoginEmail">
<Form.Label>Email address</Form.Label>
<Form.Control type="email"
placeholder="Enter email"
name="email"
onBlur={handleChange} />
</Form.Group>
<Form.Group className="mb-3" controlId="LoginPassword">
<Form.Label>Password</Form.Label>
<Form.Control type="password"
placeholder="Password"
name="password"
onBlur={handleChange} />
</Form.Group>
<Button variant="primary" type="submit" onClick={handleSubmit}>
Submit
</Button>
</Form>
)
}
Browser error (Brave)
handleSubmit # main.chunk.js:781
callCallback # vendors~main.chunk.js:24274
invokeGuardedCallbackDev # vendors~main.chunk.js:24323
invokeGuardedCallback # vendors~main.chunk.js:24383
invokeGuardedCallbackAndCatchFirstError # vendors~main.chunk.js:24398
executeDispatch # vendors~main.chunk.js:28633
processDispatchQueueItemsInOrder # vendors~main.chunk.js:28665
processDispatchQueue # vendors~main.chunk.js:28678
dispatchEventsForPlugins # vendors~main.chunk.js:28689
(anonymous) # vendors~main.chunk.js:28900
batchedEventUpdates$1 # vendors~main.chunk.js:42585
batchedEventUpdates # vendors~main.chunk.js:24072
dispatchEventForPluginEventSystem # vendors~main.chunk.js:28899
attemptToDispatchEvent # vendors~main.chunk.js:26382
dispatchEvent # vendors~main.chunk.js:26300
unstable_runWithPriority # vendors~main.chunk.js:56804
runWithPriority$1 # vendors~main.chunk.js:31680
discreteUpdates$1 # vendors~main.chunk.js:42602
discreteUpdates # vendors~main.chunk.js:24084
dispatchDiscreteEvent # vendors~main.chunk.js:26266

Try to change
fetch('/api/login').then(res => console.log(res)).catch(error => console.log('error')) to fetch('/api/login').then(res => res.json()).then(result => console.log(result)).catch(error => console.log('error')).
Because using fetch, your 'res' is just an HTTP response, not the actual JSON. So you need res.json() to get the JSON body.
Edit version
Change <Button variant="primary" type="submit" onClick={handleSubmit}> to <Button variant="primary" type="submit" onClick={(e)=>handleSubmit(e)}>. Also add e.preventDefault() in the handleSubmit function to prevent the page from refreshing.
Note: You should pass your user in api login

Related

POST http://127.0.0.1:5500/ 405 (Method Not Allowed) Upload files to GS bucket Flask app

I am trying to build a Flask application to upload files to a GS bucket. I ran app.py on localhost, and when I try to submit the files, the server raises the 405 Method Not Allowed error. I searched everywhere, and nothing seems to help. Here is my code:
HTML Form:
<form action="/" method="POST" enctype="multipart/form-data">
<input
class="block w-full text-sm text-gray-900 border border-gray-300 rounded-lg cursor-pointer bg-gray-50 dark:text-gray-400 focus:outline-none dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400"
id="multiple_files" type="file" multiple>
app.js:
document.getElementById("request").addEventListener("click", function (event) {
event.preventDefault();
const files = document.getElementById("multiple_files").files;
const formData = new FormData();
for (let i = 0; i < files.length; i++) {
formData.append("multiple_files", files[i]);
}
fetch("/", {
method: "POST",
headers: {
'Access-Control-Allow-Origin': '*'
},
body: formData
})
.then(response => response.json())
.then(data => {
console.log(data);
})
.catch(error => {
console.error(error);
});
});
app.py
import os
import uuid
from flask import Flask, request, redirect, render_template
from google.cloud import storage
app = Flask(__name__)
# Set the bucket name and json authentication file values
bucket_name = "BUCKET_NAME"
auth_file = "AUTH_FILE"
# Initialize Google Cloud Storage client
client = storage.Client.from_service_account_json(auth_file)
bucket = client.get_bucket(bucket_name)
# Route for the file upload form
#app.route("/", methods=["GET", "POST"])
def index():
if request.method == "POST":
# Get the uploaded files
files = request.files.getlist("multiple_files")
# Upload each file to the Google Cloud Storage bucket
for file in files:
# Generate a unique file name
filename = str(uuid.uuid4()) + "-" + file.filename
blob = bucket.blob(filename)
blob.upload_from_file(file)
return redirect("/")
return render_template("index.html")
if __name__ == "__main__":
app.run(debug=True)
Can you please help me? I just started learning web development, and I cannot find any resource to help me fix this. Thanks!
I tried to change the "POST" to "PUT" but it also did not help.

How to make a POST request from Angular to Flask server

I'm working on an application that requires me to upload csv files to a FLASK server from an Angular frontend. i am having difficulties doing that. how can i connect the angular frontend to the backend flask server.
Here's my component.html
<div [hidden] = "submitted">
<form (ngSubmite) = "onSubmit()" action = "http://localhost:5000" method = "post" enctype="multipart/form-data">
<input type="file" name="file" />
<input type = "submit" value="Upload">
</form>
Here's my component.ts
import { Component, OnInit } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Component({
selector: 'app-upload',
templateUrl: './upload.component.html',
styleUrls: ['./upload.component.css']
})
export class UploadComponent implements OnInit {
submitted = false;
constructor() { }
onSubmit(){
this.submitted = true;
}
ngOnInit() {
}
}
here's my flask server
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
#app.route('/upload' , method = ['GET' ,'POST'])
def upload_File():
if request.method == 'POST':
#check if the psot request has the file part
if 'file' not in request.files:
flash('No file part')
return redirect(request.url)
file = request.files['file']
#if the user does not select file , browser alsos
#submite an empty part without filename
if file.filename == ' ':
flash('No selected file')
     filename = secure_filename(file.filename)
     file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
     #return render_template('success.html', name = filename)
return redirect(request.url)
return 'File Uploaded'
Import HttpClientModule in your AppModule's imports.
Inject HttpClient in your component (move that logic into a service later) like this constructor(private readonly http: HttpClient) {}
And finally in your submit method you can do an http request this.http.post(url, body).subscribe()

How do I make changes in a particular React component from a Flask server?

I hope my question is clear enough.
So, I have a React form in component A. I want to pass the fields using an AJAX request to a Flask server, which processes the data received and updates the DOM in component B.
Tried looking up several other SO pages but none of them answered the question. And I'm super new to both AJAX and Flask, so that doesn't help either.
My current code looks like this:
Component A:
import React from "react";
class InputForm extends React.Component {
claimRef = React.createRef();
handleSubmit = event => {
event.preventDefault();
const claim = this.claimRef.current.value;
this.props.addClaim(claim);
$.ajax({
type: "POST",
url: "/test/",
data: claim
})
.done(function(data) {
// self.clearForm();
})
.fail(function(jqXhr) {
console.log("failed to register");
});
};
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Claim:
<textarea name="claim" ref={this.claimRef} placeholder="Claim" />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
export default InputForm;
Flask server:
#!/usr/bin/env python
import os
from flask import Flask, render_template, request
app = Flask(__name__)
#app.route("/")
def index():
return render_template('index.html')
#app.route('/test/', methods=['GET', 'POST'])
def test():
clicked = None
if request.method == "POST":
clicked = request
return render_template('test.html', clicked=clicked)
if __name__ == "__main__":
app.run(host='0.0.0.0', port=os.environ.get('PORT', 3000), debug=True)
I've added a test.html file temporarily, which is supposed to simply print the data, but even localhost:3000/test just prints "None".
I get absolutely no errors in any part of the application, and I also get status 200 in the network tab of the webpage, which means that the data is being accepted.
How do I access the passed data and subsequently, print it in component B?
There is nothing wrong with your reactjs http post, however I would recommend you to use the fetch api. However, when you want to talk to the client from your server you have to use json.
Here is how you would make an http request to the server try this:
const data = this.claimRef.current.value;
fetch('/test/', {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(data), // body data type must match "Content-Type" header
})
.then(response => response.json())
.then(data => console.log(data));
Once you create make the http post to the server, this is how you retrieve the data from the server (flask)
#app.route('/test/', methods=['GET', 'POST'])
def test():
clicked = None
if request.method == "POST":
data = request.json
print(data) #json data from client (reactjs)
return jsonify(data='test')
# jsonify returns http response as json
Try it and see what you get! I hope this helps and good luck!
Be aware of CORS
fetch api
https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch

Returning either render_template, or jsonify from Flask as jQuery response

I am trying to create a login page, that after entering incorrect username or password displays an error in the paragraph [working], or redirects the user to the dashboard if the login was successful [not working].
The HTML for the login form looks as follows
<form id="login" action="/login" method="post">
<fieldset>
<legend>Login to the Metalworks</legend>
Username:<br>
<input type="text" name="username"><br>
Password:<br>
<input type="password" name="password"><br><br>
<input type="submit" value="Login">
</fieldset>
</form>
<br>
<p id="result" style="font-size:24px; font-weight:bold"></p>
then I have a JS script that sends a HTTP request to my webserver after hitting the submit button
$(document).ready(function() {
$("#login").ajaxForm({
url: "/login",
dataType: "json",
success: loginResult
});
});
function loginResult(response)
{
result = document.getElementById("result");
if (!response.success)
{
result.style.color = "red";
result.innerHTML = response.error;
}
}
so far all of this works, I get the username and password in my Flask application, where I compare it to the accounts in the DB and if an error occurs, I return a jsonify-ed object with error, otherwise I'd like to make a redirection to the dashboard.html, which doesn't work
#app.route("/")
def home():
return render_template("login.html", title="Metalworks Login");
#app.route("/login", methods = ["POST"])
def login():
if "username" not in request.form or len(request.form["username"]) == 0: return jsonify({"success":False, "error":"Username is not specified!"});
if "password" not in request.form or len(request.form["password"]) == 0: return jsonify({"success":False, "error":"Password is not specified!"});
username = request.form["username"];
password = request.form["password"];
cursor = accountsCollection.find({"username":username});
try:
account = cursor[0];
except:
return jsonify({"success":False, "error":"Could not find account {}!".format(username)});
if account["password"] != password:
return jsonify({"success":False, "error":"Incorrect password!"});
# this does nothing
return render_template("dashboard.html", title="Metalworks Dashboard");
1, any ideas on how to properly redirect after successful login?
2, what is the proper way of handling the session, setting timeout etc?
1.
You can use redirect to redirect user to other routes.
For example:
from flask import Flask, render_template, request, redirect, jsonify
app = Flask(__name__)
#app.route("/")
def home():
return render_template("login.html", title="Metalworks Login")
#app.route("/dashboard")
def dashboard():
return render_template("dashboard.html", title="Metalworks Login")
#app.route("/login", methods = ["POST"])
def login():
if "username" not in request.form or len(request.form["username"]) == 0: return jsonify({"success":False, "error":"Username is not specified!"})
if "password" not in request.form or len(request.form["password"]) == 0: return jsonify({"success":False, "error":"Password is not specified!"})
username = request.form["username"]
password = request.form["password"]
account = {"username": "admin", "password": "admin"}
if account["username"] != username or account["password"] != password:
return jsonify({"success":False, "error":"Incorrect password!"})
return redirect("/dashboard")
app.run(debug=True)
dashboard.html:
<h1>Dashboard</h1>
Output after inserting admin as username and password:
2.
I would suggest to try Flask-Login for login, logout and login_required functionalities.
From official documentation: login-example using Flask-Login

How to integrate Captcha (Recaptcha) for WTForms in CherryPy

I want to use a RecaptchaField() in my WTForms, such as:
class MyForm(Form):
name = StringField('Your name', [InputRequired(message='Please enter your name!')])
recaptcha = RecaptchaField() # RecaptchaField as provided by Flask-WTF
submit = SubmitField('Send')
Since I am using CherryPy, I am not sure whether or not I should use Flask-WTF, because Flask is a whole framework itself. I am wondering if I can use the Recaptcha functionality of Flask-WTF within my CherryPy solution. I tried the following:
from wtforms import StringField
from wtforms.validators import InputReqired
from flask.ext.wtf import Form
from flask.ext.wtf.recaptcha import RecaptchaField
# ...
form = MyForm() # Somewhere in my code
as seen in this Example here. I get the following Exception:
RuntimeError: working outside of application context
It means I have to properly set up a Flask app considering the right context... This is where I am starting to wonder if I am doing the right approach. Is there no other way than set up a separate Flask app inside my CherryPy app??
My answer is mostly relevant to CherryPy and reCaptcha parts of the question. In my opinion, usage of WTForms and other similar libraries leads to a design problem when, speaking in terms of MVC-like design, you scatter the view and the controller into your own code and WTForms code/configuration. Things are simple when you manage one thing in a single place. Thus I suggest to use template engine like Jinja2 for the view (you can create a macro for a repetitive form element) and use input validation library like voluptuous in the controller (you can use same schema for form and API validation).
If you can't avoid WTForms, just grab validateRecaptcha and turn it into WTForms custom validator.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import urllib
import json
import cherrypy
import voluptuous as volu
config = {
'global' : {
'server.socket_host' : '127.0.0.1',
'server.socket_port' : 8080,
'server.thread_pool' : 8
},
'/' : {
'recaptcha' : {
# By default, all keys work on localhost
'siteKey' : '6LeYIbsSAAAAACRPIllxA7wvXjIE411PfdB2gt2J',
'secret' : '6LeYIbsSAAAAAJezaIq3Ft_hSTo0YtyeFG-JgRtu'
}
}
}
def validateRecaptcha(value):
'''https://developers.google.com/recaptcha/docs/verify'''
if 'g-recaptcha-response' not in cherrypy.request.params:
raise volu.Invalid('Recaptcha response is missing')
payload = urllib.urlencode({
'secret' : cherrypy.request.config['recaptcha']['secret'],
'remoteip' : cherrypy.request.headers['remote-addr'],
'response' : cherrypy.request.params['g-recaptcha-response']
})
url = 'https://www.google.com/recaptcha/api/siteverify'
response = json.load(urllib.urlopen(url, payload))
if not response['success']:
cherrypy.log(str(response))
raise volu.Invalid(response['error-codes'])
class App:
#cherrypy.expose
def index(self, **kwargs):
form = dict(form = {'value': ''}, errors = '')
if cherrypy.request.method == 'POST':
schema = volu.Schema({
'value' : volu.All(unicode, volu.Length(min = 8, max = 16)),
'g-recaptcha-response' : validateRecaptcha,
}, required = True, extra = True)
try:
kwargs = schema(kwargs)
except volu.MultipleInvalid as ex:
form = dict(form = kwargs, errors = {e.path[0] for e in ex.errors})
else:
raise cherrypy.HTTPRedirect('#success')
return '''<!DOCTYPE html>
<html>
<head>
<title>reCAPTCHA demo</title>
<script src="https://www.google.com/recaptcha/api.js" type="text/javascript"></script>
</head>
<body>
<form action="/" method="POST">
<div style='border: 1px red solid'>{errors}</div>
<div>Name</div>
<input type="text" name="value" value="{form[value]}"/>
<br/>
<div class="g-recaptcha" data-sitekey="{0}"></div>
<br/>
<input type="submit" value="Submit"/>
</form>
</body>
</html>
'''.format(cherrypy.request.config['recaptcha']['siteKey'], **form)
if __name__ == '__main__':
cherrypy.quickstart(App(), '/', config)

Categories

Resources