I'm having an issue trying to decode a python dictionary sent to my server as json.
This is what I have in my application:
payload = {'status':[bathroomId,item,percentage,timestamp]}
r=requests.post(url,None,json.dumps(payload))
Here is what I do in my Flask server:
req = request.get_json()
print req['status']
When I try to print the content of req['status'], it seems like python won't recognize it as a dictionary and I get an internal server error.
I tried printing req, and I get None
What am I missing?
Unless you set the Content-Type header to application/json in your request, Flask will not attempt to decode any JSON found in your request body.
Instead, get_json will return None (which is what you're seeing right now).
So, you need to set the Content-Type header in your request.
Fortunately since version 2.4.2 (released a year ago), requests has a helper argument to post JSON; this will set the proper headers for you. Use:
requests.post(url, json=payload)
Alternatively (e.g. using requests < 2.4.2), you can set the header yourself:
requests.post(url, data=json.dumps(payload), headers={"Content-Type": "application/json"})
Here is the relevant code from Flask:
Flask only loads JSON if is_json is True (or if you pass force=True to get_json). Otherwise, it returns None.
is_json looks at the Content-Type header, and looks for application/json there.
Related
I have a request in python that calls a get endpoint and in the responses headers a Etag is returned. I am extracting this etag to use in a later json request. The etag when printed is in the following format W/"5w+V3HeRYGpkXyvO5oLhMA==". When i try post this request in the json i get a bad data request as characthers in the etag are not escaped. I have tried using re.escape() but this does not seem to be changing the format for me. If anyone can help.
response = self.client.get("https://URL", headers={'Authorization':'Token'}){'Authorization':'Token'})
Etag = response.headers["etag"]
self.client.post("https://URL", headers={'Authorization': 'Token','Content-Type': 'application/json'}, json={"etag": Etag})
I am just trying to access an API through Postman and its wokring fine.The Postman header response is returning some details like below
Authentication-Token →/DwG7gAxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Connection →keep-alive
Content-Length →16
Content-Type →application/json;charset=UTF-8
Date →Tue, 25 Sep 2018 17:44:01 GMT
Server →Apache-Coyote/1.1
But when I am trying to do same in Python I am just receivig the response status.(200)
How can I get the above Authentication-Token etc details like Postman in python code.
import requests
import json
url = 'https://test-orchestrator.lmig.com/baocdp/rest/login/'
headers = {"Content-Type": "application/json"}
data1 = {"username":"abc", "password":"abc"}
print("Testing authentication for Remedy test environment...")
change_response=requests.post(url,data=json.dumps(data1),headers=headers)
print(change_response)
If you print change_response, it will most likely look like this <status [200]> or something to that effect. If you want to see the contents of the response, you can use the vars response.text, response.content, or response.headers (among others) or since this is a json response, you can use the method response.json() to convert the contents of the response into a dictionary full of native Python data types.
I would reccommend x = response.json(), as the contents of your response seem to contain an auth token that you will most likely need to communicate with this device further. You can then use auth+token = x[token_key] to isolate that token.
Im trying to test a PUT request in my Flask app, using flasks test client.
Everything looks good to me but i keep getting 400 BAD request.
I tried the same request using POSTMAN and I get the response back.
Here is the code
from flask import Flask
app = Flask(__name__)
data = {"filename": "/Users/resources/rovi_source_mock.csv"}
headers = {'content-type': 'application/json'}
api = "http://localhost:5000/ingest"
with app.test_client() as client:
api_response = client.put(api, data=data, headers=headers)
print(api_response)
Output
Response streamed [400 BAD REQUEST]
You do need to actually encode the data to JSON:
import json
with app.test_client() as client:
api_response = client.put(api, data=json.dumps(data), headers=headers)
Setting data to a dictionary treats that as a regular form request, so each key-value pair would be encoded into application/x-www-form-urlencoded or multipart/form-data content, if you had used either content type. As it is, your data is entirely ignored instead.
I think it is simpler to just pass the data using the json parameter instead of the data parameter:
reponse = test_client.put(
api,
json=data,
)
Quoting from here:
Passing the json argument in the test client methods sets the request
data to the JSON-serialized object and sets the content type to
application/json.
I'm working on an API wrapper. The spec I'm trying to build to has the following request in it:
curl -H "Content-type:application/json" -X POST -d data='{"name":"Partner13", "email":"example#example.com"}' http://localhost:5000/
This request produces the following response from a little test server I setup to see exatly what headers/params etc are sent as. This little script produces:
uri: http://localhost:5000/,
method: POST,
api_key: None,
content_type: application/json,
params: None,
data: data={"name":"Partner13", "email":"example#example.com"}
So that above is the result I want my python script to create when it hits the little test script.
I'm using the python requests module, which is the most beautiful HTTP lib I have ever used. So here is my python code:
uri = "http://localhost:5000/"
headers = {'content-type': 'application/json' }
params = {}
data = {"name":"Partner13", "email":"example#exmaple.com"}
params["data"] = json.dumps(data)
r = requests.post(uri, data=params, headers=headers)
So simple enough stuff. Set the headers, and create a dictionary for the POST parameters. That dictionary has one entry called "data" which is the JSON string of the data I want to send to the server. Then I call the post. However, the result my little test script gives back is:
uri: http://localhost:5000/,
method: POST,
api_key: None,
content_type: application/json,
params: None,
data: data=%7B%22name%22%3A+%22Partner13%22%2C+%22email%22%3A+%22example%40example.com%22%7D
So essentially the json data I wanted to send under the data parameter has been urlendcoded.
Does anyone know how to fix this? I have looked through the requests documentation and cannot seem to find a way to not auto urlencode the send data.
Thanks very much,
Kevin
When creating the object for the data keyword, simply assign a variable the result of json.dumps(data).
Also, because HTTP POST can accept both url parameters as well as data in the body of the request, and because the requests.post function has a keyword argument named "params", it might be better to use a different variable name for readability. The requests docs use the variable name "payload", so thats what I use.
data = {"name":"Partner13", "email":"example#exmaple.com"}
payload = json.dumps(data)
r = requests.post(uri, data=payload, headers=headers)
Requests automatically URL encodes dictionaries passed as data here. John_GG's solution works because rather than posting a dictionary containing the JSON encoded string in the 'data' field it simply passes the JSON encoded string directly: strings are not automatically encoded. I can't say I understand the reason for this behaviour in Requests but regardless, it is what it is. There is no way to toggle this behaviour off that I can find.
Best of luck with it, Kevin.
I am using Flask (based on Werkzeug) which uses Python.
The user can download a file, I'm using the send_from_directory-function.
However when actually downloading the file, the HTTP header content-length is not set. So the user has no idea how big the file being downloaded is.
I can use os.path.getsize(FILE_LOCATION) in Python to get the file size (in bytes), but cannot find a way to set the content-length header in Flask.
Any ideas?
I needed this also, but for every requests, so here's what I did (based on the doc) :
#app.after_request
def after_request(response):
response.headers.add('Access-Control-Allow-Origin', '*')
return response
Since version 0.6 the canonical way to add headers to a response object is via the make_response method (see Flask docs).
def index():
response = make_response(render_template('index.html', foo=42))
response.headers['X-Parachutes'] = 'parachutes are cool'
return response
I believe you'd do something like this (untested):
from flask import Response
response = Response()
response.headers.add('content-length', str(os.path.getsize(FILE_LOCATION)))
See: Werkzug's Headers object and Flask's Response object.