Cannot GET the requested API in express.js - mysql

Here is my express app code
app.get('/books',function(req,res){
var {keyword} =req.query;
connection.query('SELECT * from books', function (error, results, fields) {
if (error) throw error;
for(let result of results){
if(result.title === keyword){
res.send(result);
}
}
});
});
and the url i am requesting is http://......../books/keyword=intro. Where intro is the user input.
What i am trying to achieve here, is from an input in HTML, to take that info and send it to my API, so it can query my DB and get what i want.
But i get a 404 error, so i guess my api is configured incorrectly.
Is there a better way to implement what i am doing?
Is the keyword=intro even the correct way to query my db.
My html is like this
<!DOCTYPE html>
</head>
<body>
<div id="data">
<input type="button" id="button" value="Click"/>
<input type="text" id="search" >
</div>
<div id="search">
</div>
<script>
document.getElementById('button').addEventListener('click',getUserInput);
function getUserInput(event){
var userInput = document.getElementById("search").value;
if(userInput !== ""){
httpGetAsync(userInput);
}
}
function httpGetAsync(searchTerm){
var theUrl = 'books?keyword=' + searchTerm;
const xhttp = new XMLHttpRequest();
xhttp.open("GET", theUrl, true); // true for asynchronous
xhttp.send(null);
xhttp.onreadystatechange = processRequest;
function processRequest() {
if (xhttp.readyState == XMLHttpRequest.DONE);
var result = JSON.parse(xhttp.response);
console.log(result);
}}
</script>
</body>

In httpGetAsync function replace
var theUrl = 'books/keyword=' + searchTerm;
with:
var theUrl = window.location + '/books/keyword=' + searchTerm;

This answer is more of a comment unless it's acceptable. The statement that I want to write is too long for a comment.
In regards to my answer is that a valid way to write your prepared statement model? How I write my SQL models are like this and it works fine. Are you receiving any errors from your SQL syntax?
Notice the brackets after the ?.
selectBooks: function(data, callback) {
let keyword = "%" + req.query + "%";
connection.query("SELECT * FROM books WHERE title LIKE ?", [keyword], callback);
}

Related

Google sheet not being updated by setValues

