I am trying to parse "#" symbol as a direct url in Flask project. The issue is everytime the url is requested, it breaks any value that has # init as it's a special character in url encoding.
localhost:9999/match/keys?source=#123&destination=#123
In flask, I am trying to get these arguments like this
app.route(f'/match/keys/source=<string:start>/destination=<string:end>', methods=['GET'])
The url response that i see on console is this:
"GET /match/keys/source=' HTTP/1.0" 404 -] happens
I believe you might not fully understand how 'query strings' work in flask. This url:
app.route(f'/match/keys/source=<string:start>/destination=<string:end>', methods=['GET'])
won't work as you expect as it won't match the request:
localhost:9999/match/keys?source=#123&destination=#123
rather it aught to be:
#app.route('/match/keys', methods=['GET'])
and this would match:
localhost:9999/match/keys?source=%23123&destination=%23123
Then to catch those 'query strings' you do:
source = request.args.get('source') # <- name the variable what you may
destination = request.args.get('destination') # <- same as the naming format above
So when you call localhost:9999/match/keys?source=%23123&destination=%23123 you test for those 'query strings' in the request url and if they are they that route function would execute.
I wrote this test:
def test_query_string(self):
with app.test_client() as c:
rc = c.get('/match/keys?source=%23123') # <- Note use of the '%23' to represent '#'
print('Status code: {}'.format(rc.status_code))
print(rc.data)
assert rc.status_code == 200
assert 'source' in request.args
assert rc.data.decode('utf-8') == "#123"
and it passes using this route function:
#app.route('/match/keys', methods=['GET'])
def some_route():
s = request.args.get('source')
return s
So you see I was able to catch the query string source value in my unit test.
I found another trick to work around with it. Instead of using GET method, I switched to POST
localhost:9999/match/keys
and in the app.routes, i sent the argument to get_json.
app.route('/match/keys/',method=['POST'])
def my_func():
arg = request.get_json
In postman, I send the POST request and send the body to be like this:
Postman Post request
Related
I want to pass a variable called manual to Flask a route, which will then do something based on the value in the POST form data. But the forms data is interpreted as string in flask even though I send it in a form as a dictionary.
here's the code
#app.route("/result", methods= [ 'POST', 'GET'])
def result():
manual = request.form.get("manual")
if manual is None:
return "manual is required"
here's how I am sending the data
r = requests.get('http://127.0.0.1:5000/result'
,data={manual':False})
I understand that I can do something like;
if manual == 'True'
but I don't want to be comparing strings, I want to do it in the standard way whichever it is.
Thanks
First of all, do a POST request, not a GET:
r = requests.post('http://127.0.0.1:5000/result', json={'manual': False})
Then (untested):
#app.route("/result", methods=['POST'])
def result():
json_data = flask.request.json
manual = json_data.get("manual")
if manual is None:
return "manual is required"
Have a look at the doc for details: More complicated POST requests.
Note that there are differences between using the data parameter and the json parameter. An important thing to note is the presence of the Content-Type header:
Using the json parameter in the request will change the Content-Type
in the header to application/json.
I'm try to test the api I wrote with Fastapi. I have the following method in my router :
#app.get('/webrecord/check_if_object_exist')
async def check_if_object_exist(payload: WebRecord) -> bool:
key = get_key_of_obj(payload.data) if payload.key is None else payload.key
return await check_if_key_exist(key)
and the following test in my test file :
client = TestClient(app)
class ServiceTest(unittest.TestCase):
.....
def test_check_if_object_is_exist(self):
webrecord_json = {'a':1}
response = client.get("/webrecord/check_if_object_exist", json=webrecord_json)
assert response.status_code == 200
assert response.json(), "webrecord should already be in db, expected : True, got : {}".format(response.json())
When I run the code in debug I realized that the break points inside the get method aren't reached. When I changed the type of the request to post everything worked fine.
What am I doing wrong?
In order to send data to the server via a GET request, you'll have to encode it in the url, as GET does not have any body. This is not advisable if you need a particular format (e.g. JSON), since you'll have to parse the url, decode the parameters and convert them into JSON.
Alternatively, you may POST a search request to your server. A POST request allows a body which may be of different formats (including JSON).
If you still want GET request
#app.get('/webrecord/check_if_object_exist/{key}')
async def check_if_object_exist(key: str, data: str) -> bool:
key = get_key_of_obj(payload.data) if payload.key is None else payload.key
return await check_if_key_exist(key)
client = TestClient(app)
class ServiceTest(unittest.TestCase):
.....
def test_check_if_object_is_exist(self):
response = client.get("/webrecord/check_if_object_exist/key", params={"data": "my_data")
assert response.status_code == 200
assert response.json(), "webrecord should already be in db, expected : True, got : {}".format(response.json())
This will allow to GET requests from url mydomain.com/webrecord/check_if_object_exist/{the key of the object}.
One final note: I made all the parameters mandatory. You may change them by declaring to be None by default. See fastapi Docs
I need to setup a /metrics endpoint so that Prometheus can consume statistics about an endpoint. How do I go about doing this?
I have this in my Flask app:
#app.route('/metrics')
def metrics():
def generateMetrics():
metrics = ""
... some string builder logic
return metrics
response = make_response(generateMetrics(), 200)
response.mimetype = "text/plain"
return response
Is this the best way? What is the difference between returning a String (just returning metrics here) and returning plain text? Why do I need the mimetype?
Is this the best way?
There are several ways to set the MIME type, better explained and discussed in this StackOverflow question. Your way works fine and gets the job done.
What is the difference between returning a String and returning plain text?
If you return a string Flask will automatically handle some of the Response logic for you. This means using some default values. If you set up two different endpoints you'll see that the difference turns out to be that your code returns the following header:
Content-Type:"text/plain; charset=utf-8"
While just returning a string (and default MIME type) would return the following header:
Content-Type:"text/html; charset=utf-8"
Why do I need the mimetype?
You might say that it is technically more correct, given that your response is simply plain text, and not HTML. However, a more forcing reason for needing it would be that a third party system you are using (Prometheus) relies on or cares about the contents of the "Content-Type" header. If they do, then you must set it for them to accept it.
Example code
For the Content-Type header demonstration I used the following example Python code:
from flask import Flask, make_response
app = Flask(__name__)
def generateMetrics():
return "hello world"
#app.route('/metrics')
def metrics():
response = make_response(generateMetrics(), 200)
response.mimetype = "text/plain"
return response
#app.route('/metrics2')
def metrics2():
return generateMetrics()
I then viewed the returned body and headers using Postman.
How to write the flask app.route if I have multiple parameters in the URL call?
Here is my URL I am calling from AJax:
http://0.0.0.0:8888/createcm?summary=VVV&change=Feauure
I was trying to write my flask app.route like this:
#app.route('/test/<summary,change>', methods=['GET']
But this is not working. Can anyone suggest me how to mention the app.route?
The other answers have the correct solution if you indeed want to use query params. Something like:
#app.route('/createcm')
def createcm():
summary = request.args.get('summary', None)
change = request.args.get('change', None)
A few notes. If you only need to support GET requests, no need to include the methods in your route decorator.
To explain the query params. Everything beyond the "?" in your example is called a query param. Flask will take those query params out of the URL and place them into an ImmutableDict. You can access it by request.args, either with the key, ie request.args['summary'] or with the get method I and some other commenters have mentioned. This gives you the added ability to give it a default value (such as None), in the event it is not present. This is common for query params since they are often optional.
Now there is another option which you seemingly were attempting to do in your example and that is to use a Path Param. This would look like:
#app.route('/createcm/<summary>/<change>')
def createcm(summary=None, change=None):
...
The url here would be:
http://0.0.0.0:8888/createcm/VVV/Feauure
With VVV and Feauure being passed into your function as variables.
You can try this:
Curl request
curl -i "localhost:5000/api/foo?a=hello&b=world"
flask server
from flask import Flask, request
app = Flask(__name__)
#app.route('/api/foo/', methods=['GET'])
def foo():
bar = request.args.to_dict()
print bar
return 'success', 200
if __name__ == '__main__':
app.run(debug=True)
console output
{'a': u'hello', 'b': u'world'}
P.S. Don't omit double quotation(" ") with curl option, or it not work in Linux cuz "&"
Routes do not match a query string, which is passed to your method directly.
from flask import request
#app.route('/createcm', methods=['GET'])
def foo():
print request.args.get('summary')
print request.args.get('change')
#app.route('/createcm', methods=['GET'])
def foo():
print request.args.get('summary')
print request.args.get('change')
In your requesting url: http://0.0.0.0:8888/createcm?summary=VVV&change=Feauure, the endpoint is /createcm and ?summary=VVV&change=Feauure is args part of request. so you can try this:
from flask import Flask, request, jsonify
app = Flask(__name__)
#app.route('/createcm', methods=['get'])
def create_cm():
summary = request.args.get('summary', None) # use default value repalce 'None'
change = request.args.get('change', None)
# do something, eg. return json response
return jsonify({'summary': summary, 'change': change})
if __name__ == '__main__':
app.run(debug=True)
httpie examples:
http get :5000/createcm summary==vvv change==bbb -v
GET /createcm?summary=vvv&change=bbb HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate
Connection: keep-alive
Host: localhost:5000
User-Agent: HTTPie/0.9.8
HTTP/1.0 200 OK
Content-Length: 43
Content-Type: application/json
Date: Wed, 28 Dec 2016 01:11:23 GMT
Server: Werkzeug/0.11.13 Python/3.6.0
{
"change": "bbb",
"summary": "vvv"
}
You're mixing up URL parameters and the URL itself.
You can get access to the URL parameters with request.args.get("summary") and request.args.get("change").
Simply we can do this in two stpes:
1] Code in flask [app.py]
from flask import Flask,request
app = Flask(__name__)
#app.route('/')
def index():
return "hello"
#app.route('/admin',methods=['POST','GET'])
def checkDate():
return 'From Date is'+request.args.get('from_date')+ ' To Date is '+ request.args.get('to_date')
if __name__=="__main__":
app.run(port=5000,debug=True)
2] Hit url in browser:
http://127.0.0.1:5000/admin?from_date=%222018-01-01%22&to_date=%222018-12-01%22
in flak we do in this way
#app.route('/createcm')
def createcm():
summary = request.args.get('summary', type=str ,default='')
change = request.args.get('change',type=str , default='')
now you can run your end-point with different optional paramters like below
http://0.0.0.0:8888/createcm?summary=VVV
or
http://0.0.0.0:8888/createcm?change=Feauure
or
http://0.0.0.0:8888/createcm?summary=VVV&change=Feauure
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)