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.
Related
I would like to pass a JSON object to a FastAPI backend. Here is what I am doing in the frontend app:
data = {'labels': labels, 'sequences': sequences}
response = requests.post(api_url, data = data)
Here is how the backend API looks like in FastAPI:
#app.post("/api/zero-shot/")
async def Zero_Shot_Classification(request: Request):
data = await request.json()
However, I am getting this error:
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
You should use the json parameter instead (which would change the Content-Type header to application/json):
payload = {'labels': labels, 'sequences': sequences}
r = requests.post(url, json=payload)
not data which is used for sending form data with the Content-Type being application/x-www-form-urlencoded by default, or multipart/form-data if files are also included in the request—unless you serialised your JSON first and manually set the Content-Type header to application/json, as described in this answer:
payload = {'labels': labels, 'sequences': sequences}
r = requests.post(url, data=json.dumps(payload), headers={'Content-Type': 'application/json'})
Also, please have a look at the documentation on how to benefit from using Pydantic models when sending JSON request bodies, as well as this answer and this answer for more options and examples on how to define an endpoint expecting JSON data.
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.
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.
I'm trying to build a simple proxy using Flask and requests. The code is as follows:
#app.route('/es/<string:index>/<string:type>/<string:id>',
methods=['GET', 'POST', 'PUT']):
def es(index, type, id):
elasticsearch = find_out_where_elasticsearch_lives()
# also handle some authentication
url = '%s%s%s%s' % (elasticsearch, index, type, id)
esreq = requests.Request(method=request.method, url=url,
headers=request.headers, data=request.data)
resp = requests.Session().send(esreq.prepare())
return resp.text
This works, except that it loses the status code from Elasticsearch. I tried returning resp (a requests.models.Response) directly, but this fails with
TypeError: 'Response' object is not callable
Is there another, simple, way to return a requests.models.Response from Flask?
Ok, found it:
If a tuple is returned the items in the tuple can provide extra information. Such tuples have to be in the form (response, status, headers). The status value will override the status code and headers can be a list or dictionary of additional header values.
(Flask docs.)
So
return (resp.text, resp.status_code, resp.headers.items())
seems to do the trick.
Using text or content property of the Response object will not work if the server returns encoded data (such as content-encoding: gzip) and you return the headers unchanged. This happens because text and content have been decoded, so there will be a mismatch between the header-reported encoding and the actual encoding.
According to the documentation:
In the rare case that you’d like to get the raw socket response from the server, you can access r.raw. If you want to do this, make sure you set stream=True in your initial request.
and
Response.raw is a raw stream of bytes – it does not transform the response content.
So, the following works for gzipped data too:
esreq = requests.Request(method=request.method, url=url,
headers=request.headers, data=request.data)
resp = requests.Session().send(esreq.prepare(), stream=True)
return resp.raw.read(), resp.status_code, resp.headers.items()
If you use a shortcut method such as get, it's just:
resp = requests.get(url, stream=True)
return resp.raw.read(), resp.status_code, resp.headers.items()
Flask can return an object of type flask.wrappers.Response.
You can create one of these from your requests.models.Response object r like this:
from flask import Response
return Response(
response=r.reason,
status=r.status_code,
headers=dict(r.headers)
)
I ran into the same scenario, except that in my case my requests.models.Response contained an attachment. This is how I got it to work:
return send_file(BytesIO(result.content), mimetype=result.headers['Content-Type'], as_attachment=True)
My use case is to call another API in my own Flask API. I'm just propagating unsuccessful requests.get calls through my Flask response. Here's my successful approach:
headers = {
'Authorization': 'Bearer Muh Token'
}
try:
response = requests.get(
'{domain}/users/{id}'\
.format(domain=USERS_API_URL, id=hit['id']),
headers=headers)
response.raise_for_status()
except HTTPError as err:
logging.error(err)
flask.abort(flask.Response(response=response.content, status=response.status_code, headers=response.headers.items()))
I'm trying to make a RESTful api call in python/django with requests.post
I can get requests.get(url=url, auth=auth) to work. Similar call in the same api family for this company
I'm trying to do:
data = {'start': 13388, 'end': 133885, 'name': 'marcus0.5'}
r = requests.post(url=url, auth=auth, headers={'Accept': 'application/json'}, data=data)
and I get the following error:
>>> r.text
u'{"status":"error","errorCode":"COMMON_UNSUPPORTED_MEDIA_TYPE","incidentId":"czEtbXNyZXBvcnRzMDQuc3RhZ2V4dHJhbmV0LmFrYW1haS5jb20jMTM3NTgxMzc3MTk4NQ==","errorMessage":"The server is refusing to service the request because the entity of the request is in a format not supported by the requested resource for the requested method.. Content type \'application/x-www-form-urlencoded;charset=UTF-8\' not supported."}'
I think it has something to do with the json, but I'm not sure what and I'm not sure how to fix it. Any ideas?
Extra info [not sure if it applies]:
I imported
import requests, django
I know the the auth is correct and I tested it with the get method
You want to set the Content-Type parameter of your request to 'application/json', not the Accept parameter.
Taken from w3.org:
The Accept request-header field can be used to specify certain media types which are acceptable for the response.
Try this instead:
import json
data = {'start': 13388, 'end': 133885, 'name': 'marcus0.5'}
r = requests.post(url=url, auth=auth, data=json.dumps(data),
headers={'content-type': 'application/json'})
EDIT:
There is a little bit of confusion (for me as well) about when to send data as a dict or a json encoded string (ie. the result of json.dumps). There is an excellent post here that explains the problem. For a brief summary send a dict when the API requires form-encoded data, and a json encoded string when it requires json-encoded data.