Post Method 405 Error - python

I have a decently intermediate understanding of APIs, and am not trying to host information I've got from APIs onto the web.
This incredibly simple code:
from flask import Flask, request, render_template
import requests
app = Flask(__name__)
#app.route('/temperature', methods=['POST'])
def temperature():
zipcode = request.form['zip']
r = requests.get('http://api.openweathermap.org/data/2.5/weather?zip=' +zipcode+',us&appid=9b56b06ab4c7f06821ccf55e3e10fce5')
json_obj = r.text
return json_obj
#app.route('/')
def index():
return 'hi'
if __name__ == '__main__':
app.run(debug=True)
Is not giving me anything (except the 405 error).
Can someone please explain why my POST method is not working?

While I'm not entirely sure what you have done, here's what I think you did:
You accessed the /temperature page in your browser which is by default a GET-Request.
You then get returned a 405 Method Not Allowed Error, because your route explicitly requires that the page will be accessed via the HTTP-POST Method.
Modify #app.route('/temperature', methods=['POST']) to #app.route('/temperature', methods=['POST', 'GET']) and you should be fine.

I'll post my answer from /r/ flask here, just for posterity.
the line in your code: zipcode = request.form['zip'] implies that you are submitting data from an HTML form to the view via a POST.
If there is no form, then request.form['zip'] does nothing, and is most likely raising the error. Considering that I see no route in your logic there that points to any HTML, I'm guessing that's the issue.
If you have not built a form for the user to submit the zip code, then you could build it into the route logic. For example, you could do:
#app.route('/temperature/<zipcode>')
def temperature(zipcode):
# add some kind of validation here to make sure it's a valid zipcode
r = requests.get('http://api.openweathermap.org/data/2.5/weather?zip=' +zipcode+',us&appid=DONT_SHARE_YOUR_API_KEY')
json_obj = r.text
return json_obj
You could then use http://127.0.0.1:5000/temperature/20003 to see the data for that zip code.
(as a side note, it's often unwise to publicly share your API keys. you may want to generate a new key.)

Related

How to get query parameters from POST request using python [duplicate]

How do you access query parameters or the query string in Flask routes? It's not obvious from the Flask documentation.
The example route /data below illustrates the context that I would like to access that data. If someone requests something like example.com/data?abc=123, I would like access to the string ?abc=123 or to be able to retrieve the value of parameters like abc.
#app.route("/data")
def data():
# query_string = ???
return render_template("data.html")
from flask import request
#app.route('/data')
def data():
# here we want to get the value of user (i.e. ?user=some-value)
user = request.args.get('user')
The full URL is available as request.url, and the query string is available as request.query_string.decode().
Here's an example:
from flask import request
#app.route('/adhoc_test/')
def adhoc_test():
return request.query_string
To access an individual known param passed in the query string, you can use request.args.get('param'). This is the "right" way to do it, as far as I know.
ETA: Before you go further, you should ask yourself why you want the query string. I've never had to pull in the raw string - Flask has mechanisms for accessing it in an abstracted way. You should use those unless you have a compelling reason not to.
I came here looking for the query string, not how to get values from the query string.
request.query_string returns the URL parameters as raw byte string (Ref 1).
Example of using request.query_string:
from flask import Flask, request
app = Flask(__name__)
#app.route('/data', methods=['GET'])
def get_query_string():
return request.query_string
if __name__ == '__main__':
app.run(debug=True)
Output:
References:
Official API documentation on query_string
We can do this by using request.query_string.
Example:
Lets consider view.py
from my_script import get_url_params
#app.route('/web_url/', methods=('get', 'post'))
def get_url_params_index():
return Response(get_url_params())
You also make it more modular by using Flask Blueprints - https://flask.palletsprojects.com/en/1.1.x/blueprints/
Lets consider first name is being passed as a part of query string
/web_url/?first_name=john
## here is my_script.py
## import required flask packages
from flask import request
def get_url_params():
## you might further need to format the URL params through escape.
firstName = request.args.get('first_name')
return firstName
As you see this is just a small example - you can fetch multiple values + formate those and use it or pass it onto the template file.
Werkzeug/Flask as already parsed everything for you. No need to do the same work again with urlparse:
from flask import request
#app.route('/')
#app.route('/data')
def data():
query_string = request.query_string ## There is it
return render_template("data.html")
The full documentation for the request and response objects is in Werkzeug: http://werkzeug.pocoo.org/docs/wrappers/
Try like this for query string:
from flask import Flask, request
app = Flask(__name__)
#app.route('/parameters', methods=['GET'])
def query_strings():
args1 = request.args['args1']
args2 = request.args['args2']
args3 = request.args['args3']
return '''<h1>The Query String are...{}:{}:{}</h1>''' .format(args1,args2,args3)
if __name__ == '__main__':
app.run(debug=True)
Output:
Every form of the query string retrievable from flask request object as described in O'Reilly Flask Web Devleopment:
From O'Reilly Flask Web Development, and as stated by Manan Gouhari earlier, first you need to import request:
from flask import request
request is an object exposed by Flask as a context variable named (you guessed it) request. As its name suggests, it contains all the information that the client included in the HTTP request. This object has many attributes and methods that you can retrieve and call, respectively.
You have quite a few request attributes which contain the query string from which to choose. Here I will list every attribute that contains in any way the query string, as well as a description from the O'Reilly book of that attribute.
First there is args which is "a dictionary with all the arguments passed in the query string of the URL." So if you want the query string parsed into a dictionary, you'd do something like this:
from flask import request
#app.route('/'):
queryStringDict = request.args
(As others have pointed out, you can also use .get('<arg_name>') to get a specific value from the dictionary)
Then, there is the form attribute, which does not contain the query string, but which is included in part of another attribute that does include the query string which I will list momentarily. First, though, form is "A dictionary with all the form fields submitted with the request." I say that to say this: there is another dictionary attribute available in the flask request object called values. values is "A dictionary that combines the values in form and args." Retrieving that would look something like this:
from flask import request
#app.route('/'):
formFieldsAndQueryStringDict = request.values
(Again, use .get('<arg_name>') to get a specific item out of the dictionary)
Another option is query_string which is "The query string portion of the URL, as a raw binary value." Example of that:
from flask import request
#app.route('/'):
queryStringRaw = request.query_string
Then as an added bonus there is full_path which is "The path and query string portions of the URL." Por ejemplo:
from flask import request
#app.route('/'):
pathWithQueryString = request.full_path
And finally, url, "The complete URL requested by the client" (which includes the query string):
from flask import request
#app.route('/'):
pathWithQueryString = request.url
Happy hacking :)
I prefer
user = request.args['user'] if 'user' in request.args else 'guest'
over
user = request.args.get('user')
this way, you can check the url actually contains the query string first
The implementation below worked for me.
from flask import request
def getVerificationStatus():
try:
requestId=int(request.args.get('requestId'))
print(requestId)
status= verificationStepRepository.getVerificationStatus(requestId)
return tb.responsify(200, "success", status)
except Exception as e:
return errorHandler.dispatchInternalServerError(str(e))
Often we just want to map the whole query string into an appropriate python data structure and take it from there. The appropriate structure is a multi-dictionary because keywords can repeat, for example we need to handle A=123&A=456&B=789. A multi-dictionary is a list of 2-tuples where each 2-tuple contains the key as its first item and the list of values as its second, so the above goes to [('A',['123','456']),('B',['789'])]. All of this is achieved by
qstr = request.args.lists() # A generator for the multi-dict
qstr = list(qstr) # To get the actual multi-dict
If all you want is a dictionary where the first occurrence of a duplicate keyword is used you can just go
qstr = request.args.to_dict()
This can be done using request.args.get().
For example if your query string has a field date, it can be accessed using
date = request.args.get('date')
Don't forget to add "request" to list of imports from flask,
i.e.
from flask import request
If the request if GET and we passed some query parameters then,
fro`enter code here`m flask import request
#app.route('/')
#app.route('/data')
def data():
if request.method == 'GET':
# Get the parameters by key
arg1 = request.args.get('arg1')
arg2 = request.args.get('arg2')
# Generate the query string
query_string="?arg1={0}&arg2={1}".format(arg1, arg2)
return render_template("data.html", query_string=query_string)
This Code worked for me:
from flask import Flask, request
app = Flask(__name__)
#app.route('/')
def search():
query = request.args
for key,value in query.items():
print(key,value)
return "Hello World"
if __name__ == '__main__':
app.run(debug=True)

