Flask - Getting POST data from Angular $http.post() - javascript

In a very basic test web app I am making, I am using angular to run a function when a form is submitted. The function asynchronously posts data to a simple api I built which is supposed to input data into a database dependent on the POST information it receives. It seems like the POST is working correctly on the front end, however I cannot access request.json from Flask at all or get any of the post data. I feel like this problem may be something simple I have overlooked but as of now I cannot figure it out at all. Here is some of the code:
AngularJS:
$scope.submitAddMsg = function (){
var data = {'author': $scope.msgauthor, 'message': $scope.msgmsg};
$http.post('/addMessage', data, {headers: {'Content-Type': 'application/json'}}).
success(function(data, status, headers, config) {
console.log(data);
console.log(status);
console.log(headers);
console.log(config);
}).
error(function(data, status, headers, config) {
alert(JSON.parse(data));
});
};
Flask view function for /addMessage
#app.route('/addMessage', methods=['POST'])
def addMessage():
#results in 'None type not iterable'
#response = request.form.get('author')
#results in a 400 error
#response = request.get_json()
#results in a 400 error
#response = request.get_json()
#results in 'author' not defined
#name = request.args.get('author')
#return jsonify(author = author)
return str(jsonify(response))
I cannot stop getting errors as if the request is not what I think it should be, is there something else I should be doing to properly handle this? Because I cannot access any POST information when using Angular to send the POST or even a REST Client with payload exactly how the angular is sending data.
Here is the JavaScript console to see what data, status, headers, and config ends up being in the success function that runs after the POST:
<Response 46 bytes [200 OK]>
testbase.js:53 200
testbase.js:54 function (c){a||(a=Xc(b));return c?(c=a[z(c)],void 0===c&& (c=null),c):a}
testbase.js:55 Object {method: "POST", transformRequest: Array[1], transformResponse: Array[1], headers: Object, url: "/addMessage"…}data: Objectheaders: ObjectAccept: "application/json, text/plain, */*"Content-Type: "application/json"__proto__: Objectmethod: "POST"transformRequest: Array[1]transformResponse: Array[1]url: "/addMessage"__proto__: Object
Any help on getting this working right is much appreciated, let me know if you need more information

you can use request.data to get the raw post data.
you can also set the silent Flag of get_json to True so you can get the exact message of failure.
from the docs
get_json(force=False, silent=False, cache=True)
Parameters:
force – if set to True the mimetype is ignored.
silent – if set to False this method will fail silently and return False.
cache – if set to True the parsed JSON data is remembered on the request.

Try adding app.debug = True before you start the app and try again.
You can also try:
message = request.json.get('message')
And I would also try putting this in your route
['POST', 'OPTIONS'])

Related

Sending A Json object through Fetch API to a Flask Server leads to a 400 Bad Request [duplicate]

