Accessing Flask server from my web page - javascript

This is a question continue from this question here.
I am trying to control a servo motor using the image buttons on my web page. My servo controller is in the form of python script (cameraservo2.py) and I am using jQuery to post the data to the python function. The conclusion that I get from asking "how to run python script from webpage" is by using 'Flask' which is totally new to me. However I have installed it successfully using just pip install Flask. (let me know if i miss out anything?)
I have my index.html, cameraservo3.py and routes.py in my /var/wwwfolder. My webserver is by default running and I can access it by my Raspberry Pi IP address from another network computer.
This is my routes.py code:
from flask import Flask, jsonify, render_template, request
from cameraservo3 import turnCamera
app = Flask(__name__)
#app.route('/turn_servo', methods=['POST'])
def turn_servo_ajax():
direction = request.form['direction']
cam_result = turnCamera(direction=direction)
return '<div> {} </div>'.format(cam_result)
if __name__ == '__main__':
app.debug = True
app.run(host='0.0.0.0')
Part of my jQuery script in index.html:
$('#left_button').click(function(){
$.post("/turn_servo", {direction:"left"}).done(function (reply) {
$('#camerapos').empty().append(reply);
alert("left button clicked");});
});
part of my html:
<div id="control_button">
<img src="button_left.png" id="left_button" height="50" width="50">
<img src="button_right.png" id="right_button" height="50" width="50">
<p id="camerapos"> test </p>
</div>
cameraservo2.py can be found in the answer for my question there. I run python routes.py and it gave me
* Running on http://0.0.0.0:5000/
* Restarting with reloader
But the script (cameraservo2.py) doesn't get executed when I click the left_button. What's wrong? Which part have I done wrong??
The quickstart guide of Flask isn't very helpful as well. :/

You'll run into the same-origin policy restrictions unless you serve the index.html file from the same host and port number. It's easiest to just add the index.html page to your Flask server too.
Add a / route that serves the page that will do the AJAX post. You could use a template to fill in the route here for $.post() to. If using Jinja2 for the template, that would be:
#app.route('/')
def homepage():
return render_template('index.html')
and the file index.html in the templates subdirectory of your Flask project with:
$('#left_button').click(function(){
$.post("{{ url_for('turn_servo_ajax') }}", {direction:"left"}).done(function (reply) {
$('#camerapos').empty().append(reply);
alert("left button clicked");});
});
where the {{ }} part is Jinja2 template syntax, and url_for() returns a fully-formed URL for the turn_servo_ajax view function.

Related

Within a Flask endpoint, how to take in a file and return a new file?

I have an endpoint that takes in a csv file given by the user, the function then performs some analysis on it, and the user should then have the report downloaded onto their system.
the code looks similar to this currently:
function uploadFile(file) {
var form = new FormData();
form.append('file', file);
var request = new XMLHttpRequest();
request.open('POST', '/upload');
request.send(form);
}
#app.route("/upload", methods=["POST"])
def endpoint_function():
file = flask.request.files["file"]
analysis_function(pd.read_csv(file)) # Outputs csv to 'filepath'
return flask.send_file(filepath, as_attachment=True)
When the function is triggered from the frontend, it creates the csv, but does not download it to the users system.
I have checked that the report csv is being correctly placed at the filepath.
I wrote a minimum working example of downloading a file from a flask route:
The directory of this app contains two files:
app.py - python script
download.txt - file to be downloaded
app.py:
# app.py
from flask import Flask, send_file
app = Flask(__name__)
#app.route('/')
def index():
return " Download File"
#app.route('/download')
def download_file():
return send_file("download.txt", as_attachment=True)
if __name__ == '__main__':
app.run(debug=True, port=8000, host='127.0.0.1')
Test this code on your machine, if its failing, maybe you have a setting on your browser/firewall to block file downloads.
With the JavaScript, you'll need to await the response from the server, then you should be able to download it as would another file.
Here's a link to a post that shows you how to await the XMLHttpRequest: In JavaScript how do I/should I use async/await with XMLHttpRequest?
Hope this helps!

