How to validate URL parameters in Flask app? - python

I'm writing a RESTful API in Flask. I can access URL parameters via the Request Object. What is the best way to validate the given URL parameters?
For example:
/places?zip=97239 # This is a valid filter
/places?foo=bar # This is not a valid filter, 404 response?
One solution is to search through request.args and compare each entry against a set of valid URL parameters. Is there a better way?
Thanks!

Put the GET parameters in a dictionary and validate it using voluptuous.
For example:
parameters = Schema({
Required('zip'): Coerce(int),
})
will accept any dictionary with a "zip" key that has a value that can be coerced to an integer (so either 1 or "1" depending on how you get the values). You can then validate it using:
parameters(my_get_params) # should not raise an exception

Instead of doing validation by hand, you can use WTForms, which, besides helping you create actual forms, validates URL / POST parameters automatically according to specified models.
Whether this is better will depend on your specific situation.

You can use the flask-parameter-validation library in order to validate within Flask. This is useful as it uses Flask features under-the-hood, handles files/forms, and implicitly converts Query parameters.
For your example, you would do the following:
from flask import Flask
from typing import Optional
from flask_parameter_validation import ValidateParameters, Query
app = Flask(__name__)
#app.route("/places", methods=["GET"])
#ValidateParameters()
def check_places(
zip: Optional[int] = Query()
):
return "Hello World!"
if __name__ == "__main__":
app.run()

Related

how to pass GET parameters with Flask using add_url_rule

beginner's question:
is it possible to pass GET request parameters to a route function in Flask using add_url_rule?
I am getting the error message that the verify_username_route function I declare later (that takes 1 parameter) is called without any parameters passed.
self.application_.add_url_rule(self.path_ + '/verify', 'verify', self.verify_username_route, methods=['GET'])
To fetch query string parameters, you use request.args.get('argname') in your function. Nothing is passed in -- it's all done through the globals.
To pass any parameters in your URLs, you can use Flask's built-in patterns. These work for both #app.route decorators and add_url_route methods. Here is your code, with a parameter:
self.application_.add_url_rule(self.path_ + '/verify/<int:val>', 'verify', self.verify_username_route, methods=['GET'])
The important part from this is the exact route: /verify/<int:parameter>. This tells Flask that you want the route to be in the format of /verify/something, where something is any integer. Whatever integer is entered here when the request is made gets passed to your self.verify_username_route as a parameter called val.
Read more about this here.

Django reverse routes - two optional parameters