How to deal with Facebook's Verification requests on flask app

Im setting up a flask app on Heroku to set up web hooks for phishing certificates pulling from Facebook's certificate transparency api. I am trying to get pass facebook's verification requests (facebook sending a GET request asking for hub.challenge) however I do not understand how to give them the required information. Before suggesting I use facebook's prebuilt Heroku app, I am doing this to learn.
I tried looking up more information on GET requests however this hasn't helped me solve this problem.
This is facebook's website on this. https://developers.facebook.com/docs/graph-api/webhooks/getting-started#verification-requests
#app.route("/facebook", methods=['GET', 'POST'])
if request.method == 'GET':
def get_facebook(mode, challenge, verify_token):
#not sure what to put in here
After reviewing the docs, a few pointers:
You'll receive the request as a GET, so you won't need the 'POST' value in methods
The values sent from Facebook will be request args, and can be accessed using request.args.get('e.g.')
Facebook is expecting an int to be returned, which is up to you to decide what this is.
The result (disclaimer: this is untested!):
import datetime
from flask import jsonify
#app.route("/facebook", methods=['GET'])
def get_facebook():
my_token = 'abc123' # The token you setup on the App dashboard
if request.args.get('hub.verify_token') == my_token:
# The token is valid, return the (current datetime as an int)
# Assuming facebook is expecting a JSON result value
return jsonify({'hub.challenge': int(datetime.datetime.now().timestamp())})
return 'invalid', 403