This question already has answers here:
How to get POSTed JSON in Flask?
(13 answers)
Closed 2 days ago.
I was trying to send some JSON data to the sever following some online articles and the official flask documentation, but I keep getting a 400 error. What I've tried hasn't worked so far.
I have read that if flask doesn't get properly formated JSON data it pushes this error and also that the read of the request must specify Content-Type header as application/json or else the same happens.
I copied some of my code off the official Documentation and this is what i have so far:
a view function inside my flask application:
#main.route('/test', methods=['GET','POST'])
def test():
if request.method == 'POST':
print(request.method)
print(request.headers.get('Content-Type'))
print(request.is_json)
#this gets me the 400 when run
#print(request.json)
return render_template('test.html')
the following scrip tag inside test.html:
<script>
let data = {"data": "Hello World!"}
document.querySelector('#main').addEventListener('click', function () {
fetch('/test', {
method: "POST",
body: JSON.stringify(data),
headers: {"Content-Type": "application/json"},
credentials: "same-origin"
})
.then(response => console.log(response.json))
})
</script>
Every time I hit the button to POST the data I get the following showing in my terminal
POST
text/plain;charset=UTF-8
False
So I assume what is causing all of this is that the Content-Type header of the HTTP request is not setting properly.
Any ideas on how I could fix this would be apreciated
Based on your code and the error message you are receiving, the issue might be related to the request header not being set correctly.
You are setting the Content-Type header in your JavaScript code to "application/json", which is correct. However, your Flask view function does not check the Content-Type header correctly. You can check it like this:
if request.is_json:
data = request.get_json()
print(data)
else:
print("Request is not JSON")
This checks whether the request is in JSON format using the is_json property of the request object. If it is, then you can use the get_json() method to extract the data. If it's not, you can print a message or return an error.
Additionally, you might want to add a try-except block to catch any errors that might occur when parsing the JSON data:
if request.is_json:
try:
data = request.get_json()
print(data)
except Exception as e:
print("Error parsing JSON data:", e)
return "Bad Request", 400
else:
print("Request is not JSON")
return "Bad Request", 400
This will catch any exceptions when parsing the JSON data and return a "Bad Request" error with a 400 status code.
I hope this helps!
You need to specify the full endpoint of what you are targeting.
from flask import Flask, request
# create the flask app
app = Flask(__name__)
# post endpoint
#app.route('/post', methods=['POST'])
def endpoint():
data = request.get_json()
return data
# run the app
if __name__ == '__main__':
app.run(debug=True)
const endpoint = "http://127.0.0.1:5000/post";
// post request to endpoint
const response = fetch(endpoint, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
name: "John Doe",
})
});
response.then(data => {
data.text().then(text => {
console.log(text);
})
})

What is the correct way to post images on django-rest-framework server using javascript?