I am writing a large file uploader for Google Drive and when I tried to implement writing some data to a Google Sheet I ran into a brick wall, for whatever reason I could not get it to ever write or even give a error as to why. I decided to start a whole new project and made it as simple as possible so all it does is grab similar data to what I will be grabbing and write it, but still no luck.
I am not super familiar with the Google Apps processes or the syntax of using them so I am probably just doing something really stupid.
Old code removed
I have tried removing some variables like file and email in case they needed to be written differently and changing how the form is passed to the function but the best I ever got was a "Cannot read Null" error when I passed it a form that didn't exist.
UPDATE:
Once I had it working I tried to slip it into the main script I am using (Which is basically a copy of this but now its not working, I am realizing this may be over my head unfortunately cause no matter what I try its doing the same, runs and uploads the file fine, but does not update the form.
Google Scripts:
function doGet(e) {
return HtmlService.createHtmlOutputFromFile('Form.html');
}
function getAuth() {
return { accessToken: ScriptApp.getOAuthToken(), folderId: "1sFxs3Ga4xWFCgIXRUnQzCAAp_iRX-wdj" };
}
function setDescription({fileId, description}) {
DriveApp.getFileById(fileId).setDescription(description);
}
function updateform(formObject) {
try {
var ss = SpreadsheetApp.openById('1iCTNZ6RERnes1Y-ocfXzPN3jviwdIEK_dBKQ4LIu5KI');
var sheet = ss.getSheets()[0];
sheet.appendRow([myFile.getName(), myFile.getUrl(), formObject.myName], "If This Shows Up It Worked");
} catch (error) {
return error.toString();
}
}
HTML:
<form id="myForm" align="center" onsubmit="updatesheet(This)">
<input type="text" name="myName" placeholder="Your name..">
<input type="file" name="myFile">
<input type="submit" value="Submit Form" onclick="run(); return false;">
</form>
<div id="progress"></div>
<div id="output"></div>
<script src="https://cdn.jsdelivr.net/gh/tanaikech/ResumableUploadForGoogleDrive_js#master/resumableupload_js.min.js"></script>
<script>
function onSuccess() {
var div = document.getElementById('output');
div.innerHTML = '<a href="Spreadsheet Updated</a>';
}
function onFailure(error) {
alert(error.message);
}
function updatesheet(form) {
google.script.run.withSuccessHandler(onSuccess).withFailureHandler(onFailure).updateform(form);
}
function run() {
google.script.run.withSuccessHandler(accessToken => ResumableUploadForGoogleDrive(accessToken)).getAuth();
}
function ResumableUploadForGoogleDrive({accessToken, folderId}) {
const myName = document.getElementsByName("myName")[0].value;
const file = document.getElementsByName("myFile")[0].files[0];
if (!file) return;
let fr = new FileReader();
fr.fileName = file.name;
fr.fileSize = file.size;
fr.fileType = file.type;
fr.readAsArrayBuffer(file);
fr.onload = e => {
var id = "p";
var div = document.createElement("div");
div.id = id;
document.getElementById("progress").appendChild(div);
document.getElementById(id).innerHTML = "Initializing.";
const f = e.target;
const resource = { fileName: f.fileName, fileSize: f.fileSize, fileType: f.fileType, fileBuffer: f.result, accessToken, folderId };
const ru = new ResumableUploadToGoogleDrive();
ru.Do(resource, function (res, err) {
if (err) {
console.log(err);
return;
}
console.log(res);
let msg = "";
if (res.status == "Uploading") {
msg = Math.round((res.progressNumber.current / res.progressNumber.end) * 100) + "% (" + f.fileName + ")";
} else {
msg = res.status + " (" + f.fileName + ")";
}
if (res.status == "Done") {
google.script.run.withSuccessHandler(_ => {
document.getElementById('myForm').style.display = 'none';
document.getElementById('p').style.display = 'none';
document.getElementById('output').innerHTML = "All information submitted, thank you!";
}).setDescription({fileId: res.result.id, description: "Uploaded by " + myName});
}
document.getElementById(id).innerText = msg;
});
}
}
</script>
Several things about your updated code.
First it should be this not This.
Second you have onsubmit and onclick events for the same form. I believe the onclick is suppressing the submit event. Remove onclick entirely.
Third you use a try catch block in updateform so withFailureHandler will never execute. Instead the error message or null is returned to the success handler onSuccess(error).
Forth, I use a paragraph <p> instead of an anchor <a>. The href is malformed in your anchor.
Last, run() can be executed in updatesheet(form). Note run() is asynchronous which means it doesn't wait for google.script.run to finish before executing.
I can simply tell you that all the alerts are displayed and the execution log shows updateform did execute. So this code works for me.
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<form id="myForm" align="center" onsubmit="updatesheet(this)">
<input type="text" name="myName" placeholder="Your name..">
<input type="text" name="myFile">
<input type="submit" value="Submit Form">
</form>
<div id="progress"></div>
<div id="output"></div>
<script>
function onSuccess(error) {
if( error ) {
alert(err);
return;
}
alert("onSuccess");
var div = document.getElementById('output');
div.innerHTML = "<p>Spreadsheet Updated</p>";
}
function run() {
alert("run");
}
function updatesheet(form) {
alert("updatesheet");
google.script.run.withSuccessHandler(onSuccess).updateform(form);
run();
}
</script>
</body>
</html>

Can't Integrate HTML's DOM in NodeJS/ExpressJS

Good day, hoomans! I badly need your help!
My question: Is there any way (in NodeJS/ExpressJS) to dynamically alter an element such as adding new li upon POST request like after clicking the submit button (without using jsdom though)?
I am developing a very simple application which should allow a client (student) to keep track of the lessons in his/her every class, monitor his/her grades, etc., with simple dynamic and real-time features. I am using Node.js EXPRESS, mySQL and AngularJS for this.
I created a feature where a student can search for a class then receive a list of results real-time, which basically means I want to dynamically add li elements upon request without reloading the page or redirecting the client to another page.
The process is: (1) the student types in the name of a class, (2) pass the textfield's value upon request (post), (3) use the value as key for database search, (4) then return the data extracted from the database by populating the ul element.
The database thing works. It is able to retrieve data from the database using the value entered in the textfield. However, when I add the code to dynamically add li element, I receive a runtime error every time the request is made. The code for this is found inside routes/grades.js.
The error I get is:
throw err; // Rethrow non-MySQL errors
^
TypeError: req.body.getElementById is not a function
and that is caused by this code block
var ul = req.body.getElementById("search");
var li = req.body.createElement("li");
li.appendChild(req.body.createTextNode(reqObj["className"]));
I believe createElement and createTextNode will also cause the same error message.
I think this can be solved with jsdom but when I tried to install it through npm, I only received lots of errors so I gave up. Besides, I believe there is a simpler solution to this that I don't know yet.
Here are the primary files for the functionality I mentioned above.
views/grades.ejs
<!DOCTYPE html>
<html ng-app="ClassSaber">
<head>
<title><%= title %></title>
<link rel='stylesheet' href='/stylesheets/style.css' />
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
<script src="javascripts/app.js" type="text/javascript"></script>
</head>
<body ng-controller="classController">
<% include template/header2.ejs %>
<div class="lessons" id="homebranding_top">
<section>
<h1>Grades</h1>
<hr>
</section>
<section>
<p>
Keeping track of your progress eh? That's great! Search your class and we'll show your grade.
</p>
</section>
<form>
<section id="class_search">
<input type="text" id="search" ng-model="data.className" placeholder="Enter your class here...">
<input type="submit" value="Search" ng-click="classFun()">
<ul id="class_list">
<li ng-repeat="item in list | filter: data.className">
{{item.Class_Name}}
</li>
</ul>
</section>
</form>
</div>
</body>
</html>
routes/grades.js
var express = require('express');
var router = express.Router();
var path = require('path');
/* GET lessons page. */
router.get('/grades', function(req, res, next) {
res.render('grades', { title: 'Class Saber | Grades' });
});
module.exports = router;
//search class in the database
router.post('/grades', function(req, res, next){
try{
var reqObj = req.body;
console.log("Request Object: " + reqObj["className"]);
req.getConnection(function(err, conn){
if(err){
console.error('SQL Connection error: ', err);
return next(err);
}
else{
var insertSql = "SELECT Class_Name FROM classes WHERE Class_Name LIKE ?";
var insertValues = [
'%' + reqObj["className"] + '%'
];
var query = conn.query(insertSql, insertValues, function(err, result){
if(err){
console.error('SQL error: ', err);
return next(err);
}
var ul = req.body.getElementById("search");
var li = req.body.createElement("li");
li.appendChild(req.body.createTextNode(reqObj["className"]));
});
}
});
}
catch(ex){
console.err("Internal error: " + ex);
return next(ex);
}
});
public/javascripts/app.js
var app = angular.module('ClassSaber', []);
app.controller('classController', function($scope, $http){
$scope.data = {};
$scope.list = [
{Class_Name: 'Math 101'},
{Class_Name: 'Physics 101'},
{Class_Name: 'Major Elective: Quantum Mechanics'}
];
$scope.classFun = function(){
console.log('Client triggered class search function...');
$http({
url: 'http://localhost:3000/grades',
method: 'POST',
data: $scope.data
}).then(function (httpResponse){
console.log('response', httpResponse);
})
}
});
req.body contains the body of the request (the data you pass with your $http call) , and not the body element of the DOM. You cannot access client side elements (like DOM) from a server side environment (like nodejs) and the other way round. If you want to make changes to the DOM then return the instructions what has to be changed with your response, and to the corresponding changes in the browser.
I do not use angular so I can't tell you directly how to do it. But in general it would be something like that:
var query = conn.query(insertSql, insertValues, function(err, result) {
if (err) {
console.error('SQL error: ', err);
return next(err);
}
// response with a list of action to be applied
res.send([{
action : 'append-to-dom',
info : {
/* all informations you need for this e.g. reqObj["className"] */
}
}]);
});
In your client side code you would check for the actions you have to do:
$http({
url: 'http://localhost:3000/grades',
method: 'POST',
data: $scope.data
}).then(function(httpResponse) {
// check the content of your response if it contains actions
/*
var ul = req.body.getElementById("search");
var li = req.body.createElement("li");
li.appendChild(req.body.createTextNode( .. the data from your response ... ))
*/
})
How you would structure the response is up to you and depends on the environment.
Angular might already have a specific pattern how to do this, but as I said, I do not use angular so I can't tell you.
The concept that t.niese gave me was really helpful and I was able to fix the problem.
Here are the changes I made as per the suggested answer:
In my routes
var query = conn.query(insertSql, insertValues, function(err, result){
if(err){
console.error('SQL error: ', err);
return next(err);
}
var class_array = [];
for(var i=0; i<result.length; i++){
class_array.push(result[i]);
}
console.log(class_array.valueOf());
res.send([{
info: class_array.valueOf()
}])
});
and in my client-side code
$scope.classFun = function(){
console.log('Client triggered class search function...');
$http({
url: 'http://localhost:3000/grades',
method: 'POST',
data: $scope.data
}).then(function (httpResponse){
console.log('response', httpResponse);
var tbody = document.getElementById("class_list_data");
while(tbody.firstElementChild){
tbody.removeChild(tbody.firstChild);
}
for(var i=0; i<httpResponse.data.length; i++){
for(var j=0; j<httpResponse.data[i].info.length; j++){
var tr = document.createElement("tr");
var td = document.createElement("td");
td.appendChild(document.createTextNode(httpResponse.data[i].info[j].Class_Name.toString()));
tr.appendChild(td);
tbody.appendChild(tr);
}
}
})
}
Also, I made little changes with my template. Instead of list, I use table.
<div id="homebranding_middle">
<table id="class_list">
<thead>
<th>CLASS DESCRIPTION</th>
<th>SCHEDULE</th>
<th>CLASSROOM ASSIGNMENT</th>
<th>INSTRUCTOR</th>
</thead>
<tbody id="class_list_data">
<tr id="class_list_row" ng-repeat="item in list | filter: {Class_Name: data.className}">
<td>{{item.Class_Name}}</td>
<td>{{item.Class_Code}}</td>
<td>{{item.Class_Room}}</td>
<td>{{item.Class_Instructor}}</td>
<dynamic></dynamic>
</tr>
</tbody>
</table>
</div>
All in all, my /grades page can actually do something now. I get status code 200 and all retrieved data from the DB could be played out.
localhost:3000/grades
Going pretty well.
Many thanks to t.niese! Cheers!

Parse TCP JSON Stream and emit each object via Socket.io

I am working with a data feed that sends a JSON stream over a TCP socket and I'm using node.js/socket.io to emit the stream to a browser client.
Everything is working except I need each JSON object to emitted as a separate message from the socket.io server. In the client the messages are received like this:
//Message 1:
{"type":"TYPE_1","odds":[{"eventId":"foo","odds":[{"oddId":foo,"oddType":"LIVE","source":"foo"}]}]}
//Message 2:
{"type":"TYPE_2","odds":[{"eventId":"foo","odds":[{"oddId":foo,"oddType":"LIVE","source":"foo"}]}]}
{"type":"TYPE_3","odds":[{"eventId":"foo","odds":[{"oddId":foo,"oddType":"LIVE","source":"foo"}]}]}
//Message 3:
{"type":"TYPE_4","odds":[{"eventId":"foo","od
//Message 4:
ds":[{"oddId":foo,"oddType":"LIVE","source":"foo"}]}]}
The data feed docs state: "All messages sending to your application will form a JSON stream (no delimiter between messages), so you may need a decoder that support JSON stream."
So the stream is strictly correct but I need each object as separate message.
I have looked at https://www.npmjs.com/package/JSONStream and others but am very new to nodejs and socketio and am not sure how to implement them in to the server.
Have also read How can I parse the first JSON object on a stream in JS, nodejs JSON.parse(data_from_TCP_socket), http://www.sebastianseilund.com/json-socket-sending-json-over-tcp-in-node.js-using-sockets.
I think it's something to do with buffer chunk lengths and them being too big so the messages get split but that could be wrong! I'm guessing I need a delimiter check that balances brackets but not sure how to go about it or if the right approach.
My Server Script:
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var net = require('net');
var port = 8992; // Datafeed port
var host = '127.0.0.1'; // Datafeed IP address
//Whenever someone connects this gets executed
io.on('connection', function(socket){
console.log('A user connected to me the server');
//Whenever someone disconnects this piece of code executed
socket.on('disconnect', function () {
console.log('A user disconnected');
});
});
//Create a TCP socket to read data from datafeed
var socket = net.createConnection(port, host);
socket.on('error', function(error) {
console.log("Error Connecting");
});
socket.on('connect', function(connect) {
console.log('connection established');
socket.write('{"type":"SUBSCRIBE"}');
});
socket.on('data', function(data) {
//console.log('DATA ' + socket.remoteAddress + ': ' + data);
var data = data.toString();
io.sockets.emit('event', JSON.stringify(data));
});
http.listen(3000, function(){
console.log('listening on *:3000');
});
My Client:
<!DOCTYPE html>
<html>
<head><title>Hello world</title></head>
<script src="https://cdn.socket.io/socket.io-1.4.5.js"></script>
<script src="http://code.jquery.com/jquery-1.11.1.js"></script>
<script>
var socket = io.connect('http://localhost:3000');
</script>
<body>
<form action="">
<input id="m" autocomplete="off" /><button>Send</button>
</form>
<ul id="messages"></ul>
<script>
socket.on('event', function(data){
var t = JSON.parse(data.toString('utf8'));
$('#messages').prepend($('<li>').text(t));
console.log('Got event from Server:', t);
});
</script>
</body>
</html>
Any help or guidance would be amazing as really struggling with this.
A common delimiter to use is a newline character (\n). If you have that appended to your JSON messages it will be very easy to parse the messages. For example:
var sockBuf = '';
socket.setEncoding('utf8');
socket.on('data', function(data) {
sockBuf += data;
var i;
var l = 0;
while ((i = sockBuf.indexOf('\n', l)) !== -1) {
io.sockets.emit('event', sockBuf.slice(l, i));
l = i + 1;
}
if (l)
sockBuf = sockBuf.slice(l);
});
or a more efficient, but slightly less simple solution:
var sockBuf = '';
socket.setEncoding('utf8');
socket.on('data', function(data) {
var i = data.indexOf('\n');
if (i === -1) {
sockBuf += data;
return;
}
io.sockets.emit('event', sockBuf + data.slice(0, i));
var l = i + 1;
while ((i = data.indexOf('\n', l)) !== -1) {
io.sockets.emit('event', data.slice(l, i));
l = i + 1;
}
sockBuf = data.slice(l);
});

AJAX request on Node.js server

I am unable to make an AJAX request from my .html page to my node.js server for a JSON file. I've been reading on AJAX requests, but all I am able to make out is how to display the servers responseText.
It would be great if you could help me out, it would be even better if you could link me some tutorials on this, anyway this is what I've got at this moment:
server.js
var express = require('express');
var fs = require('fs');
var app = express();
app.get('/test', function(req, res){
var arr = new Array();
var rd = readline.createInterface({
input: fs.createReadStream('info.json'),
output: process.stdout,
terminal: false
});
rd.on('line', function(line) {
arr.push(line);
}).on('close', function(){
res.send(arr);
});
});
app.get('/', function(req, res) {
fs.readFile('test2.html',function (err, data){
res.writeHead(200, {'Content-Type': 'text/html','Content-Length':data.length});
res.write(data);
res.end();
});
});
app.listen(process.env.PORT || 3000);
test.html
<html>
<head>
<script>
function sendAjax(){
var xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = function(){
if(xmlHttp.readyState==4 && xmlHttp.status == 200){
console.log(xmlHttp.responseText);
}
document.getElementById("myDiv").innerHTML=xmlHttp.responseText;
}
xmlHttp.open("GET", "/test", true);
xmlHttp.send();
}
</script>
</head>
<body>
<input type="submit" onClick="sendAjax()" value="SendAjax" />
<div id="myDiv"><h2>Let AJAX change this text</h2></div>
</body>
</html>
I know this may not look like much, I've been struggling with this, and the book I have (Node.js in Action) doesn't help me alot. But as I said, what I want is to display the .json info in the browser. Thx for reading
If I understand right, you may replace
document.getElementById("myDiv").innerHTML=xmlHttp.responseText;
with
var parsed = JSON.parse(xmlHttp.responseText);
var html = '';
for (var i = 0; i < parsed.length; i++) {
html += '<div>' + parsed[i] + '</div>';
}
document.getElementById("myDiv").innerHTML = html;
You may also try to replace
res.send(arr);
with
res.json(arr);
Update
Or maybe you just forgot to write this line in the beginning of server.js:
var readline = require('readline');

Parse JSON from twitter using JQUERY

I want to search a tweet from twitter, it will depend on text or hashtag. Then Show it on <div id="result"> . but i get confused because my code doesn't show the tweet.
Here is my code to read JSON from twitter search :
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript">
$(document).ready(function()
{
$('#btn').click(function()
{
$.getJSON("http://search.twitter.com/search.json?q="+$('#search').val(),function(data)
{
$.each(data.results, function(i,data){
var from = data.from_user;
var tw_content = data.text;
$('#result').append("<p>User : "+from+"<br>Tweet : "+tw_content+"</p>");
});
});
});
});
</script>
<input type="text" id="search"/><input type="button" id="btn" value="cari">
<div id="result">
</div>
And while I run this, nothing happen. anyone can help me ?
I would do something like below:
$(document).ready(function() {
// Declare variables to hold twitter API url and user name
var twitter_api_url = 'http://search.twitter.com/search.json';
var twitter_user = 'behudinnystrom';
// Enable caching
$.ajaxSetup({ cache: true });
// Send JSON request
// The returned JSON object will have a property called "results" where we find
// a list of the tweets matching our request query
$.getJSON(
twitter_api_url + '?callback=?&rpp=5&q=from:' + twitter_user,
function(data) {
$.each(data.results, function(i, tweet) {
// Uncomment line below to show tweet data in Fire Bug console
// Very helpful to find out what is available in the tweet objects
//console.log(tweet);
// Before we continue we check that we got data
if(tweet.text !== undefined) {
// Calculate how many hours ago was the tweet posted
var date_tweet = new Date(tweet.created_at);
var date_now = new Date();
var date_diff = date_now - date_tweet;
var hours = Math.round(date_diff/(1000*60*60));
// Build the html string for the current tweet
var tweet_html = '<div class="tweet_text">';
tweet_html += '<a href="http://www.twitter.com/';
tweet_html += twitter_user + '/status/' + tweet.id + '">';
tweet_html += tweet.text + '<\/a><\/div>';
tweet_html += '<div class="tweet_hours">' + hours;
tweet_html += ' hours ago<\/div>';
// Append html string to tweet_container div
$('#tweet_container').append(tweet_html);
}
});
}
);
});
DEMONSTRATION
You should use jsonp to get the result, because jsonp provides a method to request data from a server in a different domain
Check this FIDDLE
I use $.ajax function with dataType: jsonp here
Check this and this for JSONP