I have a question about Django and it's routing system. I believe that it can be powerfull, but right now I am struggling with one issue I don't experience when working in other frameworks and I can't seem to get a grip on it. Worth to mention that I don't have much experience with Django at this point.
The issue is simple - I have a view which takes two optional parameters, defined like this
def test_view(id=None, grid=None):
Both parameters are optional and frequently are not passed. Id can only be an integer and grid will never be an integer (it is a special string to control datagrid when I don't want to use sessions). I have a route defined like this:
url(a(r'^test_view (\/(?P<id>\d+))? (\/(?P<grid>[^\/]+))? \/?$'), views.test_view, name='test_view'),
This works great and I am not having trouble with using one-way routes. But when I try to use the reverse function or url template tag, following error occurs:
Reverse for 'test_view' with arguments '('20~id~desc~1',)' and keyword arguments '{}' not found.
In this example I tried to find reverse without the id, just with the grid parameter. I have tried various methods of passing parameters to the reverse function:
(grid, )
(None, grid)
('', grid)
{id=None, grid=grid}
All of them result in same error or similliar one.
Is there a way to implement this in django? Maybe just disable the cool URL for the grid parameter. That is how I do it in for example Nette framework for PHP, isntead of having an url like this: 'localhost/test_view/1/20~id~desc~1' I have url like this: 'localhost/test_view/1?grid=20~id~desc~1'. This would be completely sufficient, but I have no idea how to achive this in Django.
As you note in your question, the best way to achieve this is to use standard GET query parameters, rather than doing it in the path itself. In Django you do that exclusively in the view; the URL itself is then just
url(r'^test_view$', views.test_view, name='test_view'),
and you request it via localhost/test_view?id=1&grid=20~id~desc~1. You get the params from request.GET, which is a dictionary-like object; you can use .get so that it does not raise a KeyError when the key is not provided.
def test_view(request):
id = request.GET.get('id')
grid = request.GET.get('grid')

How to unit test view_func in url rule?

I have the following routing url rule defined and would like to test it.
app.add_url_rule('/api/v1.0/worker/bbc-stage-0', 'stage0', view_func=BBCStage0TaskView.as_view('bbc_stage0_taskview'))
The following tests if the path is correct:
def test_url_to_view_stage0_exists(self):
self.assertEqual(api.app.url_map._rules_by_endpoint['stage0'][0].rule, '/api/v1.0/worker/bbc-stage-0')
I haven't found a way to test if view_func is pointing to the right class. Is there a way to test that?
Werkzeug's Map maps paths to endpoints. The Flask app maps these endpoints to view functions in app.view_functions, which is used during app.dispatch_request. So to check what view has been connected to an endpoint, simply get it from that map. Since you're using a class based View, the real view function will be different every instantiation, so you instead test that the view_class is the same.
self.assertEqual(api.app.view_functions['stage0'].view_class, BBCStage0Task)
This is sort of a meaningless test, as you're basically testing Flask internals, which are already tested by Flask. Your own tests would be much more useful by simply using the test client to see if a request to a url returns what you expect.
with api.app.test_client() as client:
rv = client.get('/api/v1.0/worker/bbc-stage-0')
# assert something about the response, such as 'expected string' in rv.data

Passing variables through URL to a flask app

Well i've this in my flask app :
#app.route("/changeip/<ip>")
def change_ip(ip) :
return ip
Now if i invoke it like :
http://127.0.0.1:5000/changeip?ip=1.2.2.2
It spits out "URL not found"...what is that i'm doing wrong here?
The first route describes a url with a value as part of the url. The second url describes a route with no variables, but with a query parameter in the url.
If you are using the first route, the url should look like http://127.0.0.1/changeip/1.2.2.2.
If you are using the second url, the route should look like /changeip, the function should be def change_ip():, and the value should be read from request.args['ip'].
Usually the route should describe any arguments that should always be present, and form or query params should be used for user-submitted data.
You should use:
app.route('/something/<ip>')
def function(ip):
And when you are using url_for, you should pass value of ip aswell:
url_for('function', ip='your_ip_address')
The accepted answer is correct, but I wanted to add the method that it appears the OP was originally trying in his http request.
Another way to pass in variables is through the question mark that separates variables in the url, and using requests.
import requests
Then in the method,
#app.route("/changeip")
def change_ip():
return requests.args.get('ip', '')
For the url, you pass the variable in using the question mark delimiter, the way you were originally trying.
http://127.0.0.1:5000/changeip?ip=1.2.2.2

bottle.py URL routing & reverse howto?

Sample Bottle.py code:
#route('/show_<name>')
def show(name):
return ''
My question is:
Given a URL, how do we get the view function? E.g. the URL is /show_magic, I need to know the show() function is responsible for this request URL
Given a route (not Router!!) and parameters, how to get the URL? e.g. I need a function called reverse which reverse(default_app().routes[0], name='me') == '/show_me'
you might want to consider named routes
#route('/show_<item_name>', name='item_show')
def show(item_name):
return ''
now given the route name and params how to get the URL? we use get_url
get_url('item_show', item_name='my_item')
http://nongraphical.com/2012/08/using-bottle-py-in-production/
For your first question, use Bottle.match. Given a path (i.e. '/show_magic') and the method (GET or POST or whatever), the following will return a tuple containing a Route object and its parameters:
default_app().match({'PATH_INFO': path, 'REQUEST_METHOD': method})
The function called is the Route object's callback or call attribute.
For your second question, use the router's build method with the route's rule and kwargs:
default_app().router.build(route.rule, name='me')
That doesn't seem to be documented, but it works.

Categories

Resources