21

I am using Flask to create a couple of very simple services. From outside testing (using HTTPie) parameters through querystring are getting to the service.

But if I am using something like.

    data = {
        'param1': 'somevalue1',
        'param2': 'somevalue2'}

    response = self.client.get(url_for("api.my-service", **data))

I can see the correct URI being created:

http://localhost:5000/api1.0/my-service?param1=somevalue1&param2=somevalue2

when I breakpoint into the service:

request.args

is actually empty.

self.client is created by calling app.test_client() on my configured Flask application.

Anyone has any idea why anything after ? is being thrown away or how to work around it while still using test_client?

4 Answers 4

39

I've just found out a workaround.

Make

data = {
    'param1': 'somevalue1',
    'param2': 'somevalue2'}

response = self.client.get(url_for("api.my-service", **data))

into this:

data = {
    'param1': 'somevalue1',
    'param2': 'somevalue2'}

response = self.client.get(url_for("api.my-service"), query_string = data)

This works but seems a bit unintuitive, and debugging there is a place where the provided query string in the URI is thrown away ....

But anyway this works for the moment.

Sign up to request clarification or add additional context in comments.

Comments

2

I know this is an old post, but I ran into this too. There's an open issue about this in the flask github repository. It appears this is intended behavior. From a response in the issue thread:

mitsuhiko commented on Jul 24, 2013
That's currently intended behavior. The first parameter to the test client should be a relative url. If it's not, then the parameters are removed as it's treated as if it was url joined with the second. This works:

>>> from flask import Flask, request
>>> app = Flask(__name__)
>>> app.testing = True
>>> @app.route('/')
... def index():
...  return request.url
... 
>>> c = app.test_client()
>>> c.get('/?foo=bar').data
'http://localhost/?foo=bar'

One way to convert your absolute url into a relative url and keep the query string is to use urlparse:

from urlparse import urlparse

absolute_url = "http://someurl.com/path/to/endpoint?q=test"
parsed = urlparse(absolute_url)
path = parsed[2] or "/"
query = parsed[4]
relative_url = "{}?{}".format(path, query)

print relative_url

Comments

1

If you are trying any other HTTP Method other than GET

response = self.client.patch(url_for("api.my-service"), query_string=data,
                             data="{}")

data="{}" or data=json.dumps({}) should be there, even if there is no content in the body. Otherwise, it results in BAD Request.

Comments

0

For me the solution was to use the client within with statements:

with app.app_context():
    with app.test_request_context():
        with app.test_client() as client:
            client.get(...)

instead of

client = app.test_client()
client.get(...)

I put the creation of the test client in a fixture, so that it is "automatically" created for each test method:

from my_back_end import MyBackEnd

sut = None
app = None
client = None

@pytest.fixture(autouse=True)
def before_each():
    global sut, app, client
    sut = MyBackEnd()
    app = sut.create_application('frontEndPathMock')
    with app.app_context():
        with app.test_request_context():                
            with app.test_client() as client:
                yield

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.