I have a question about JSON.stringify() and how to parse it. I have a frontend code and a backend in python (Django).
My fetch function looks like this in frontend.
const response = await fetch('some-url', {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
payload: payload
})
});
When i do console.log on JSON.stringify({payload: payload}), its type is string. Then in my backend code, when i print out request.data['payload']), its type is <class 'dict'>. I am confused why the type changed when i sent the request to the backed. I was going to use json.loads() to parse the payload but since it is already dictionary it returns an error and i can just do request.data['payload'] to access its data.
Can someone explain this behavior?
So I guess you are using Django Rest framework.
request.data
Will in Django Rest provide you with a parsed version of the request body. Because you are using the content-type: json it will try and parse it as .. json.
See docs here: https://www.django-rest-framework.org/api-guide/requests/#data
In regular Django for parsing a JSON request it would require the use of json.loads like:
parsed_json = json.loads(request.body)
Related
I have a website with a big form. When I first made the website, I was using a GET request to send the form values to a Python CGI script (using the JavaScript fetch function). In the Python script, I could read the data with parameters = cgi.FieldStorage().
Since a GET request has a limited payload size, I had to switch to a POST request because that request type has no limit.
I changed my JavaScript fetch function to the following to make a POST request:
fetch('../../cgi-bin/saveFormAnswers.py', {
method: 'POST',
body: JSON.stringify(data),
headers: {
'Content-type': 'application/json; charset=UTF-8',
}
})
.then(antwoord => antwoord.json())
.then(data => {
console.log("Return data Python:")
console.log(data);
}
);
However, I can't seem to get the data in the Python CGI script. cgi.FieldStorage() doesn't work anymore. How do I get the POST payload in the Python script and how do I send a (JSON) dictionary back as a response to the POST request?
I'm not using any frameworks like Flask.
EDIT: I came to the conclusion it's related to the JavaScript code and that cgi.FieldStorage() should work. Instead of letting JavaScript do the POST request, I set up the POST request directly in the HTML form which worked just fine without any issues. I'm still trying to figure out what's wrong with my JavaScript code.
Fixed it by using sys.stdin instead of cgi.FieldStorage().
data = ""
if int(os.environ.get('CONTENT_LENGTH', 0)) != 0:
for i in range(int(os.environ.get('CONTENT_LENGTH', 0))):
data += sys.stdin.read(1)
console.log("data ", data); // returns an object in JSON format {propertyName: propertyValue}
dataString = JSON.stringify(dataString); //correctly stringified json
let response = await fetch('updateRecevingEntry.php',
{
method:'POST',
headers: {'Content-Type':'application/json'},
body: dataString
}).then(response=>response.json());
however I get back an undefined index on the php side.
where the php is:
$matkey = $_POST['materialKey'];
returns
<b>Notice</b>: Undefined index: materialKey in <b>path/updateRecevingEntry.php</b> on line <b>3</b><br />
for all the data... none of it is getting caught.
so why is the _POST['propertyName'] not catching the stringData from the body?
I've tried a few variations, such as sending the data instead of the string data messing with the header, but I can't seem to figure out how to send the payload such that _POST['propertyName'] catches the data in the body.
I was using $.ajax from jquery before, and it was working: but I'm in the process of refactoring that out.
the Fetch api is new to me. where am I going wrong. I also don't want to parse a json object on the php side.
after reading one of the answers, I got it to work in one case,
but
let response = await fetch('updateRecevingEntry.php',
{
method:'POST',
headers: {'Content-Type':'application/json'},
body: sendData
}).then(response=>response.json());
and the php
$postData = json_decode(file_get_contents("php://input"), true);
var_dump($postData);
just returns a big fat NULL.
Edit two: turns out it just needs to actually be encoded via JSON.stringify(sendData). Since the. It works as expected.
The first thing I've noticed is that you're not using the right variable (you're using stringData instead of dataString):
dataString = JSON.stringify(dataString); //correctly stringified json
let response = await fetch('updateRecevingEntry.php', {
method:'POST',
headers: {'Content-Type':'application/json'},
body: dataString
}).then(response=>response.json());
Though you shouldn't need to stringify it as you're sending it with json headers.
Additionally, have you tried instead of $_POST, using php://input?
From PHP.net:
php://input is a read-only stream that allows you to read raw data from the request body. In the case of POST requests, it is preferable to use php://input instead of $HTTP_RAW_POST_DATA as it does not depend on special php.ini directives. Moreover, for those cases where $HTTP_RAW_POST_DATA is not populated by default, it is a potentially less memory intensive alternative to activating always_populate_raw_post_data. php://input is not available with enctype="multipart/form-data".
So you would use it like so:
$postData = json_decode(file_get_contents("php://input"), true);
$matkey = $postData['materialKey'];
This reads the body of the POST request as a JSON string then converts it to a PHP array.
I am working on converting angularjs application to react and decided to use axios for API request.
Everything work fine except some response body with JSON type but the boolean values are string type not boolean. It works fine with angularJs $http but some of endpoints returns like that.
The modules are AngularJs + Typescript 2.9.1 + axios 0.19.0
let request = Axios({
...requestConfig,
url: resource, method: 'get', responseType: 'json'
}).then(response => response);
and the response body is
{
some: "true"
}
but I am excepting
{
some: true
}
Any ideas?
[UPDATE] as Phil pointed out, Boolean('false') does not work. I updated the code to something that will work for 'true' and 'false', but a more complex function is needed if you want to cover all possibilities.
If the response by the API exactly looks like this:
{
"some": "true"
}
Then axios is not doing anything wrong. It's dangerous for a library to automagically parse values as they see fit, just look at how Json.NET handles values that they think look like Datetime.
If the payload returned by the API looks exactly like this:
{
"some" : true
}
Then axios should parse it as a boolean directly.
What I propose you do, is to always parse the value as a boolean, even if it is already one:
let request = await Axios({...requestConfig,
url: resource, method: 'get', responseType: 'json'
});
let someValue = String(request.data.some) == "true";
This will work for Boolean("true") as well as Boolean(true).
I have a JSON Array that I am trying to post to SENDGRID using Ajax. Using Postman I am able to post with no issues however when I post the data in my .js file I keep getting an error (bad request = missing parameters).
Any help is appreciated.
Note: The values are in fact valid. I have removed the identifying information for safety.
CHROME PAYLOAD:
AJAX Call:
var mailUrl = "https://api.sendgrid.com/v3/mail/send";
var postdata = '{"personalizations": [{"to":[{"to email"}],"from": {"email":"from email"},"subject":"Hello, World!" , "content" : [{ "type":"text/plain" , "value":"TestMessage!" }]}]}'
$.ajax({
type: 'POST',
headers: {Authorization: "Bearer APIKEY"},
url: mailUrl,
contentType: "application/json",
data: JSON.stringify(postdata),
success: function (res) {
alert('ok');
},
error: function (res) {
alert('problems');
}
});
The problem seems to be with this part of json [{"to":[{"to email"}].You can use jsonlint to validate the json. Also JSON.stringify() method converts a JavaScript value to a JSON string.
But in your case postdata is already a string .
The string stored in the variable is a valid JSON. Calling JSON.stringify() on a JSON will escape all the special characters like " and that escaped string will not be deserialized to the object you intended.
While a string is still a valid JSON according to some specifications, The specifications for application/json stated in RFC4627
An object structure is represented as a pair of curly brackets
surrounding zero or more name/value pairs (or members).
make the returned string invalid for post.
Sending the string itself without serializing it again will likely work.
There is a client-side JavaScript and server-side Python, powered by Django. There is a data object: foo_data = {"foo":1, "bar":2}.
Now, I would like to send a post-request using dojo/request/xhr, and send foo_data along with another variable:
xhr.post(document.location.href, {
data: {
'is_foo': true,
'data': foo_data
},
headers: { 'Content-Type': 'application/json' }
}).then(function(text){
console.log('The server returned: ', text);
});
And then read sent data in Django's views.py file:
def post(self, request, *args, **kwargs):
json.loads(request.body)
BUT, it doesn't work:
if I ssend foo_data, python doesn't recognize it correctly as JSON object and can't read it using json.loads.
I can't encode foo_data using JSON.parse because it is already an object!
request.POST is an empty QueryDict
request.body has string word object (instead of the real object)
Any ideas how to solve this?
Goal: send JSON object from JS --> Python and read it on server-side.
dojo.xhr has been deprecated, please consider using dojo/request more info here:
https://dojotoolkit.org/reference-guide/1.10/dojo/request/xhr.html#dojo-request-xhr
For a live example of post to a server, you can look source code for this page:
https://dojotoolkit.org/documentation/tutorials/1.8/ajax/demo/dojo-request-xhr-post.php
Here some a simple example of usage:
require(dojo/request"],
function(request){
// post the data to the server
request.post("your/server/script", {
// send your data here
data: { yourData: 1},
// wait 2 seconds for a response
timeout: 2000
}).then(function(response){
// do smt here when operation is successfully executed
});
}
);
Regarding your code sample in your question, you have't posted your server side code. But you could try to pass your data to the server using JSON.stringify().