I have attempted to create a request in javascript, that has previously worked using python just fine.
the following is an accurate representation of the code I used to post the request with python:
url = 'https://website.com/api/e1'
header = {
'authorization': 'abcd1234'
}
payload = {
'content': "text",
}
r = requests.post(url, data=payload,headers=header )
This (above) works just fine in python.
now what I did in javascript is the following:
payload = {
"content": "this is text",
};
fetch("https://website.com/api/e1", {
method: "POST",
headers: {
"authorization":
"abcd1234",
},
body: JSON.stringify(payload),
});
but this is returning the error
400- Bad request
When using data parameters on python requests.post, the default Content-Type is application/x-www-form-urlencoded(I couldn't find it on the document, but I checked the request. If you know, please leave a comment).
To achieve the same result with fetch, you must do as follows.
const payload = {
'content': 'this is text',
};
fetch('https://website.com/api/e1', {
method: 'POST',
headers: {
'authorization': 'abcd1234',
},
body: new URLSearchParams(payload),
});
You don't need to do this body: JSON.stringify(payload), rather you can simply pass payload in body like this body:payload
Related
I'm trying to send form data from a NativeScript app to a TYPO3-Webservice.
This is the JavaScript I'm using:
httpModule.request({
url: "https://my.domain.tld/webservice?action=login",
method: "POST",
headers: { "Content-Type": "application/json" },
content: JSON.stringify({
username:username,
password:password
})
}).then((response) => {
console.log("got response");
console.log(response.content);
//result = response.content.toJSON();
callback(response.content.toJSON());
}, (e) => {
console.log("error");
console.log(e);
});
But I can't read this data in the controller. Even with this:
$rest_json = file_get_contents("php://input");
$postvars = json_decode($rest_json, true);
$postvars is empty. $_POST is empty, too (which is - according to some docs - because the data is sent as JSON and thus the $_POST-Array isn't populated.
Whatever I do, whatever I try, I can't get those variables into my controller.
I tried it with fetch as well as with formData instead of JSON.stringify, same result.
I might have to add, that when I add the PHP-part in the index.php of TYPO3, $postvars is being populated. So I guess something goes missing, until the controller is called.
Any ideas?
the nativescript part seems ok, your problem must be corrected in the server side.
i use similare call and its works
// send POST request
httpModule.request({
method: "POST",
url: appSettings.getString("SERVER") + '/product/list',
content: JSON.stringify(data),
headers: {"Content-Type": "application/json"},
timeout: 5000,
}).then(response => { // handle replay
const responseAsJson = response.content.toJSON();
console.log('dispatchAsync\n\tresponse:', responseAsJson);
}, reason => {
console.error(`[ERROR] httpModule, msg: ${reason.message}`);
});
html-javascript
var csrftoken = $('[name="csrfmiddlewaretoken"]').val();
$('#Save').click(function () {
var ajaxdata = {
exam: $('#Exam').val()
};
$.ajax({
url: '/save',
type: 'POST',
dataType: 'json',
data: JSON.stringify(ajaxdata),
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
"X-CSRFToken": csrftoken
},
credentials: 'include',
success: function () {
alert(ajaxdata);
console.log(ajaxdata);
},
error:function (xhr, ajaxOptions, thrownError){
console.log(ajaxdata);
}
});
}
views.py
import json
from django.http import HttpResponse
def save(request=request):
data = json.loads(request.body)
testexam = data['exam']
testexam = request.POST.get('exam')
testobj = MyObject.objects.filter(name="David").first()
testobj.Exam = testexam
testobj.save()
return HttpResponse(json.dumps({"success": True}), content_type="application/json")
These are my html and views now.
Removed the "flask" part.
data = json.loads(request.body)
allowed me to receive data successfully!
Still don't quite understand why " request.POST " didn't work.
I'll come back later to update if I manage to know the reason!
Thanks for the comments and useful suggestions!
No need using the flask.
This is how I receive the data:
data = json.loads(request.body)
and it all works well!
Thanks for all the comments, suggestions, answers! Really appreciated!
your ajax code is just fine, however you're doing few things wrong. First of all, in your html part.
<h1> This is simple html</h1>
<input type="text" id = "Exam">
<button type="button" id="Save">Save</button>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script>
var csrftoken = $('[name="csrfmiddlewaretoken"]').val();
$('#Save').click(function () {
var ajaxdata = {
exam: $('#Exam').val()
};
$.ajax({
url: '/save',
type: 'POST',
dataType: 'json',
data: JSON.stringify(ajaxdata),
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
"X-CSRFToken": csrftoken
},
credentials: 'include',
success: function () {
alert(ajaxdata)
},
error:function (xhr, ajaxOptions, thrownError){
console.log("this is an error")
}
});
});
</script>
You were initiating the ajaxdata before the click event happened, which may lead to the null value of #Exam filed.
Now getting back to your Flask part, you can't do request.POST with the data sent through Ajax request. Rather you can access all the data you sent through your js with request.data, below is the code which is working successfully.
from flask import Flask, request,send_from_directory
import json
# set the project root directory as the static folder, you can set others.
app = Flask(__name__)
#app.route('/home')
def root():
#return "this is home"
return send_from_directory("/home/ekbana/Documents/","index.html")
#app.route('/save',methods=['POST'])
def save(request=request):
print(request.data.decode("utf-8")) #We need to decode because it's a byte
#not a string
data = json.loads(request.data.decode("utf-8"))
#data here is {'exam': 'a text'} a dict in this case
testexam = data["exam"]
testobj = MyObject.objects.filter(name="David").first()
testobj.Exam = testexam
testobj.save()
return HttpResponse(json.dumps({"success": True}), content_type="application/json")
This is working fine with me, I replicated a simple example for your requirement. Aslo make sure to use methods=["POST"] if you want your route to recieve the POST request, if you didn't specify it, it may lead to HTTP_405_METHOD_NOT_ALLOWED.
I have a call made from my client that passes in some post data like this:
function doSomethingApi(email) {
return axios({
method: 'post',
url: `/api`,
data: {
scan_refference: 'ref',
user_email: email
}
})
}
On the server side this gets proxied to apply certain secrets:
app.post('/api', (req, res) => {
const url = 'https://my.api.com';
req.pipe(request({
url,
headers: {
'Content-Type': 'application/json',
Accept: 'application/json'
},
auth: {
user: secrets.USERNAME,
pass: secrets.PASSWORD
},
body: {
value1: `${secrets.VALUE1}`,
value2: `${secrets.VALUE2}`
}
})).pipe(res);
});
request and axios are just 2 different http libraries I use, one is preferred for client other for server, thats all. Issue now is that I am overwriting body in my proxy, where as I want to simply add value1 and value2 to existing body passed from client.
First get the body from the initial call as a JSON object. This depends on what you use, but e.g. in Express you could:
app.use(express.bodyParser());
Then
var previousBody = req.body
Finally merge the initial JSON with whatever you want (NOTE: this means your client will definitely not be able to use the "value1" and "value2" properties, because they will be overwritten)
body: Object.assign(previousBody, {
value1: `${secrets.VALUE1}`,
value2: `${secrets.VALUE2}`
})
I'm trying to POST to an API endpoint on my server. I know my endpoint works because if I use Advanced REST Client, I can hit it and get a JSON response as expected. The problem seems to be that no data is being sent in the body of my request despite calling request.write(postData) which contains a key, value pair. Without this data being sent in the body, my server returns a 401 error as expected without this information. Printing out the content of the POST server-side is empty but I'm clueless as to why it's empty.
var postData = querystring.stringify({
"access_token" : accessToken,
"id": applianceId
});
var serverError = function (e) {
log("Error", e.message);
context.fail(generateControlError(requestName, "DEPENDENT_SERVICE_UNAVAILABLE", "Unable to connect to server"));
};
var callback = function(response) {
var str = "";
response.on("data", function(chunk) {
str += chunk.toString("utf-8");
});
response.on("end", function() {
result = generateResult(CONTROL, requestName.replace("Request", "Confirmation"), messageId);
context.succeed(result);
});
response.on("error", serverError);
};
var options = {
hostname: REMOTE_CLOUD_HOSTNAME,
port: 443,
path: REMOTE_CLOUD_BASE_PATH + "/" + endpoint,
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded"
}
};
var request = https.request(options, callback);
request.on("error", serverError);
//This doesn't seem to write anything since if I print out the POST
//data server-side it's empty; however, if I print out the value of
//postData here, it looks as expected: 'access_token=xxxxx'
request.write(postData);
request.end();
I have testing you code again httpbin.org/post and it seems that it is working.
I believe that the issue related to, that your should POST application/json and not "application/x-www-form-urlencoded
Please try to change the header
headers: {
"Content-Type": "application/json"
}
Then, try to change the postData to JSON string:
var postData=JSON.stringify({access_token:"xxxxx"})
To be sure that problem you success to send and the problem is not local (maybe there is an issue in your server), change the target to mirror URL:
var options = {
hostname: "httpbin.org",
path:'/post',
port: 443,
method: "POST",
headers: {
"Content-Type": "application/json"
}
};
If there is no problem in your NodeJS version, the is the response you should get: (It is mean that the server got the posted data)
{
"args": {},
"data": "{\"access_token\":\"xxxxx\"}",
"files": {},
"form": {},
"headers": {
"Content-Length": "24",
"Content-Type": "application/json",
"Host": "httpbin.org"
},
"json": {
"access_token": "xxxxx"
},
"origin": "5.29.63.30",
"url": "https://httpbin.org/post"
}
BTW: I really recommend you to move to a library to manage the request for you:
https://github.com/request/request - Very popular
https://github.com/request/request-promise - For popular who like to use the Promise syntax (The next thing in JavaScript)
https://github.com/visionmedia/superagent - For people who like to write same code in Browser & Server
This seems very similar to a number of other questions and it seems obvious that the error indicates there's something wrong with my JSON payload. But I'm at a loss as to why.
I'm running a Google Apps Script to test sending a message to Google Firebase Cloud Messaging.
My code:
function SendGCMessage() {
var url = "https://gcm-http.googleapis.com/gcm/send";
var apiKey = "AbCdEfG";
var to = "ZyXwVuT:ToKeNtOkEnToKeNtOkEnToKeNtOkEn"
var payload = {
"data": {
"message" : "This is the message"
},
"to":to
};
var sendCount = 1;
var headers = {
"Content-Type": "application/json",
"Authorization": "key=" + apiKey
};
var params = {
headers: headers,
method: "post",
payload: payload
};
var response = UrlFetchApp.fetch(url, params);
return {message: "send completed: " + response.getContentText()};
}
When I run this in debug mode, the object payload looks fine - like a normal Javascript object. params as well. UrlFetchApp takes a Javascript object, not a String in JSON notation. However I did try "JSON.stringify(params)" and I got an error. What did I do wrong?
Note: params looks like this when I pause it in the debugger:
{"headers":{"Content-Type":"application/json","Authorization":"key=AbCdEfG"},"method":"post","payload":{"data":{"message":"This
is the message"},"to":"ZyXwVuT:ToKeNtOkEnToKeNtOkEnToKeNtOkEn"}}
I discovered the problem, thanks to https://stackoverflow.com/a/10894233/3576831
the 'payload' parameter must be a string as specified here:
https://developers.google.com/apps-script/class_urlfetchapp?hl=fr-FR#fetch.
Adjusting this section of the script works:
var params = {
headers: headers,
method: "post",
payload: JSON.stringify(payload)
};