When a user clicks on the form, I send a http post request to database server. Which in turn sends post request back to user server.
My problem is that I can't post this database result recieved from database server to pug. I am not sure how to implement AJAX here.
I have tried sending the server http request itself, doesn't work. I have also tried to render the results to the pug file in the code as well, not luck!
script.js:
// analyze sentiment button
function analyzeSentiment() {
// get and post filter to the backend for sentiment score
let form = $("#searchSentiment-form");
let query = form.serialize();
console.log(query);
$.post('/', query);
}
pug file
form#searchSentiment-form(action='javascript:analyzeSentiment()', method='POST')
input(type="text" id="sentimentFilter" name="sentimentFilter" placeholder="Search a filter" required)
button(type="submit" id="sentiAnalysis" name="sentiAnalysis") ANALYZE
index.js
if(req.body.sentimentFilter) {
// 1) Convert Tweet into JSON
tweetJSON = { sentimentFilter: req.body.sentimentFilter };
console.log("Analyze this:", tweetJSON)
// 2) Send via HTTP post request to the ANALYSIS-SERVER
request({
url: "http://LoadBalancer-1284897978.us-west-2.elb.amazonaws.com",
method: "POST",
json: true, // <--Very important!!!
body: tweetJSON
}, function (error, response, body){
if(error) {
console.log("HTTP POST: Sending tweets to analysis-server Failed", error);
} else {
console.log("Success! Send sentiment request to analysis-server");
}
});
// receiving post result from server with results
} else if (req.body.score) {
let score = req.body.score;
res.render('index', {score:score});
let JSONscore = { userScore: score};
// 2) Send via HTTP post request to the LOAD-BALANCER FOR TWITTER-SERVER
request({
url: "http://52.26.216.28:3000",
method: "GET",
json: true,
body: JSONscore
}, function (error, response, body){
if(error) {
console.log("ERROR: COULD NOT SEND SCORE TO OWN USER-SERVER...", error);
} else {
console.log("SUCCESSFULY SENT SCORE TO OWN USER!..");
}
});
console.log("Received Score is ", req.body.score);
}
Your question states that you send the request to the database server which then sends the request to the node.js server, this is not correct. The user sends the request to the node.js server, which then creates a new request to the database server. When the response is received by the node.js server in the callback, at that time you want to send the final response back to the client.
If you want to do this in the client without reloading the template then you need to:
Only send JSON in the response,
Handle the response with jquery, and then
Update the DOM using jquery
First, only send JSON. None of the two callbacks are sending a response back to the client, that's a really big problem and it will look like your server is hanging.
This is how to return the response from the database to the client in your first callback. Expressjs has a shortcut method on the response (res) object that cleanly and quickly sends a JSON payload back properly:
function (error, response, body){
if(error) {
console.log("HTTP POST: Sending tweets to analysis-server Failed", error);
} else {
console.log("Success! Send sentiment request to analysis-server");
res.json(response);
}
}
Make sure you have that in all callbacks, then let's move on to the second issue in your code, handling the Ajax response.
Here is the relevant part of the sample code from the jquery $.post docs:
// Assign handlers immediately after making the request,
// and remember the jqxhr object for this request
var jqxhr = $.post( "example.php", function() {
alert( "success" );
})
.done(function() {
alert( "second success" );
})
.fail(function() {
alert( "error" );
});
You'll want to add the .done and .fail functions to your ajax code so you have something listening for that response from the server.
Finally, you'll probably want to show the user the result, so add a div to your pug:
form#searchSentiment-form(action='javascript:analyzeSentiment()', method='POST')
input(type="text" id="sentimentFilter" name="sentimentFilter" placeholder="Search a filter" required)
button(type="submit" id="sentiAnalysis" name="sentiAnalysis") ANALYZE
div#response
Then in your .done call you can display the results:
// analyze sentiment button
function analyzeSentiment() {
// get and post filter to the backend for sentiment score
let form = $("#searchSentiment-form");
let query = form.serialize();
console.log(query);
$.post('/', query).done(function(data){
console.log(data);
$('#results').html(data);
});
}
Related
I just started using Twilio services and there have been a few challenges. The phone number I send from the front end, I'm not able to make out if its actually being sent to the backend route. Whenever the GET request is done, it throws an error
": Required parameter "opts['to']" missing. twilio".
The first error is what I am getting now.
My form sends this to the backend:
case 2:
const Phoneno = {
phone:countryCode+PhoneNumber
};
axios.post('http://localhost:4000/app/otp', { data :Phoneno });
console.log(Phoneno)
my route for sending otp:
router.post('/otp', async(req, res)=>{
client.verify.v2.services("VERIFY_SERVICE_SID")
.verifications
.create({to:req.body.phone, channel: 'sms'})
.then((verification) => {
console.log(verification.status);
return callback(null);
}).catch((e) => {
console.log(e);
return callback(e);
});
});
In that console.log, I get this,
"{phone: '+91**********'}
phone: "+91**********"(my actual number)
[[Prototype]]: Object"
Also, when I hardcode the phone number, the route works perfectly fine. And when i send an HTTP request to the route, then also it sends an otp to my phone number. But is not able to recognize the data sent from the frontend.
My http request:
POST http://localhost:4000/app/otp
Content-Type: application/json
{
"Phoneno":"+9199********"
}
Please help me out. Thanks a lot for looking into it.
You are making a GET request to your back-end, but you are trying to get the data from the request body. GET requests do not have a body.
You're also trying to send the data by passing it in an object as the second argument to axios.get, but that argument should be a config object. To send the data in the query for the GET request it should be under the params key for that object:
const Phoneno = {
phone:countryCode+PhoneNumber
};
axios.get('http://localhost:4000/app/otp', { params: Phoneno });
Then on the back-end, read the data from the query, using req.query.phone:
router.get('/otp', async(req, res)=>{
client.verify.v2.services(VERIFY_SERVICE_SID)
.verifications
.create({to:req.query.phone, channel: 'sms'})
.then((verification) => {
console.log(verification.status);
return callback(null);
}).catch((e) => {
console.log(e);
return callback(e);
});
However, this might not be a good idea because an attacker can easily create a URL to your site and add the phone number in the query parameters and use it to perform SMS pumping.
I'd actually recommend you change your back-end to a POST request and send the data from the front end in a POST request with the data in the body of the request:
const Phoneno = {
phone:countryCode+PhoneNumber
};
axios.post('http://localhost:4000/app/otp', { data: Phoneno });
router.post('/otp', async(req, res)=>{
client.verify.v2.services(VERIFY_SERVICE_SID)
.verifications
.create({to:req.body.data.phone, channel: 'sms'})
.then((verification) => {
console.log(verification.status);
return callback(null);
}).catch((e) => {
console.log(e);
return callback(e);
});
I'm using Angular2 on the client side and a node-express server as my backend. The node-server works as an API-middleware and also as my authentication service. The user-requests must contain a valid JWT token to perform requests on the node-server.
All of my GET functions and other PUT functions are working properly. I wrote a new one, which just should delete an ID on a third-party API, doesn't.
Furthermore, my node-express server sends custom error messages at some points to the client. This comes to my problem, whenever I run my latest PUT-function, my server responds with "No token provided". This happens when the user isn't logged in on the client side.
As I said, all my other functions working. this.createAuthenticationHeaders(); is necessary to perform valid request on the server side. But it's implemented.
In other words, the authentication gets lost between client and server and I get my own error message: "No token provided".
Appointment-Detail.Component.ts
cancelAppointment() {
this.authService.getProfile().subscribe(profile => {
this.username = profile.user.username; // Set username
this.email = profile.user.email; // Set e-mail
if (profile.user.email) {
this.apiService.cancelUserAppointment(this.id).subscribe(data => {
console.log(this.id);
if (!data.success) {
this.messageClass = 'alert alert-danger'; // Set error bootstrap class
this.message = data.message; // Set error message
} else {
this.messageClass = 'alert alert-success'; // Set success bootstrap class
this.message = data.message; // Set success message
// After two seconds, navigate back to blog page
}
});
}
});
}
API Service
cancelUserAppointment(id) {
this.createAuthenticationHeaders();
console.log('API SERVICE ' + id);
return this.http
.put(this.domain + 'api/appointments/' + id + '/cancel', this.options)
.map(res => res.json());
}
An API Service functions that works
getCertificatesByUser(email) {
this.createAuthenticationHeaders();
return this.http
.get(this.domain + 'api/user/' + email + '/certificates', this.options)
.map(res => res.json());
}
Server route to the third party API
router.put('/appointments/:id/cancel', (req, res) => {
console.log('hi');
var id = req.params.id;
const url = process.env.acuityUri + '/appointments/' + id + '/cancel';
console.log(id);
});
Authentication middleware
router.use((req, res, next) => {
const token = req.headers['authorization']; // Create token found in headers
// Check if token was found in headers
if (!token) {
res.json({
success: false,
message: 'No token provided'
}); // Return error
} else {
// Verify the token is valid
jwt.verify(token, config.secret, (err, decoded) => {
// Check if error is expired or invalid
if (err) {
res.json({
success: false,
message: 'Token invalid: ' + err
}); // Return error for token validation
} else {
req.decoded = decoded; // Create global variable to use in any request beyond
next(); // Exit middleware
}
});
}
});
Without doing too much of a deep dive into your auth headers, I see a pretty glaring issue that I think may be the cause of your troubles.
HTTP REST verbs carry different "intents", the intent we specifically care about in this case is wether or not your request should have a body.
GET requests do not carry a body with them.
PUT requests do carry a body.
Because of this, angular's HttpClient request methods (http.get, http.post, etc.) have different method signatures.
To cut to the chase, http.put's method signature accepts 3 parameters: url, body, and options, whereas http.get's method signature only accepts 2: url and options.
If you look at your example, for http.put you are providing this.httpOptions as the second parameter instead of the third, so Angular is packaging up your options object as the PUT request body. This is why you have a working example and a non-working example; the working example is a GET!
The solution? Simply put something else as the request body in the second parameter and shift this.options down to the third parameter slot. If you don't care what it is, just use the empty object: {}.
So your request should look like this:
return this.http
.put(this.domain + 'api/appointments/' + id + '/cancel', {}, this.options)
At the very least, this should send whatever is in this.options to the server correctly. Now wether what's in this.options is correct or not is another story.
Example PUT call from Angular's docs: https://angular.io/guide/http#making-a-put-request
I have 4 inputs and button which takes all data from them and sends to my PostreSQL database through axios.post() request. Not clearly understand how .then() is working. So, here is my button code which just calls this.addNewPainting function:
<button onClick={ this.addNewPainting }>Submit</button>
Here is my addNewPainting function:
addNewPainting() {
axios.post(`http://localhost:333/api/add`, {
title: this.state.titleInput,
year: this.state.yearInput,
size: this.state.yearInput,
location: this.state.locationInput
})
.then(function(response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
}
Before this project, I used to put response.data to the array with this.setState, but now I have the database and I'm just stuck.
Here is my controller function:
add_painting: (req, res, next) => {
const db = req.app.get('db');
const { title, year, size, location } = req.body;
console.log(title, year, size, location);
db.add_painting([ title, year, size, location ])
.then( () => res.status(200).send() )
.then( () => res.status(500).send() );
}
And the endpoint:
app.post('/api/add', paintings_controller.add_painting);
For future reading (becase you requested it): I'm not an expert using promises, but it works similarly like the AJAX requests.
When you make a request to the server (GET, POST, PUT, etcetera), you're waiting for a response from this (a collection of data, a message, a succesful/unsuccesful POST/PUT/DELETE, etcetera). Depending of the response, you'll code the expected events (error, success, complete, etcetera).
In this case you're using axios, a new way to do AJAX requests. The equivalent way of the error/success/complete/... events is the then() function. Using this approach you can perform operations that makes new tasks or simply print a response message (in your case) of the server.
From MDN:
The then() method returns a Promise. It takes up to two arguments:
callback functions for the success and failure cases of the Promise.
Let's suppose that we have this snippet of code in AJAX:
$.ajax(
{
url : yourURL,
type : 'POST',
data : yourData,
datatype : 'json',
success : function(data) {
yourSuccessFunction(data);
},
error : function(jqXHR, textStatus, errorThrown) {
yourErrorFunction();
}
});
Using axios, you'll code something like this:
axios.post('/user', {
YourData: yourData
}).then(() => { this.yourSuccessFunction() })
}).catch(() => { this.yourErrorFunction() });
I just found the error. I was making a request to PORT 333 in my axios.post(), but the server was working on port 3333.
I'm a bit new to all this (including Javascript callbacks and ES6). I'm using NodeJS + Express + MongoDB.
I'm calling an Ajax function to update an item and the success Ajax call is never done.
Here is my Ajax call (called from React)
editBug : function(bug){
console.log('about to edit bug with these values',bug);
$.ajax({
url:'/api/bugs',
method: 'PUT',
data:bug
})
.done((jqxhr) => {
console.log('succcess while editing the bug');
this.setState({successVisible : true});
})
.fail((jqxhr) => {
console.log('error : ' + jqxhr);
})
},
Here is my API function:
app.put('/api/bugs',function(req,res){
//console.log('req',req);
console.log('query string : ',req.query);
console.log('query params : ',req.params);
console.log('query body: ',req.body);
let id = new ObjectID(req.body._id);
req.body._id = new ObjectID(req.body._id);
db.collection('bugs').replaceOne(
{_id:id},
req.body,
function(err,result){
assert.equal(err,null);
console.log('Successfull replace!');
res.status(200);
}
);
});
The Successfull replace! log is correctly shown on the server side.
The about to edit bug with these values is correctly shown on the front side. But the succcess while editing the bug log is not shown on front end and it seems .done call is never executed.
The problem is that you are not sending any response back to the browser on node side. Try the following snippet and you should be good to go
Also, I'd like to point out that you should handle the errors. While updating the bugs if something goes wrong, the best practice would be to inform the browser with the 500 status code indicating that the intended action failed. I've added this aspect in the snipped below
app.put('/api/bugs', function(req, res) {
//console.log('req',req);
console.log('query string : ', req.query);
console.log('query params : ', req.params);
console.log('query body: ', req.body);
let id = new ObjectID(req.body._id);
req.body._id = new ObjectID(req.body._id);
db.collection('bugs').replaceOne({
_id: id
},
req.body,
function(err, result) {
if (err) {
console.log('Failed replace');
res.status(500).end(); // <- We set the response status code and end the request
} else {
assert.equal(err, null);
console.log('Successfull replace!');
res.status(200).end(); // <- We set the response status code and end the request
}
}
);
});
Don't you need to end your response object on the Node.js side?
Try adding res.end(); or any kind of response to your response object.
Also, you can use chrome's (or any other browser's) network tab to actually see how your AJAX requests end up, to see if they hang or finish.
I'm allowing my site to accept incoming calls with python and javascript. I want to make sure that whoever answers the call has their username logged correctly by Twilio. As posted in their docs you need to create a capability token to accept incoming calls:
capability.allow_client_outgoing(application_sid)
capability.allow_client_incoming("jenny")
There could be up to 20 different users on the site at once that could answer the call so I would want the "jenny" string to be replaced to allow a dynamic username based upon who is logged in.
I'm using Django as my framework and generate the token through a view that request the username from request.user.username
def token(request):
capability = TwilioCapability(TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN)
capability.allow_client_outgoing(APP_ID)
capability.allow_client_incoming(request.user.username)
token = capability.generate()
data = json.dumps({'token': token})
return HttpResponse(data, content_type='application/json')
My Twilio Voice URL gets directed to this function. If it does not see a phone_number parameter then it can assume it is a incoming call. I somehow want to send the 'call_rep' parameter through this post which will match up the usernames to allow the incoming call with the correct user information:
#twilio_view
def make_call(request):
resp = Response()
if 'phone_number' in request.POST:
phone_number = request.POST['phone_number']
resp.say("Making the call now")
resp.dial(number=phone_number, callerId=TWILIO_PHONE_NUMBER)
else:
resp.say("Incoming call")
with resp.dial(callerId=TWILIO_PHONE_NUMBER) as r:
r.client(request.POST['call_rep'])
return resp
Is there somewhere in my JavaScript I need to put the call_rep's username in?
Twilio.Device.setup(token);
Twilio.Device.ready(function (device) {
});
Twilio.Device.error(function (error) {
console.log(error);
$("#log").text("Error: " + error.message);
});
Twilio.Device.offline(function(device) {
// Called on network connection lost.
});
Twilio.Device.connect(function (conn) {
console.log("Successfully established call");
});
Twilio.Device.disconnect(function (conn) {
// Called for all disconnections
console.log('DISCONNECT: ' + conn.status);
});
/* Listen for incoming connections */
Twilio.Device.incoming(function (conn) {
connection = conn
connection.accept()
});
For outgoing calls I can pass extra parameters no problems. How do I do this with incoming?
Twilio.Device.connect({
call_rep: '{{ request.user.username }}',
phone_number: phone_number
});