How to send user specific data using SSE

i am trying to create a social media page where in home page of every user they can see feeds,
feeds from friend's post. when ever my friend create a post i can see the same in my feeds in real time.
For that i am using SSE in python flask. everything working find but after adding few more users only i realise all the post are coming to all logged in people's feed. which wrong, i want to see feeds from only my friends.
Can any one help me how to achieve it. i am sharing the base level code of python and java script.
Client side:
var source = new EventSource("http://172.19.0.3:8044/events");
source.addEventListener('user_feeds', function(event) {
var data = JSON.parse(event.data);
console.log("Even from server ");
console.log(data);
}, false);
Server side
from flask_cors import CORS
from flask_sse import sse
from factory import create_app
app = create_app()
CORS(app)
app.config["REDIS_URL"] = "redis://redis"
input_user_feeds = dict()
app.register_blueprint(sse, url_prefix='/events)
PROMOTION_BLUEPRINT = Blueprint('my_page', __name__, url_prefix='/api/v1/')
#PROMOTION_BLUEPRINT.route('/feeds/<user_id>', methods=["GET"])
def feeds(user_id):
push_feeds(user_id)
return "SUCCESS"
#PROMOTION_BLUEPRINT.route('/user_request/<user_id>', methods=["POST"])
def user_request(user_id):
data = request.json
add_feeds(user_id, data)
return "SUCESS"
def push_feeds(user_id):
while 1 == 1:
if user_id in input_user_feeds:
input_request = input_user_feeds[user_id]
sse.publish(input_request, type='user_feeds')
del input_user_feeds[user_id]
def add_feeds(user_id, data):
input_user_feeds[user_id] = data
if __name__ == '__main__':
app.run(host='0.0.0.0', port=Config.PORT, debug=True)
I trued to do with single user id. but that is also not a good idea.
It will be helpful if anyone having good knowledge in SSE help me find the solution.
Thanks in advance.

API works in Postman, but not on a browser

I created a flask api connecting to my mongodb database.
My initial part of the code looks like:
app = Flask(__name__)
cors = CORS(app, resources={
r"/api/v1/*": {"origin": "*"},
})
client = MongoClient(connection_str)
db = client.get_database(db_name)
#app.route("/api/v1/players", methods = ['GET'])
def get_all_players():
....
This works as I intended when I use Postman, but when I input directly into the browser (localhost:5000/api/v1/players), it shows me an error as follows:
I think this is the reason why my fetch doesn't work.
Any thoughts?
It's the problem with SSL certificate. All you need to do, is add ssl_context='adhoc' to your app.run() call.
An example :
from flask import Flask
app = Flask(__name__)
#app.route("/")
def hello():
return "Hello"
if __name__ == "__main__":
app.run(ssl_context='adhoc')
also you need to install pyopenssl in your virtual environment

how can I get variable from javascript using flask

So I have set up app.py, index.js, index.html in appropriate folder as flask suggests. Index.html gets rendered as when app.py runs then index.html runs index.js which grabs input data from user. I am trying to send this input and send it to python where I can call an API, grab data, and work with it however I cannot think of a way to do this.
my app.py:
import os
from flask import Flask, render_template, jsonify, request, redirect
app = Flask(__name__)
# This will run upon entrance
#app.route("/")
def home():
return render_template("index.html")
#app.route("/stock_data")
def get_stock_data():
# called from index.js Plot function
if __name__ == "__main__":
app.run()
and here is my javascript code:
console.log("everythin works fine.")
d3.select("#stocklabelsubmit").on("click", submitted)
function submitted(){
d3.event.preventDefault();
// grab label inputted.
var inputted_label = d3.select("#stockInput").node().value;
d3.select("#stockInput").node().value = "";
Plot(inputted_label);
};
function Plot(input){
var url = "full url"
// when this function is called call /stock_data function!!
// data is what is returned from python
d3.json(url).then(function(data){
})
}
Everything works fine, when I console log inputted_label at the end of function submitted it works. Now I want to send inputted_label variable to /stock_data. Thanks in advance!
var url = "/stock_data"
This needs to be a valid URL, not just the path to the Flask endpoint. That means it must start with "http://" or "https://" and include a domain. For development purposes, "http://localhost/stock_data" will work. If you ever deploy this to a server, you will want to create a configuration file so that the host name can be configured depending on what environment you are running in.

Sending data from JavaScript to Python function locally with AJAX

I am trying to build a website where a user can enter text, which will be picked up via javascript, and sent to a python function where it will be posted to twitter. For the time being, the python function is being stored locally, along with the rest of the site. However, my AJAX isn't too great and I'm having a few issues.
I have written AJAX code which sends a POST request to the python function with the tweet, and the response is the entire python script. No connection is made to the socket my script is listening to. Below is the AJAX function and the python script. Any ideas what's going on?
Thanks in advance for any help!
$(function(){
$('#PostTweet').on('click', function(e) {
var tweet = document.getElementById("theTweet").value;
var len = tweet.length;
if(len > 140){
window.alert("Tweet too long. Please remove some characters");
}else{
callPython(tweet);
}
});
});
function callPython(tweet){
window.alert("sending");
$.ajax({
type: "POST",
url: "tweet.py",
data: tweet,
success: function(response){
window.alert(response);
}
})
}
And the Python Script:
from OAuthSettings import settings
import twitter
from socket import *
consumer_key = settings['consumer_key']
consumer_secret = settings['consumer_secret']
access_token_key = settings['access_token_key']
access_token_secret = settings['access_token_secret']
s = socket()
s.bind(('', 9999))
s.listen(4)
(ns, na) = s.accept()
def PostToTwits(data):
try:
api = twitter.Api(
consumer_key = consumer_key,
consumer_secret = consumer_secret,
access_token_key = access_token_key,
access_token_secret = access_token_secret)
api.PostUpdate(data)
makeConnection(s)
except twitter.TwitterError:
print 'Post Unsuccessful. Error Occurred'
def makeConnection(s):
while True:
print "connected with: " + str(na)
try:
data = ns.recv(4096)
print data
PostToTwits(data)
except:
ns.close()
s.close()
break
makeConnection(s)
Your problem is that you are working with pure sockets which know nothing about HTTP protocol. Take a look at Flask or Bottle web micro frameworks to see how to turn python script or function into web endpoint.
you need a webserver so that your can make request via web browser.
you can web framework like flask or django or you can use webpy.
A simple example using webpy from their website
import web
urls = (
'/(.*)', 'hello'
)
app = web.application(urls, globals())
class hello:
def GET(self, name):
if not name:
name = 'World'
return 'Hello, ' + name + '!'
if __name__ == "__main__":
app.run()
then you call url(your python function) from javascript.
You can totally write a simple web server using sockets, and indeed you've done so. But this approach will quickly get tedious for anything beyond a simple exercise.
For example, your code is restricted to handling a single request handler, which goes to the heart of your problem.
The url on the post request is wrong. In your setup there is no notion of a url "tweet.py". That url would actually work if you were also serving the web page where the jquery lives from the same server (but you can't be).
You have to post to "http://localhost:9999" and you can have any path you want after:"http://localhost:9999/foo", "http://localhost:9999/boo". Just make sure you run the python script from the command line first, so the server is listening.
Also the difference between a get and a post request is part of the HTTP protocol which your simple server doesn't know anything about. This mainly means that it doesn't matter what verb you use on the ajax request. Your server listens for all HTTP verb types.
Lastly, I'm not seeing any data being returned to the client. You need to do something like ns.sendall("Some response"). Tutorials for building a simple http server abound and show different ways of sending responses.

Categories

Resources