Unit testing Python Google Cloud HTTP functions - need to pass in a request object

I'm getting started writing Google Cloud http Functions using Python and I would like to include unit tests. My function only responds to POST requests so the basic outline of my function is:
def entry_point(request):
if request.method == 'POST':
# do something
else:
# throw error or similar
I want to write a simple unit test to ensure that if the function receives a GET request the response has a 405 status.
Hence in my unit test I need to pass in a value for the request parameter:
def test_call(self):
req = #need a way of constructing a request
response = entry_point(req)
assert response.status == 405 # or something like this
Basically I need to construct a request then check that the response status is what I expect it to be. I've googled around and found loads of pages that talk about mocking and all sorts of stuff that I frankly don't understand (I'm not a crash hot developer) so I'm hoping someone can help me with an idiot's guide of doing what I need to do.
I did find this: https://cloud.google.com/functions/docs/bestpractices/testing#unit_tests_2:
from unittest.mock import Mock
import main
def test_print_name():
name = 'test'
data = {'name': name}
req = Mock(get_json=Mock(return_value=data), args=data)
# Call tested function
assert main.hello_http(req) == 'Hello {}!'.format(name)
def test_print_hello_world():
data = {}
req = Mock(get_json=Mock(return_value=data), args=data)
# Call tested function
assert main.hello_http(req) == 'Hello World!'
which kinda helped but it doesn't explain how I can specify the request method (i.e. GET, POST etc...).
It is probably late to also comment on this one, but I was going through the same quest. How to REALLY unit test a cloud function without mocks and/or Flask test client. For the records, at the Google Cloud Platform Python Docs Samples, it is explained how to use Flask test_request_context() functionality with some examples to achieve this (without having to create Request object by hand).
Just dawned on me that I was rather over-thinking this somewhat. For the purposes of testing my code doesn't actually require a real Flask request passed to it, it merely requires an object that has the attributes my code refers to. For me, this will do:
import unittest
from main import entry_point
class Request:
def __init__(self, method):
self.method = method
class MyTestClass(unittest.TestCase):
def test_call_with_request(self):
request = Request("GET")
response = entry_point(request)
assert response.status_code == 405

Python Flask local server not updating

I am starting to learn Flask, so I am a noob in this stuff, but I have ran out of ideas to implement, that is why I came here to ask. I have python script that makes a GET request to the API and it returns me a QRcode, after that I get the QRcode and add it to my html, everything works fine.
But I have this code checking for the JSON response that the API gives me, it haves three responses: "loading", "authenticated" & "got qr code".
req = requests.get('this is the link with my API token')
json_content = req.content
# parsed JSON content, ready to use
parsed_json = json.loads(json_content)
#app.route("/")
def index():
if parsed_json["accountStatus"] == "loading":
print(parsed_json["accountStatus"])
print(req.status_code)
return render_template("loading.html")
if parsed_json["accountStatus"] == "got qr code":
print(parsed_json["accountStatus"])
str_parsed_json = yaml.safe_load(parsed_json["qrCode"])
print(req.status_code)
return render_template("qrcodePage.html", str_parsed_json=str_parsed_json)
if parsed_json["accountStatus"] == "authenticated":
print(parsed_json["accountStatus"])
print(req.status_code)
return render_template("index.html")
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000, debug=True)
The response I am getting is a 200
I have searched all over the internet to see if someone else has the same issue as me, but I haven't found one person with this problem.
I have tried restarting the following
Restart my local server
Making True the debug thing in the app.run()
Check in PostMan the server response but it always return me the expected result, but changes are not seen in the page.
The only way it seems to work is when I make some changes to my code, and restart the server, that is when I can refresh the page and redirect me to the expected template file.
Thanks in advance.
Move your requests.get and all subsequent object based on that inside your index():
#app.route("/")
def index():
req = requests.get('this is the link with my API token')
json_content = req.content
# parsed JSON content, ready to use
parsed_json = json.loads(json_content)
if parsed_json["accountStatus"] == "loading":
print(parsed_json["accountStatus"])
return render_template("loading.html")
... rest of your code
Currently your requests is not being refreshed past the point of your server starting. But if you move it inside your #app.route("/") each time you visit the site's root page, it will do a new requests.get() to refresh your data.

