Fred Zimmerman
Fred Zimmerman

Reputation: 1238

how to parse key value pair request from url using python requests in flask

I have spent about a week on this issue and although I have made considerable progress I am stuck at a key point.

I am writing a simple client-server program in Python that is supposed to accept key/value pairs from the command line, formulate them into an url, and request the url from the server. The problem appears to be either that the url is not properly formatted or that the server is not parsing it correctly. (That is, the key-value pairs appear to be properly making it from the command line to the function that contains the request.)

import sys
import requests

server_url = "http://0.0.0.0:5006"

def test(payload):

   print('payload in function is ' + payload)
   r = requests.get('http://0.0.0.0:5006/buy', params=payload)
   print(r.url) #debug
   print(r.encoding)
   print(r.text)
   print(r.headers)

if __name__ == '__main__':

    payload = sys.argv[2]
    print('payload from cli is ' + payload)
    test(payload)

Server:

import subprocess
from flask import Flask
from flask import request
import request

# Configure the app and wallet
app = Flask(__name__)
@app.route('/buy', methods=['GET', 'POST'])

def test(key1, key2):

    key1 = str(request.args.get('key1'))
    key2 = str(request.args.get('key2'))
    print('keys are' + key1 + key2)
    fortune = subprocess.check_output(['echo', 'key1'])
    return fortune

# Initialize and run the server
if __name__ == '__main__':

    app.run(host='0.0.0.0', port=5006)

Client console output:

payload from cli is {"key1": "foo", "key2": "bar"}
payload in function is {"key1": "foo", "key2": "bar"}
http://0.0.0.0:5006/buy?%7B%22key1%22:%20%22foo%22,%20%22key2%22:%20%22bar%22%7D
ISO-8859-1
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>500 Internal Server Error</title>
<h1>Internal Server Error</h1>
<p>The server encountered an internal error and was unable to complete your request.  Either the server is overloaded or there is an error in the application.</p>

{'Content-Type': 'text/html', 'Content-Length': '291', 'Date': 'Fri, 09 Sep 2016 22:16:44 GMT', 'Server': 'Werkzeug/0.11.10 Python/3.5.2'}

Server console output:

* Running on http://0.0.0.0:5006/ (Press CTRL+C to quit)
[2016-09-09 18:30:33,445] ERROR in app: Exception on /buy [GET]
Traceback (most recent call last):
  File "/usr/local/lib/python3.5/dist-packages/flask/app.py", line 1988, in wsgi_app
    response = self.full_dispatch_request()
  File "/usr/local/lib/python3.5/dist-packages/flask/app.py", line 1641, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/usr/local/lib/python3.5/dist-packages/flask/app.py", line 1544, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/usr/local/lib/python3.5/dist-packages/flask/_compat.py", line 33, in reraise
    raise value
  File "/usr/local/lib/python3.5/dist-packages/flask/app.py", line 1639, in full_dispatch_request
    rv = self.dispatch_request()
  File "/usr/local/lib/python3.5/dist-packages/flask/app.py", line 1625, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
TypeError: test() missing 2 required positional arguments: 'key1' and 'key2'
127.0.0.1 - - [09/Sep/2016 18:30:33] "GET /buy?%7B%22key1%22:%20%22foo%22,%20%22key2%22:%20%22bar%22%7D HTTP/1.1" 500 -

I take this as showing that the subprocess call is for some reason not able to decipher key1 and key2 from the URL so is failing when it runs "fortune None None".

Upvotes: 0

Views: 2134

Answers (2)

dirn
dirn

Reputation: 20729

test is expecting values for key1 and key2. Flask would provide those through your route.

@app.route('/buy/<key1>/<key2>')
def test(key1, key2):

Visiting /buy/value1/value2 would give values to the arguments. You want to pass values through the query string though.

You just need to remove them from the function's signature.

@app.route('/buy', methods=['GET', 'POST'])
def test():

Upvotes: 1

ffledgling
ffledgling

Reputation: 12140

The problem seems to be in your payload.

The payload needs to be a dictionary. You're giving it a string.

sys.argv[2] will be a string, even if you format the text to look like a dictionary. So unless there's something missing from your client code snippet, payload isn't actually a dictionary like requests would expect.

I can infact confirm this by looking at the URL being generated, which is:

http://0.0.0.0:5006/buy?%7B%22key1%22:%20%22foo%22,%20%22key2%22:%20%22bar%22%7D

Had the payload been a dictionary and correctly encoded, it would've looked something like this:

http://0.0.0.0:5006/buy?key1=foo&key2=bar

To see what type payload your really is, do print(type(payload)) somewhere inside the test function.

Once you've converted your payload into a proper python dictionary (you'll have to parse your sys.argv[2]), then requests should work as expected.

Upvotes: 2

Related Questions