I have a POST API view that accepts an image and a style sting and returns a styled image.
It works on postman just fine but I cannot get it to work using fetch API.
Serializer:
class GetImageSerializer(serializers.Serializer):
image = serializers.ImageField()
style = serializers.CharField()
DRF view:
class PostImage(APIView):
serializer_class = GetImageSerializer
parser_classes = [MultiPartParser]
def post(self, request, format=None):
print(request.data) # Debug
img = request.data.get('image')
# Process
response = FileResponse(img)
return response
The fetch call:
json = {}
json["image"] = this.state.image
json["style"] = "models\\wave\\wave200.pth"
console.log("sending --- ", json) //debug
fetch('/style_transfer/style/',
{
headers: { "Content-type": "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW" },
body: json,
method: "POST"
}
).then(response => {
if (!response.ok) {
console.log("couldn't fetch image")
}
return response.json()
})
.then(data => {
console.log("fetched data")
console.log(data)
outputs of console logs. This shows that the correct data is in json dictionary
But the data isn't received by DRF server.
The print(request.data) from the view returns <QueryDict: {}>.
The strange part is that the same code works with postman.
Things I've tried:
Remove the headers from fetch request - This throws unsupported media type error
Set content-type to "application/json" - This reads the string parameter but image key is empty. this is what request.data looks like {'image': {}, 'style': 'models\\wave\\wave200.pth'}
I want to understand what's causing this issue. I've read several similar threads but I couldn't find the recommended way to do something like this. So, what's the issue and what is the recommended way of doing this?

Getting None values for POST request (via the Axios library) sent to Python/Django

I am building a web app with Django/Python and trying to send data to a controller via a POST request using the Axios library (within Vue.js code).
The POST QueryDict seems to be empty and I can't see why that is happening:
changeCountry: function(e, id){
console.log("Let's change the country")
console.log(e.target.value) // is printing correctly
console.log(id) // also printing correctly
axios({
method: 'post',
url: '/template/country',
data: {
id: id,
country: e.target.value
},
headers: {
'X-CSRFToken': "{{csrf_token}}"
}
})
.then(function (response) {
alert(response.data); // this is returning what I expect
})
.catch(function (error) {
console.log(error);
})
},
The Python method looks like this:
def update_template_country(request):
pprint(request.POST) # prints an empty QueryDict
id = request.POST.get('id')
country = request.POST.get('country')
print(id, country) #prints None None
return HttpResponse("The country is changed") # this is being returned back to the client
The console.log messages at the top print what I expect and since there is no error I am assuming the CSRF header token is fine. Have I missed something obvious or misunderstood how this is working?
EDIT: looking at the Chrome Network tab, it seems the data is being 'POSTed' correctly:
It shows this:
{"id":"593ff2270098e6e8d3292b60","country":"US"}
and that's what I expect, so I suspect the issue is with Django. But I can't see what that might be.
Write your python POST request like this:
def update_template_country(request):
data = json.loads(request.body)
id = data["id"]
country = data["country"]
'''Any other function you want to perform'''
return HttpResponse(json.dumps({'message':'The country is changed'},status=200)
Basically the problem is with the format of POST request, Django is not able to parse it properly that's why when you print the POST request it return an empty dictionary.

python3.5 aiohttp, request post, json format and 405 errors

I finally sign up because I have no more idea for my problem.
I use asyncio and aiohttp for my back-end part and javascript for the front-end part. But I stuck with a 405 error. (I precise I am a beginner with theses libraries)
I wish retrieve a json from a post request. Here the javascript function:
function postJson (data){
$.ajax({
url : 'http://localhost:8080/postJson',
type : 'POST',
dataType : 'json',
contentType : 'application/json',
data : data, //data are ready at json format, I do not think I need to use JSON.stringify ? I does not change anything to the error anywhere
success : function(code_html, statut){
console.log("success POST");
},
error : function(resultat, statut, erreur){
console.log("error POST");
}
});
}
and the python code:
async def postJson(request):
data = await request.post()
#some code
return Response()
#asyncio.coroutine
def init(loop):
app = Application(loop=loop)
app.router.add_route('POST', '/postJson', postJson)
handler = app.make_handler()
srv = yield from loop.create_server(handler, '127.0.0.1', 8080)
print("Server started at http://127.0.0.1:8080")
return srv, handler
loop = asyncio.get_event_loop()
srv, handler = loop.run_until_complete(init(loop))
try:
loop.run_forever()
except KeyboardInterrupt:
loop.run_until_complete(handler.finish_connections())
With this code I get a 405 error. Here a bite of what says firebug about the request:
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 // so json is not in the list.
however, if I take back the line contentType : 'application/json' in my javascript file, it works (but the request send a object called MultiDictProxy and I don't understand how to use the function json() from aiohttp.web package (here).
I really need to get a json object. Someone could help me?
I find the solution. I post the conclusion here for people who could be interested:
python side:
replace the line app.router.add_route('POST', '/postJson', postConf) by
app.router.add_route('POST', '/postJson', postConf, expect_handler = aiohttp.web.Request.json)
in the postJson method:
replace data = await request.post() by data = await request.json()
and on javascript side:
data : JSON.stringify(data)
with this, my method works.
Your example works fine except two things:
#asyncio.coroutine and async with are mutually exclusive
postJson() must return response instance, not None

$http angularjs shows error on callback

I tested my php alone and it gave me this result
{"tabId":1,"tabName":"Main","uId":"1"}{"tabId":2,"tabName":"Photography","uId":"1"}
but my angularjs can't receive the callback, it return an error somewhere in angularjs
userId = '1';
$http({
url: "php/loadTab.php",
method: "GET",
params: {'userId':userId}
}).success(function(data, status, headers, config) {
console.log(data);
}).error(function(data, status, headers, config) {
});
the wierd thing I reuse the exact ajax code and it worked previously. Any thought on this?
the error : SyntaxError: Unexpected token {
at Object.parse (native)
the more strange thing : I purposely add another echo on my php and it able to console the value. what?!
The data from the server isn't valid JSON.
$httpProvider.defaults.transformResponse will try to parse the JSON if the data looks like JSON.
https://docs.angularjs.org/api/ng/service/$http
To fix this you could make the parent an array of objects like this
[{"tabId":1,"tabName":"Main","uId":"1"},{"tabId":2,"tabName":"Photography","uId":"1"}]

Categories

Resources