I am making a Web API for a python program I wrote, I am copying a tutorial
This is the API code
#!flask/bin/python
from flask import Flask
from flask import make_response
from flask import request
import requests
import json
app = Flask(__name__)
#app.route('/')
def index():
return "Hello, World!"
if __name__ == '__main__':
app.run(debug=True)
#app.errorhandler(404)
def not_found(error):
return make_response(jsonify({'error': 'Not found'}), 404)
#app.route('/5492946838458/index.html', methods=['POST'])
def create_task():
if not request.json or not 'key' in request.json or not 'name' in request.json or not 'text' in request.json or not 'pack' in request.json:
abort(400)
if 'title' in request.json and type(request.json['title']) != unicode:
abort(400)
if 'description' in request.json and type(request.json['description']) is not unicode:
abort(400)
task = {
'key': request.json['key'],
'name': request.json['name'],
'text': request.json['text'],
'pack': request.json['pack']
}
return (200)
This is the URL I'm sending it to
https://my.websites.url.here/5492946838458/
and the json data I'm sending
{
"key": "key",
"name": "name",
"text": "text",
"pack": "pack"
}
and the headers I get back I get
date: Fri, 04 Sep 2020 17:48:30 GMT
content-length: 0
vary: Origin
accept-ranges: bytes
allow: GET, HEAD, OPTIONS
Why does this happen and how can I fix this
Two problems I can see...
This line shouldn't be floating in the middle of your code. It should be at the very end:
if __name__ == '__main__':
app.run(debug=True)
With its current placement, if you're executing the app with python app.py, the app will run at this point. Routes before it (index) will be available, however routes declared after it (create_task) will not (until you kill the server - when the latter route is added, right before the python process stops).
This problem wouldn't be seen if executing with flask run as the if clause is False.
#app.route('/5492946838458/index.html', methods=['POST'])
for this one you're probably want:
#app.route('/5492946838458/', methods=['POST'])
This declares the URL of that route.
Now a request to https://my.websites.url.here/5492946838458/ should return a successful response. A request to /5492946838458 will return a 308 redirect to the one with the trailing slash.
I'm not sure why you were getting 405 before. Perhaps there's aother route somewhere in your code accepting the request, but not the method.
Related
I am new to flask and I want to return 401 error, I am not using authentication, I am simply using a parameter api_key to check whether the user is authenticated.
I've tried abort(401) and return false, but it returns error 400 'Bad Request', is this the default way it returns a 401. Or is there a different way to do this?
My Code:
import flask
from flask import jsonify, request, Response
from flask_cors import CORS, cross_origin
from GoogleNews import GoogleNews
googlenews = GoogleNews()
googlenews.set_lang('en')
googlenews.set_period('1d')
googlenews.set_encode('utf-8')
app=flask.Flask(__name__)
cors = CORS(app)
app.config['CORS_HEADERS'] = 'Content-Type'
#cross_origin()
#app.route('/', methods=["GET"])
def return_news():
API_KEY = request.args['api_key']
if API_KEY == "xyz":
googlenews.get_news('TECHNOLOGY')
return jsonify(googlenews.result(True)[0:4])
else:
return Response(response="Unauthorized", status=401)
Thankyou
instead, try flask.Response object.
from flask import Flask, Response
app = Flask(__name__)
#app.route("/abort")
def abort():
return Response(response="Unauthorized", status=401)
app.run()
without the actual code it is hard to tell, but I think it is not using the flask abort() but the python internal abort() function.
Check the code below:
import flask
app = flask.Flask("aborter")
#app.route("/abort")
def abort():
return flask.abort(401)
if __name__ == '__main__':
app.run()
Happy Coding
I'm trying to make a flask pipeline which receives data from a python file and sends the data to react which display them.
I currently am stuck trying to receive the data in flask after sending them via post to the URL: localhost:5000/weather-data
The data is being posted with this Code:
dummy_data = {'data': str(msg.payload.decode('iso-8859-1')),
'timestamp': datetime.datetime.now().isoformat()}
response = requests.post(url, data=dummy_data)
print(response.text)
The print result is:
{"data": "{\"region\": \"Jokkmokk\", \"temp_now\": 8.91, \"weather_now\": \"bewölkt\", \"humidity\": 50, \"wind\": 24}",
"timestamp": "2021-02-24T17:23:15.347058"}
Which is all right but then i try to receive the data and return it on the flask side with this code:
from flask import Flask, request
app = Flask(__name__)
#app.route('/')
def test():
return 'HelloWorld'
#app.route('/weather-data', methods=['POST', 'GET'])
def weather_data():
try:
data = request.form.to_dict()
print(data)
return data
except Exception as e:
print(e)
if __name__ == '__main__':
app.run(host='127.0.0.1', debug=True, port=5000)
This runs normally through and my print(data) gives the exact same dictionary back but if i take a look at localhost:5000/weather-data i only see empty curly braces {}
As a Test i tried to return the data without receivng them first with this code:
#app.route('/weather-data', methods=['POST', 'GET'])
def weather_data():
return {"data": "{\"region\": \"Fishermans City\", \"temp_now\": 6.87, \"weather_now\": \"st\\u00fcrmisch\", "humidity\": 52, \"wind\": 58}",
"timestamp": "2021-02-23T18:32:49.120861"}
Like this it perfectly worked and showed the Data on the website.
Edit:
I think this is a stupid question for some of you but because i am kinda new to this i wanted to ask if it is possible that the Data is on the Page but when i reload the Page it overwrites the data with empty curly braces?
If yes is there a way that i can keep them on the Page until i make another Post with new data?
You need to use jsonify
from flask import Flask, request
from flask import jsonify
app = Flask(__name__)
data = dict()
#app.route('/')
def test():
return 'HelloWorld'
#app.route('/weather-data', methods=['POST', 'GET'])
def weather_data():
if request.method == 'POST':
global data
data = request.form.to_dict()
return jsonify(data), 200
else:
return jsonify(data), 200
if __name__ == '__main__':
app.run(host='127.0.0.1', debug=True, port=5000)
Have you tried using json?
response = requests.post(url, json=dummy_data)
and
data = request.json
I am using Python 3.9 and the Flask-JWT-Extended PyPi package in my application. I am writing some test cases and when I POST to the endpoint I am testing with a proper-looking Bearer token, I get an HTTP 422 'Unprocessable Entity'. Google is not turning up an answer. How can I fix this?
# Do the Bearer login
data = {
'username': app.username,
'password': app.password,
}
tokenResponse = client.post("/login", json=data)
assert tokenResponse.content_type == 'application/json'
assert tokenResponse.json['access_token']
And shortly after, in the same test method, I try to POST to the actual endpoint:
print("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
print({"Authorization": f"JWT {tokenResponse.json['access_token']}"})
print("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
response = client.post(endpoint, buffered=False,
content_type='multipart/form-data',
data=data,headers={"Authorization": f"JWT {tokenResponse.json['access_token']}"})
Here is the token printout:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
{'Authorization': 'JWT eyJ0eXAiOiJKV1QilCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2MTI0Nzk5NzAsIm5iZiI6MTYxMjQ3OTk3MCwianRpIjoiYTQyZjU1NmUtYjQ2MS00NTNiLThkM2ItYjk1MmIzYzAwZjc0IiwiZXhwIjoxNjeyNDgwMDMwLCJpZGVudGl0eSI6IlNlbnNvbml4QXBpVXNlciIsImZyZXNoIjpmYWxzZSwidHlwZSI6ImFjY2VzcyJ9.IYrgg2e9VxhLFH0_kwQbmoHKI1wKsKfm3cpK3XZmqyY'}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Here is the traceback.
print("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
print({"Authorization": f"JWT {tokenResponse.json['access_token']}"})
print("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
response = client.post(endpoint, buffered=False,
content_type='multipart/form-data',
data=data,headers={"Authorization": f"JWT {tokenResponse.json['access_token']}"})
> assert response.status_code == 200
E assert 422 == 200
E + where 422 = <Response streamed [422 UNPROCESSABLE ENTITY]>.status_code
../tests/test_endpoints.py:153: AssertionError
First suggestion, if you look at the response.get_json() it should give you a helpful error message for why the 422 was thrown (invalid audience, jwt verification failed, etc). That might help point you in the right direction.
Here is an example of a working spec that creates and passes a JWT in via headers if it helps:
import pytest
from flask import Flask
from flask import jsonify
from flask_jwt_extended import JWTManager
from flask_jwt_extended import jwt_required
from flask_jwt_extended import create_access_token
#pytest.fixture(scope="function")
def app():
app = Flask(__name__)
app.config["JWT_SECRET_KEY"] = "foobarbaz"
JWTManager(app)
#app.route("/login", methods=["POST"])
def login():
return jsonify(access_token=create_access_token("test_user"))
#app.route("/protected", methods=["GET"])
#jwt_required
def access_protected():
return jsonify(foo="bar")
return app
def test_default_headers(app):
test_client = app.test_client()
response = test_client.post("/login")
access_token = response.get_json()["access_token"]
access_headers = {"Authorization": "Bearer {}".format(access_token)}
response = test_client.get("/protected", headers=access_headers)
assert response.status_code == 200
assert response.get_json() == {"foo": "bar"}
I have a flask app deployed to Heroku and would like to receive text from Chatfuel (bot building platform) and send back texts in return.
Now, what I did is to use my heroku app as a web-hook, so that Chatfuel can make a simple GET or POST query to my API. The problem is that I have no experience with Flask or APIs, so I am not sure about how my app can receive information (in json format) and send it back to chatfuel.
This is what I wrote so far:
import os
import sys
import json
import requests
from flask import Flask, jsonify, render_template, request
app = Flask(__name__)
#app.route('/', methods=['GET'])
def verify():
# when the endpoint is registered as a webhook, it must echo back
# the 'hub.challenge' value it receives in the query arguments
if request.args.get("hub.mode") == "subscribe" and request.args.get("hub.challenge"):
if not request.args.get("hub.verify_token") == os.environ["VERIFY_TOKEN"]:
return "Verification token mismatch", 403
return request.args["hub.challenge"], 200
return "Hello world", 200
#app.route("/json", methods=['GET','POST'])
def json():
url = "chatfuel_api"
data = json.load(urllib2.urlopen(url))
if request.json:
mydata = request.json
return "Thanks",200
else:
return "no json received"
#app.route('/hello', methods = ['GET','POST'])
def api_echo():
if request.method == 'GET':
return "ECHO: GET\n",200
if __name__ == '__main__':
app.run(debug=True)
The verify() function works, as I see an 'Hello world' message if I run the app locally. However, both json() and api_echo() don't work, and when my server receives a get or post request from chatfuel, it returns a 404 error.
As you can see, I really have a lot of confusion, and your help would be really invaluable.
Thanks
You need to make sure you have registered the proper webhook url with Chatfuel. For the code you currently have, to hit the json endpoint the url would be https://www.your_server.com/json
The verify route looks like the hub challenge FB sends, so you would have to register the root of your site (that is, with your current code) with FB to hit the verify function. That url would look like this https://www.your_site.com/
Having trouble with performing a POST instead of a GET in Python Urllib. Im running 3.5. Im trying to POST to form field.
I read that urllib.request.Request will default to POST if the data parameter is present. I read this at https://docs.python.org/3/howto/urllib2.html
I duplicate these settings and when I fire up wireshark all I see is GETs and Never a Post even though it looks like the code is executing.
Here is my code:
values = {"field1" : z[2:-1], "Submit":"Save"}
print(values)
data = urllib.parse.urlencode(values)
data = data.encode('utf-8')
print(data)
req = urllib.request.Request("http://www.randomsite.com/myprocessingscript.php", data)
with urllib.request.urlopen(req) as response:
the_page = response.read()
print(the_page)
When I fireup wireshark this is what results from the req line:
GET /myprocessingscript.php HTTP/1.1
Accept-Encoding: identity
Host: ec2-52-91-45-113.compute-1.amazonaws.com
Connection: close
User-Agent: Python-urllib/3.5
HTTP/1.1 200 OK
Date: Wed, 28 Oct 2015 02:47:22 GMT
Server: Apache/2.4.17 (Unix) OpenSSL/1.0.1p PHP/5.5.30 mod_perl/2.0.8-dev Perl/v5.16.3
X-Powered-By: PHP/5.5.30
Content-Length: 23
Connection: close
Content-Type: text/html
no post data to process
ADDITIONALLY When I run the script, this is what i get from the print statements:
{'Submit': 'Save', 'field1': 'hostlab\chris'}
b'Submit=Save&field1=hostlab%5Cchris%5Cr%5Cn'
b'no post data to process'
Traceback (most recent call last):
File "C:\Users\chris\Desktop\test.py", line 20, in
time.sleep(random.randint(5,10))
There are two web files they are accessing. Index.html and myprocessingscript.php:
Index.html:
<h1>randomsite.com.</h1>
####<p>whoami</p>
<form action="myprocessingscript.php" method="POST">
<input name="field1" type="text" />
<input type="submit" name="submit" value="Save">
</form>
</body>
</html>
myprocessingscript.php:
<?php if(isset($_POST['field1'])) {
$data = $_POST['field1'] . "\n";
$ret = file_put_contents('/tmp/mydata.txt', $data);
if($ret === false) {
die('There was an error writing this file');
}
else {
echo "$ret bytes written to file";
}
}
else {
die('no post data to process');
}
HTTP POST works as expected:
#!/usr/bin/env python
from contextlib import closing
try:
from urllib.parse import urlencode
from urllib.request import urlopen
except ImportError: # Python 2
from urllib import urlencode
from urllib2 import urlopen
url = 'http://httpbin.org/post'
data = urlencode({"field1" : "value", "Submit": "Save"}).encode()
with closing(urlopen(url, data)) as response:
print(response.read().decode())
You may see GET only after an http redirect (as the rfc recommends -- no data should be posted on redirect without prompting the user).
For example, here's an http server that redirects POST / requests:
#!/usr/bin/env python
from flask import Flask, redirect, request, url_for # $ pip install flask
app = Flask(__name__)
#app.route('/', methods=['GET', 'POST'])
def index():
if request.method == 'POST':
return redirect(url_for('post'))
return '<form method="POST"><input type="submit">'
#app.route('/post', methods=['GET', 'POST'])
def post():
return 'Hello redirected %s!' % request.method
if __name__ == '__main__':
import sys
port = int(sys.argv[1]) if len(sys.argv) > 1 else None
app.run(host='localhost', port=port)
Making an HTTP POST request using the same code (urlopen(url, data)) leads to the redirection and the second request is GET:
"POST / HTTP/1.1" 302 -
"GET /post HTTP/1.1" 200 -
Again, the first request is POST, not GET. The behavior is exactly the same if you visit / and click submit button (the browser makes POST request and then GET request).
Python issue: "Document how to forward POST data on redirects" contains a link to HTTPRedirectHandler's subclass that posts data on redirect:
#!/usr/bin/env python
from contextlib import closing
try:
from urllib.parse import urlencode
from urllib.request import (HTTPError, HTTPRedirectHandler, Request,
build_opener, urlopen)
except ImportError: # Python 2
from urllib import urlencode
from urllib2 import (HTTPError, HTTPRedirectHandler, Request,
build_opener, urlopen)
class PostHTTPRedirectHandler(HTTPRedirectHandler):
"""Post data on redirect unlike urrlib2.HTTPRedirectHandler."""
def redirect_request(self, req, fp, code, msg, headers, newurl):
m = req.get_method()
if (code in (301, 302, 303, 307) and m in ("GET", "HEAD")
or code in (301, 302, 303) and m == "POST"):
newurl = newurl.replace(' ', '%20')
CONTENT_HEADERS = ("content-length", "content-type")
newheaders = dict((k, v) for k, v in req.headers.items()
if k.lower() not in CONTENT_HEADERS)
return Request(newurl,
data=req.data,
headers=newheaders,
origin_req_host=req.origin_req_host,
unverifiable=True)
else:
raise HTTPError(req.get_full_url(), code, msg, headers, fp)
urlopen = build_opener(PostHTTPRedirectHandler).open
url = 'http://localhost:5000'
data = urlencode({"field1" : "value", "Submit": "Save"}).encode()
with closing(urlopen(url, data)) as response:
print(response.read().decode())
The access log shows two POST requests in this case (the second request is POST):
"POST / HTTP/1.1" 302 -
"POST /post HTTP/1.1" 200 -
Note: you could customize the HTTPRedirectHandler to follow the rfc 2616 behavior.
OK so i figured out what was wrong. The python module "requests.post" will not perform a post if the url is one that redirects. So I had to put the actual url in for it to work and not a url that would direct me to my desired url.
THis is the same for those using urllib