Why is my request body not being populated correctly - python

I am trying to test a very simple Express App. I have my Express set up in a typescript file as follows to respond with the body of the request that it receives:
app.listen(3000, () => console.log('Server running on port 3000'))
app.use(bodyParser.urlencoded({
extended: true
}))
app.use(bodyParser.json())
app.get('/test', (req, res) => {
res.send(req.body)
});
I am trying to call this endpoint in a python file as follows
testUrl = 'http://localhost:3000'
path = '/test'
header = {
'Content-Type': 'application/json',
}
body = {
'artistName': 'test',
}
response = requests.request(
method="GET",
url = testUrl + path,
params=header,
data=body,
)
print(response._content)
When I run the python file, all it prints out is a set of empty brackets, telling me that the body of the request it is receiving is empty. Why is the body empty if I am setting the data parameter to a populated json object? Am I using the wrong parameters? Thanks for the help!

I don't know what you mean to do with res.send(req.body) in your Express code, but req.body is not used for a GET request in Express. That's used for a POST or PUT.
Parameters for a GET request are put in the URL as part of the queryString and will appear in the req.query object in Express.

I think your mistake is in the request,
Because you are sending your header as params

Related

how to get json object from a webservice

i have the below posted json response.as shown below in json section, the parametersobject is emitted in this line (this is an angular application)
this._FromInsToSiteDataService.emitOnSubmitButtonClikedBroadcast(parameters)
and it is received in
this.subscriptionBroadcastEmitterOnSubmitButtonClicked = this._FromInsecticidesToSiteMapDataService.getBroascastEmitterOnSubmitButtonClicked().subscribe((response:Object)=>{
response['siteGeometry'] = this.selectedSite.geometry
console.log("response: ", response)
this.sSProvider.startWebServiceFor(response)
});
in the latter code i want to pass the response which is in json format to the webservice and receive it as show in the websrvicepostedbelow`
when i run the code, i expected to see the contents of the json object which is
{
"dist1": d1,
"dist2": d2,
"date1": date1,
"date2": date2,
"ingredient": activeIngredient
}
but i get NONE
please let me know how can i correctly get a json object from a webservice
json
private submit() {
let parameters = {
"dist1": d1,
"dist2": d2,
"date1": date1,
"date2": date2,
"ingredient": activeIngredient
}
this._FromInsToSiteDataService.emitOnSubmitButtonClikedBroadcast(parameters)
receiving the json object
this.subscriptionBroadcastEmitterOnSubmitButtonClicked = this._FromInsecticidesToSiteMapDataService.getBroascastEmitterOnSubmitButtonClicked().subscribe((response:Object)=>{
response['siteGeometry'] = this.selectedSite.geometry
console.log("response: ", response)
this.sSProvider.startWebServiceFor(response)
});
webservice:
#app.route("/insSpecifications/<parameters>", methods=['GET'] )
def insSpecifications(parameters):
# print(request.json())
print(request.get_json())//returns NONE
return "OK"
Intro
There are two parts to your question -
Making a request from JS
Creating a Flask API to handle the request
Both these have extensively answered on SO hence I will only summarize it here, please follow the links for more information
Answer
REST Method:
When sending JSON data from the front end to the backend, you need to make a POST request or PUT depending on the need. Please read up on REST API concepts to understand the methods and purposes.
https://www.w3schools.in/restful-web-services/rest-methods/
Making a request
Depending on which library you use in the front end, the request might look different, but essentially you need to send a request with JSON in the body and HEADERS set appropriately i.e. Content-Type: application/json
Using FETCH this can be achieved by (auto-generated from postman)
var myHeaders = new Headers();
myHeaders.append("Content-Type", "application/json");
var raw = JSON.stringify({
"username": "Sample1",
"email": "test2#test.com"
});
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: raw,
redirect: 'follow'
};
fetch("localhost:5000/sample", requestOptions)
.then(response => response.text())
.then(result => console.log(result))
.catch(error => console.log('error', error));
But most libraries would have wrappers around this, please look into making a POST request for your respective JS library
Creating Flask API
Finally, you need a Flask API to consume this request. Assuming it's a POST request. You need to create a route with method as POST and get the JSON data using get_json() : https://stackoverflow.com/a/20001283/5236575
So once the HEADERS are correctly set and a post request is made, your code should work fine by changing GET to POST
Note: The parameters field is captured correctly hence I'm leaving it as is, but that is not where your JSON body comes from
#app.route("/insSpecifications/<parameters>", methods=['POST'] )
def insSpecifications(parameters):
# print(request.json())
print(request.get_json())
return "OK"
Testing
You can test your API using Postman or any other API testing tool to see how the API behaves and validate if the issue you have is in the API or in the front-end code.

why string is changed to % when I send with post to my server

string that I want to send is
let param={"value":"data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2w"};
this.postHttp("http://202.31.237.173/ionic",param);
postHttp(url: string, param: any = {}) {
param = this.jsonToURLEncoded(param);
console.log(param);
let headers = new Headers({ 'Content-Type' : 'application/x-www-form-urlencoded', 'Accept' : 'application/json' });
//let headers = new Headers({ 'Content-Type' : 'application/json' });
let options = new RequestOptions({ headers: headers });
//return this.http.post(url, param, options).map((res: Response) => res.json() );
this.http.post(url, param, options).subscribe((o)=>{
console.log("subscribe in post http")
})
}
but when I received it in my server.
string value is shown as
'value=data%3Aimage%2Fjpeg%3Bbase64%2C%2F9j%2F4AAQSkZJRgABAQAAAQABAAD%2F2w'
it changes / to % ...etc...why is it happened and how to solve it?
server code that receive is as below
#app.route("/ionic", methods=['POST'])
def predictionic():
data = request.get_data()
print(data);
Pretty sure this is because you're using the jsonToURLEncoded() function. You dont need to do this, because the params you're encoding is actually the json body. json bodies are jsons, and not part of the url.
The value you're using in the "params" is fine and can be sent and received exactly as you defined it without any further encoding.

Basic authentication not working in node-rest-client node

I'm using node-rest-client library to call my rest API running a python flask app in a test server. The Node setup and request code is below.
If I add a user token to the request header it words fine, but in the call to obtain the user token using basic auth my python system is successfully authenticating and returning the token with a 200 status, but the flask server is then changing this to a 400 Bad Request. It works fine making the call using Postman.
Is there something missing from my two config objects for node-rest-client?
Cheers.
var options_auth = {
user: "bob",
password: "password",
mimetypes: {
json: ["application/json", "application/json;charset=utf-8"]
}
};
var Client = require('node-rest-client').Client;
var client = new Client(options_auth);
var method = "/authtoken";
var args = {
headers: {
"Content-Type": "application/json",
"api-key": "asf89a7assa98d7sd98d98ds",
//"token": "dsf98s7dsf98dsf7sd98f7dsf",
"Accept": "application/json"
},
responseConfig: {
timeout: 1000 //response timeout
}
};
client.get(Api.url+method, args, function (data, response) {
// parsed response body as js object
// raw response
//console.log(response);
if(Buffer.isBuffer(data)){
data = data.toString('utf8');
}
console.log(data);
var stringData = data.toString('utf8');
console.log("String data = "+stringData);
}).on('error', function (err) {
console.error('Something went wrong with the http client', err);
});
Also, spotted these differences between the request headers received by the server:
// Node Request fails: 400
'headers': EnvironHeaders([
('Authorization', u'Basic XXXXXXXXXXXXXX=='),
('Vga-Api-Key', u'xxxxxxxxxxxxxxxxxxxxxxxx'),
('Content-Length', u'0'),
('Connection', u'close'),
('Host', u'127.0.0.1:8080'),
('Accept', u'*/*'),
('Content-Type', u'application/json')]),
// Postman Request works: 200
'headers': EnvironHeaders([
('Authorization', u'Basic XXXXXXXXXXXXXX=='),
('Vga-Api-Key', u'xxxxxxxxxxxxxxxxxxxxxxxx'),
* ('Content-Length', u''),
* ('Connection', u'keep-alive'),
('Host', u'127.0.0.1:8080'),
* ('Cache-Control', u'no-cache'),
('Accept', u'*/*'),
('Content-Type', u''),
* ('Accept-Encoding', u'gzip, deflate')]),
The problem is your setting of the header Content-Type: application/json and the probable calling in the server of request.get_json() directly, or indirectly via the (deprecated) request.json property.
When get_json() is called Flask will check to see that a JSON payload has been sent in the body of the request and then parse it if present. That's OK if the request actually contains JSON in the body, but, being a GET request, yours doesn't. In this case, its JSON expectation being unfulfilled, the server raises a BadRequest error and returns a HTTP 400 error response.
From what you've shown your request doesn't need to be JSON because the authorisation username and password are passed in the Authorization: Basic xxxxxxxx header.
The easiest and best way to fix the problem is to simply omit the content type header.
Alternatively you can tell Flask not to complain if there is no JSON data to parse by passing silent=True to get_json, but this just papers over the problem and is not a good idea.

Facebook Messenger with Flask

I'm trying to get the FB messenger API working using Python's Flask, adapting the following instructions: https://developers.facebook.com/docs/messenger-platform/quickstart
So far, things have been going pretty well. I have verified my callback and am able to receive the messages I send using Messenger on my page, as in the logs in my heroku server indicate the appropriate packets of data are being received by my server. Right now I'm struggling a bit to send responses to the client messenging my app. In particular, I am not sure how to perform the following segment from the tutorial in Flask:
var token = "<page_access_token>";
function sendTextMessage(sender, text) {
messageData = {
text:text
}
request({
url: 'https://graph.facebook.com/v2.6/me/messages',
qs: {access_token:token},
method: 'POST',
json: {
recipient: {id:sender},
message: messageData,
}
}, function(error, response, body) {
if (error) {
console.log('Error sending message: ', error);
} else if (response.body.error) {
console.log('Error: ', response.body.error);
}
});
}
So far, I have this bit in my server-side Flask module:
#app.route('/', methods=["GET", "POST"])
def chatbot_response():
data = json.loads(req_data)
sender_id = data["entry"][0]["messaging"][0]["sender"]["id"]
url = "https://graph.facebook.com/v2.6/me/messages"
qs_value = {"access_token": TOKEN_OMITTED}
json_response = {"recipient": {"id": sender_id}, "message": "this is a test response message"}
response = ("my response text", 200, {"url": url, "qs": qs_value, "method": "POST", "json": json_response})
return response
However, running this, I find that while I can process what someone send my Page, it does not send a response back (i.e. nothing shows up in the messenger chat box). I'm new to Flask so any help would be greatly appreciated in doing the equivalent of the Javascript bit above in Flask.
Thanks!
This is the code that works for me:
data = json.loads(request.data)['entry'][0]['messaging']
for m in data:
resp_id = m['sender']['id']
resp_mess = {
'recipient': {
'id': resp_id,
},
'message': {
'text': m['message']['text'],
}
}
fb_response = requests.post(FB_MESSAGES_ENDPOINT,
params={"access_token": FB_TOKEN},
data=json.dumps(resp_mess),
headers = {'content-type': 'application/json'})
key differences:
message needs a text key for the actual response message, and you need to add the application/json content-type header.
Without the content-type header you get the The parameter recipient is required error response, and without the text key under message you get the param message must be non-empty error response.
This is the Flask example using fbmq library that works for me:
echo example :
from flask import Flask, request
from fbmq import Page
page = fbmq.Page(PAGE_ACCESS_TOKEN)
#app.route('/webhook', methods=['POST'])
def webhook():
page.handle_webhook(request.get_data(as_text=True))
return "ok"
#page.handle_message
def message_handler(event):
page.send(event.sender_id, event.message_text)
In that scenario in your tutorial, the node.js application is sending an HTTP POST request back to Facebook's servers, which then forwards the content on to the client.
So far, sounds like your Flask app is only receiving (AKA serving) HTTP requests. The reason is that that's what the Flask library is all about, and it's the only thing that Flask does.
To send an HTTP request back to Facebook, you can use any Python HTTP client library you like. There is one called urllib in the standard library, but it's a bit clunky to use... try the Requests library.
Since your request handler is delegating to an outgoing HTTP call, you need to look at the response to this sub-request also, to make sure everything went as planned.
Your handler may end up looking something like
import json
import os
from flask import app, request
# confusingly similar name, keep these straight in your head
import requests
FB_MESSAGES_ENDPOINT = "https://graph.facebook.com/v2.6/me/messages"
# good practice: don't keep secrets in files, one day you'll accidentally
# commit it and push it to github and then you'll be sad. in bash:
# $ export FB_ACCESS_TOKEN=my-secret-fb-token
FB_TOKEN = os.environ['FB_ACCESS_TOKEN']
#app.route('/', method="POST")
def chatbot_response():
data = request.json() # flasks's request object
sender_id = data["entry"][0]["messaging"][0]["sender"]["id"]
send_back_to_fb = {
"recipient": {
"id": sender_id,
},
"message": "this is a test response message"
}
# the big change: use another library to send an HTTP request back to FB
fb_response = requests.post(FB_MESSAGES_ENDPOINT,
params={"access_token": FB_TOKEN},
data=json.dumps(send_back_to_fb))
# handle the response to the subrequest you made
if not fb_response.ok:
# log some useful info for yourself, for debugging
print 'jeepers. %s: %s' % (fb_response.status_code, fb_response.text)
# always return 200 to Facebook's original POST request so they know you
# handled their request
return "OK", 200
When doing responses in Flask, you have to be careful. Simply doing a return statement won't return anything to the requester.
In your case, you might want to look at jsonify(). It will take a Python dictionary and return it to your browser as a JSON object.
from flask import jsonify
return jsonify({"url": url, "qs": qs_value, "method": "POST", "json": json_response})
If you want more control over the responses, like setting codes, take a look at make_response()

AngularJS - http request with Basic Auth (connect to FreeNAS)

Im trying to connect to the REST API of FreeNAS (http://api.freenas.org/authentication.html) within my AngularJS app. The API uses basic authentication with username and password.
In python this is a very easy thing as there is only one line of code:
requests.get('http://freenas.mydomain/api/v1.0/account/bsdusers/',auth=('root', 'freenas'))
I tried to find something for AngularJS but stumbled only over excrutiating code, e.g. How do I get basic auth working in angularjs?
Is there anything available like this:
$http({
method: 'GET',
url: 'http://freenas.mydomain/api/v1.0/account/bsdusers/',
auth: ['username':'root', 'password':'pw']
}).then(function successCallback(response) {
// this callback will be called asynchronously
// when the response is available
}, function errorCallback(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
You need to create a function for encoding the user and password in Base64("username:password") and add Authorization header.
You can try encoding your username and password over here https://www.base64encode.org/ and see if it works. "root:freenas" being cm9vdDpmcmVlbmFz you can try the code below.
$http.defaults.headers.common['Authorization'] = 'Basic cm9vdDpmcmVlbmFz';
Once you get it working get implement the Base64 factory you posted ( How do I get basic auth working in angularjs? )
Hope it helps :)
You can try like this.
$http.defaults.headers.common = {"Access-Control-Request-Headers": "accept, origin, authorization"};
$http.defaults.headers.common['Authorization'] = 'Basic ' + Base64.encode('root' + ':' + 'freenas');
$http({
method: 'GET',
url: 'http://freenas.mydomain/api/v1.0/account/bsdusers/'
}).then(function successCallback(response) {
// this callback will be called asynchronously
// when the response is available
}, function errorCallback(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});

Categories