Query parameters in Flask route [duplicate]

How do you access query parameters or the query string in Flask routes? It's not obvious from the Flask documentation.
The example route /data below illustrates the context that I would like to access that data. If someone requests something like example.com/data?abc=123, I would like access to the string ?abc=123 or to be able to retrieve the value of parameters like abc.
#app.route("/data")
def data():
# query_string = ???
return render_template("data.html")
from flask import request
#app.route('/data')
def data():
# here we want to get the value of user (i.e. ?user=some-value)
user = request.args.get('user')
The full URL is available as request.url, and the query string is available as request.query_string.decode().
Here's an example:
from flask import request
#app.route('/adhoc_test/')
def adhoc_test():
return request.query_string
To access an individual known param passed in the query string, you can use request.args.get('param'). This is the "right" way to do it, as far as I know.
ETA: Before you go further, you should ask yourself why you want the query string. I've never had to pull in the raw string - Flask has mechanisms for accessing it in an abstracted way. You should use those unless you have a compelling reason not to.
I came here looking for the query string, not how to get values from the query string.
request.query_string returns the URL parameters as raw byte string (Ref 1).
Example of using request.query_string:
from flask import Flask, request
app = Flask(__name__)
#app.route('/data', methods=['GET'])
def get_query_string():
return request.query_string
if __name__ == '__main__':
app.run(debug=True)
Output:
References:
Official API documentation on query_string
We can do this by using request.query_string.
Example:
Lets consider view.py
from my_script import get_url_params
#app.route('/web_url/', methods=('get', 'post'))
def get_url_params_index():
return Response(get_url_params())
You also make it more modular by using Flask Blueprints - https://flask.palletsprojects.com/en/1.1.x/blueprints/
Lets consider first name is being passed as a part of query string
/web_url/?first_name=john
## here is my_script.py
## import required flask packages
from flask import request
def get_url_params():
## you might further need to format the URL params through escape.
firstName = request.args.get('first_name')
return firstName
As you see this is just a small example - you can fetch multiple values + formate those and use it or pass it onto the template file.
Werkzeug/Flask as already parsed everything for you. No need to do the same work again with urlparse:
from flask import request
#app.route('/')
#app.route('/data')
def data():
query_string = request.query_string ## There is it
return render_template("data.html")
The full documentation for the request and response objects is in Werkzeug: http://werkzeug.pocoo.org/docs/wrappers/
Try like this for query string:
from flask import Flask, request
app = Flask(__name__)
#app.route('/parameters', methods=['GET'])
def query_strings():
args1 = request.args['args1']
args2 = request.args['args2']
args3 = request.args['args3']
return '''<h1>The Query String are...{}:{}:{}</h1>''' .format(args1,args2,args3)
if __name__ == '__main__':
app.run(debug=True)
Output:
Every form of the query string retrievable from flask request object as described in O'Reilly Flask Web Devleopment:
From O'Reilly Flask Web Development, and as stated by Manan Gouhari earlier, first you need to import request:
from flask import request
request is an object exposed by Flask as a context variable named (you guessed it) request. As its name suggests, it contains all the information that the client included in the HTTP request. This object has many attributes and methods that you can retrieve and call, respectively.
You have quite a few request attributes which contain the query string from which to choose. Here I will list every attribute that contains in any way the query string, as well as a description from the O'Reilly book of that attribute.
First there is args which is "a dictionary with all the arguments passed in the query string of the URL." So if you want the query string parsed into a dictionary, you'd do something like this:
from flask import request
#app.route('/'):
queryStringDict = request.args
(As others have pointed out, you can also use .get('<arg_name>') to get a specific value from the dictionary)
Then, there is the form attribute, which does not contain the query string, but which is included in part of another attribute that does include the query string which I will list momentarily. First, though, form is "A dictionary with all the form fields submitted with the request." I say that to say this: there is another dictionary attribute available in the flask request object called values. values is "A dictionary that combines the values in form and args." Retrieving that would look something like this:
from flask import request
#app.route('/'):
formFieldsAndQueryStringDict = request.values
(Again, use .get('<arg_name>') to get a specific item out of the dictionary)
Another option is query_string which is "The query string portion of the URL, as a raw binary value." Example of that:
from flask import request
#app.route('/'):
queryStringRaw = request.query_string
Then as an added bonus there is full_path which is "The path and query string portions of the URL." Por ejemplo:
from flask import request
#app.route('/'):
pathWithQueryString = request.full_path
And finally, url, "The complete URL requested by the client" (which includes the query string):
from flask import request
#app.route('/'):
pathWithQueryString = request.url
Happy hacking :)
I prefer
user = request.args['user'] if 'user' in request.args else 'guest'
over
user = request.args.get('user')
this way, you can check the url actually contains the query string first
The implementation below worked for me.
from flask import request
def getVerificationStatus():
try:
requestId=int(request.args.get('requestId'))
print(requestId)
status= verificationStepRepository.getVerificationStatus(requestId)
return tb.responsify(200, "success", status)
except Exception as e:
return errorHandler.dispatchInternalServerError(str(e))
Often we just want to map the whole query string into an appropriate python data structure and take it from there. The appropriate structure is a multi-dictionary because keywords can repeat, for example we need to handle A=123&A=456&B=789. A multi-dictionary is a list of 2-tuples where each 2-tuple contains the key as its first item and the list of values as its second, so the above goes to [('A',['123','456']),('B',['789'])]. All of this is achieved by
qstr = request.args.lists() # A generator for the multi-dict
qstr = list(qstr) # To get the actual multi-dict
If all you want is a dictionary where the first occurrence of a duplicate keyword is used you can just go
qstr = request.args.to_dict()
This can be done using request.args.get().
For example if your query string has a field date, it can be accessed using
date = request.args.get('date')
Don't forget to add "request" to list of imports from flask,
i.e.
from flask import request
If the request if GET and we passed some query parameters then,
fro`enter code here`m flask import request
#app.route('/')
#app.route('/data')
def data():
if request.method == 'GET':
# Get the parameters by key
arg1 = request.args.get('arg1')
arg2 = request.args.get('arg2')
# Generate the query string
query_string="?arg1={0}&arg2={1}".format(arg1, arg2)
return render_template("data.html", query_string=query_string)
This Code worked for me:
from flask import Flask, request
app = Flask(__name__)
#app.route('/')
def search():
query = request.args
for key,value in query.items():
print(key,value)
return "Hello World"
if __name__ == '__main__':
app.run(debug=True)

Categories

Resources