deleting a row from db using node, mysql, express and pure js - javascript

I am creating a simple app using node, express, mysql.
I am trying to create a route with which I can delete a row from my db, I wrote a pure javascript xhr.
when I test it I keep getting the following error message
POST http://localhost:3000/article/22 404 (Not Found)
this is what I have:
main.js
function handleDeleteClick(e, userId) {
e.preventDefault(); // Prevent default behaviour of this event (eg: submitting the form
// Perform the AJAX request to delete this user
var target = e.target;
var id = target.getAttribute('data-id');
var page = '/article/' + id;
var parameters = 'delete=true';
var xmlhttp = new XMLHttpRequest();
if (confirm('Are you sure you want to delete this?') == true) {
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
// Request completed
}
}
xmlhttp.open("POST", page, true);
xmlhttp.send(parameters);
}
}
and the route app.js
app.delete('/article/:id', function(req, res) {
con.query(`DELETE FROM posts WHERE posts.id = ${req.params.id}`,
function(err, result, fields) {
if (err) {
console.log(err);
} else {
console.log("deleted Record: " + result.affectedRows);
res.redirect('/')
}
});
});
what am I missing?
help is very much appreciated!
thanks.

change POST to DELETE in your main.js-file:
xmlhttp.open("DELETE", page, true);
You are getting this 404 NOT FOUND error because route POST /article/:id does not exist (it's DELETE /article/:id).
Note: Your DELETE-query is vulnerable for SQL-injection attacks escaping-query-values
Escape query values:
con.query('DELETE FROM posts WHERE posts.id = ?', [req.params.id]);
Note: Actually, correct http status for this case is 405 METHOD NOT ALLOWED, but express by default doesn't distinguish those cases

app.delete expects to recieve a DELETE request.
xmlhttp.open("POST", page, true); is sending a POST request.
Change the second argument to "DELETE" to make a DELETE request.

you have a delete route in your server, so if you want to send a request to that route, you should pass "DELETE" parameter to xmlhttp.
so simply change
xmlhttp.open("POST", page, true);
to
xmlhttp.open("DELETE", page, true);
also, this answer may help you understand using XMLHttpRequest better
Do not insert params directly into your database query
As others said, you are vulnerable to SQLInjection attacks. you should evaluate params first instead of just inserting it directly into your SQL query

Related

what callback function should i use in an XMLHttpRequest to render the response?

After a user does something on a page, I use ajax to send some data to my Node.js Express server. That server then does this:
router.post('/', function(req, res){
//user authentication then, inside that callback
res.redirect('/dashboard');
}
dashboard.js then does this:
router.get('/', function(req, res, next) {
console.log("dashboard"); //<--This code is running
res.render('index',{title:"You are logged in"});
}
Now the front end is doing this:
function httpGetAsync(theUrl, callback){
let user = document.getElementById('username').value;
let pass = document.getElementById('password').value;
let data = {
"username": user,
"password": pass
}
var xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = function() {
if (xmlHttp.readyState == 4 && xmlHttp.status == 200)
callback(xmlHttp.responseText);
}
xmlHttp.open("POST", theUrl, true); // true for asynchronous
xmlHttp.setRequestHeader("Content-Type", "application/json; charset=utf-8");
var dataAsJson = JSON.stringify(data);
xmlHttp.send(dataAsJson);
}
Instead of seeing my nice "You are logged in" page, index.html logs to my browser's console. This is obviously because my onclick listener does this:
onclick='httpGetAsync("/createUser", console.log)'
Instead of console.log (which is obviously the wrong thing here), what should I be calling?
How do I get this res.render('index',{title:"You are logged in"}) in dashboard.js to actually render?
This is a lot like ExpressJS : res.redirect() not working as expected?, but that question does not include the portion that includes their front end code which is where I think the problem lies. And the last comment there reads: "No, never figured it out. I ended up building my app differently, with the login part in a modal, instead of another page... Very frustrating".
As XHR are meant to send and revive response you are receiving html page as response with status 301 or 302, the possible solution is to send the redirect url as response instead
router.post('/', function(req, res){
//user authentication then, inside that callback
res.send('/dashboard');
}
and on receiving this response you can redirect to response url on callback
function redirect(res){
window.location = res;
}
onclick='httpGetAsync("/createUser", redirect)'

How to use HTTP method POST without changing URL?

It is common to use HTTP method POST to send a form.
For example, if the form action is "/login",
the request would send to server, and the URL would be like "index/login".
However, I want to implement two things.
Use HTTP method POST without "form". I want to send my own message.
And without changing the URL after the AJAX
Thanks.
Update: reply to DvS
The studies I have researched use libraries like jQuery or AngularJS.
But I want to implement by pure javascript.(like XMLHTTPRequest)
And I don't know how to use "NOT A FORM" in AJAX.
Maybe there's some references I can study?
Thanks again.
Try jQuery's AJAX call
http://api.jquery.com/jquery.ajax/
$("#id_of_button_to_submit").click(function(){
$.ajax({url: "/login", success: function(result){
//do things with your result
$("#div1").html(result);
}});
});
I found answer in "You might need jQuery"
var request = new XMLHttpRequest();
request.open('GET', '/my/url', true);
request.onload = function() {
if (request.status >= 200 && request.status < 400) {
// Success!
var resp = request.responseText;
} else {
// We reached our target server, but it returned an error
}
};
request.onerror = function() {
// There was a connection error of some sort
};
request.send();
The server side is implemented by Node.js and express
var express = require('express');
var app = express();
app.use(express.static(__dirname + '/public'));
app.post('/newindex', function(req, res){
console.log("req received!");
res.send('This is POST METHOD');
})
app.listen(8888);
Old post but I ran into this problem and it got to my search results, and I suspect that the cause is the same.
Basically don't use a form action and submit button.
Then call the function using a regular button, or whatever else you want.
Seems like default form behavior for the submit button but without an action is HTTP GET to the current page, which runs and of course mucks everything up.

Ajax Post to a different domain url , redirect to another url

I am supposed to call a third party vendor - Cybersource using their silent order post. The problem is that I have an accordion page which has 3 panes, Account creation, Service address and billing (on third pane).
I am trying make an ajax call from [http://mydomain/billing][1] TO [http://cybersource/silentorderpost/pay][1].
In the post parameters I am setting response url = [http://mydomain/billing][1] this is where CS will send the response back.
When the Ajax post goes from my website to CS website, I do not get a callback but the Cybersource post the response back to my website [http://mydomain/billing][1] and this reloads my whole accordion page which I am trying to avoid. I understand that During an Ajax call, the Ajax expects a response on the same domain as "Called webservice", i.e. my Ajax post expects that Cybersource will post the response on something like [http://cybersource/response][1]. However, CS posts or redirects the response to my website and this is probably the reason, I never get my callback. When the response is posted my whole accordion page reloads and this causes all sorts of issues.
My Code:
function myFunction() {
//document.getElementById("myForm1").submit();
var http= new XMLHttpRequest();
var url = "https://testsecureacceptance.cybersource.com/silent/pay";
var params = document.getElementById("queryStr");
http.open("POST", url, true);
http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
http.send(params);
//Send the proper header information along with the request
http.onreadystatechange = function() {//IT NEVER COMES BACK TO THIS SECTION
if(http.readyState == 4) {
alert(http.responseText);
console.log("I came back");
}
}
}
</script>
USING JQUERY:
function myFunction() {
//document.getElementById("myForm1").submit();
var http= new XMLHttpRequest();
var url = "https://testsecureacceptance.cybersource.com/silent/pay";
var params = document.getElementById("queryStr");
var jqxhr = $.post( url, function() {
alert( "success" );
})
.done(function() {
alert( "second success" );
})
.fail(function() {
alert( "error" );
})
.always(function() {
alert( "finished" );
});
// Set another completion function for the request above
jqxhr.always(function() {
alert( "second finished" );
});
}
Any solutions?
var xhr = new XMLHttpRequest();
xhr.open('POST',url,true);
var params = document.getElementById("queryStr");
// you need to call this method:
xhr.send(params);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
//return stuff
} else {
//return stuff
}
}
just like i wrote in my comment, you also need to send your request to the server via xmlhttprequestObject.send() before the readystate can change.
greetings
I found a way out. On my form I added an iframe and now when I get a post response from CS, my page does not reload, instead the response is updated in the iframe.
<form action="https://testsecureacceptance.cybersource.com/silent/pay" method ="post" target="myIframe"> ..... </form>
<iframe src="" name="myIframe"></iframe>
I got the same issue when I integrate cyber source silent post order. I resolved it with form with hidden input fields to create the signature and invisible iframe as the target for my form.
Few things you need to take care while integrating cyber source silent post
1. Make sure you are passing all required fields
2.Generate unique application number and uuid otherwise cyber source will consider it as duplicate request
3.create the signature to make sure input fields are not tampered
4.Dont use ajax to submit the request, in this case the call might ge success but cyber source will not call your customer post back URL that you configured for response.

difference between youtube's request and mine

i want to make a script that makes every video's comment section look like the ones that still have the old kind.
for example, videos on this channel:https://www.youtube.com/user/TheMysteryofGF/videos
in Firebug, in the Net tab, i noticed the comment JSON file's URL it is requested from is different.
i tried to run a code on the youtube watch page which would request the file the same way, but it doesnt work, and in firebug it says it was forbidden.
the URL is the same, they are both POST, and i cant figure out what is different. i can even resend the original request in firebug and it works... so anyway, here is a code i tried on a video with "1vptNpkysBQ" video url.
var getJSON = function(url, successHandler, errorHandler) {
var xhr = typeof XMLHttpRequest != 'undefined'
? new XMLHttpRequest()
: new ActiveXObject('Microsoft.XMLHTTP');
xhr.open('post', url, true);
xhr.onreadystatechange = function() {
var status;
var data;
// https://xhr.spec.whatwg.org/#dom-xmlhttprequest-readystate
if (xhr.readyState == 4) { // `DONE`
status = xhr.status;
if (status == 200) {
data = JSON.parse(xhr.responseText);
successHandler && successHandler(data);
} else {
errorHandler && errorHandler(status);
}
}
};
xhr.send();
};
getJSON('https://www.youtube.com/watch_fragments_ajax?v=1vptNpkysBQ&tr=time&frags=comments&spf=load', function(data) {
alert('Your public IP address is: ' + data);
}, function(status) {
alert('Something went wrong.');
});
You are using Ajax to get data. Ajax has 1 restriction: You can only get data from your own server. When you try to get data from another server/domain, you get a "Access-Control-Allow-Origin" error.
Any time you put http:// (or https://) in the url, you get this error.
You'll have to do it the Youtube way.
That's why they made the javascript API. Here is (the principal of) how it works. You can link javascript files from other servers, with the < script > tag
So if you could find a javascript file that starts with
var my_videos = ['foo', 'bar', 'hello', 'world'];
then you can use var my_videos anywhere in your script. This can be used both for functions and for data. So the server puts this (dynamically generated) script somewhere, on a specific url. You, the client website can use it.
If you want to really understand it, you should try building your own API; you'll learn a lot.
Secondary thing: Use GET.
POST means the client adds data to the server (example: post a comment, upload a file, ...). GET means you send some kind of ID to the server, then the server returns its own data to the client.
So what you are doing here, is pure GET.

Load image and remove when authentification is required

I am grabbing some (random) images from a search machine and display them to the users. The problem is: It may happen that some images require a http authentification (username/password). I dont want to have those images... they should be removed without displaying the popup where you can enter the username and password.
Actually I am using simple jquery methods to display my images.
var displayNode = ....
....
var m_img = $("<img />", {src : "...."});
m_img.bind('error', function (e) {
$(this).remove();
});
displayNode.append(m_img);
Now I load the image directly and if an error occurs it will be removed. But.. when server sends back a HTTP (Basic) Authentification flag this is of course not an error. Hence there is an input prompt. When I click on "cancel" the propmt closes, jquery treats this as an error and removes the image.
So.. what is the best way to check if there is authentification and if not display it to the user?
You can make a HEAD request that only returns headers, then check the headers for the authentication header before actually making the request:
The HEAD method is identical to GET except that the server MUST NOT return a message-body in the response. The metainformation contained in the HTTP headers in response to a HEAD request SHOULD be identical to the information sent in response to a GET request. This method can be used for obtaining metainformation about the entity implied by the request without transferring the entity-body itself.
http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
You would use this method to first check the headers, then if OK, get the image. You'll have to test it with your protected resource, I'm not sure what the browser will do when requesting just the HEAD and I don't have a local protected resource to test against (CORS got me on the online resources I was trying to test against). Fiddle:
var basicAuthProtectedURL = 'http://fiddle.jshell.net';
var xhr = new XMLHttpRequest();
xhr.open("HEAD", basicAuthProtectedURL, true);
xhr.onload = function (e) {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
console.log(xhr.getAllResponseHeaders()); //all headers
console.log(xhr.getResponseHeader('Content-Type')); //just the one you want
if (xhr.getResponseHeader('WWW-Authenticate')) {
console.log('I got the authentication header, skip this request.');
} else {
console.log('no header, resource unsecure');
}
} else {
console.error(xhr.statusText);
}
}
};
xhr.onerror = function (e) {
console.error(xhr.statusText);
};
xhr.send(null);
http://jsfiddle.net/5z5bnwgz/
Post back how it goes!

Categories