I have created a rest api in nodejs
i have the get request function like this:
server.js
const search = 'example' //user input search variable changes based on input from html file
app.get('/api/getData', (req, res) => {
var url = 'externalapiurl' + search // so you can see that my requests depends on the users input search variable
request(url, function (err, response, body) {
var data = 'json loaded data'
res.send(data)
});
});
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
})
i also have a html file and another script.js that has a search button where the user can type in a string and that string i want it to be the 'const search' in the server.js and then after that to return it back to the html file just to test it.
index.html script.js server.js script.js index.html
----search----- ----> puts string into const search ----> send back to html and display as text
this might help with the html search button
server.js
const searchbtn = document.getElementsByClassName("search-btn")[0];
searchbtn.addEventListener("click", getAns);
function getAns() {
var search = document.getElementById("input").value;
//what do i do now?
}
how do i call the get function to my api from my script.js file, taking subreddit variable with it into server.js and then sending it back to html file.
Related
I was given an assignment in class for making a basic ReSTFul Web Application, and received a sample to create mine off of, but only 2 of the 4 routes worked and I'm very new so I can't figure out why the other functions aren't working. The code looks like:
//setup
var express = require('express');
var app = express();
var fs = require("fs");
//run the server
var server = app.listen(8081, function () {
var host = server.address().address
var port = server.address().port
console.log("Example app listening at http://%s:%s", host, port)
})
//http://localhost:8081
//general route
//data for existing users located in "users.json"
//here is the refer
app.get("/", function(req,res){
var msg=""
msg += "<center><h1> This is the default page </h1></center>"
msg += " use the following <br />"
msg += " http://localhost:8081/listUsers <br />"
msg += " http://localhost:8081/addUser <br />"
msg += " http://localhost:8081/deleteUser <br />"
msg += " http://localhost:8081/(Put id# here) <br />"
res.send(msg);
});
//To find a list of users
app.get('/listUsers', function (req, res) {
fs.readFile( __dirname + "/" + "users.json", 'utf8', function (err, data) {
console.log( data );
res.end( data );
});
})
//To add a user to the list
var user = {
"user4" : {
"name" : "mohit",
"password" : "password4",
"profession" : "teacher",
"id": 4
}
}
app.post('/addUser', function (req, res) {
fs.readFile( __dirname + "/" + "users.json", 'utf8', function (err, data) {
//First read existing users.
data = JSON.parse( data );
data["user4"] = user["user4"];
console.log( data );
res.end( JSON.stringify(data));
});
})
//to show details of user by id#
app.get('/:id', function (req, res) {
// First read existing users.
fs.readFile( __dirname + "/" + "users.json", 'utf8', function (err, data) {
var users = JSON.parse( data );
var user = users["user" + req.params.id]
console.log( user );
res.end( JSON.stringify(user));
});
})
var id = 2;
//to delete a user
app.delete('/deleteUser', function (req, res) {
// First read existing users.
fs.readFile( __dirname + "/" + "users.json", 'utf8', function (err, data) {
data = JSON.parse( data );
delete data["user" + 2];
console.log( data );
res.end( JSON.stringify(data));
});
})
The functions for listing users and specifying users work, but the addUser and deleteUser say "unspecified," leading me to believe that the ( data ) part may not be properly specified. But I don't know specifically how I would specify a function.
Okay, there are a few issues going on here. First of all, it helps to walk through your code line by line to see what its doing, so you can try to figure out what you're missing:
You're reading the contents of users.json as a string using fs.readFile, which gets put in the variable "data" in your callback function.
You're converting "data" from a string to an object using JSON.parse. So far, so good.
You're setting the property "user4" on data, which should now be a list of users. This may or may not be correct depending on what the structure is for your users - if its an array, this code won't work. If its an object where each key is the username, you'll be fine here. Also, potential problem - you're setting the same key on the data object every time this request is made. You will continually overwrite the "user4" property each time, which will act as an update instead of an add. There's no way to determine what this code should be without see what you're POSTing into this API.
You're setting data["user4"] equal to user["user4"], or more specifically the value of the "user4" property of user. First issue - user is not defined anywhere. If this was data that was sent in the body of the POST, you'll want to read it from the body - probably something like (again, dependent on the format of data you're sending during your POST):
data["user4"] = req.body.user;
You're logging the full list of users. No problem here, good for visibility while debugging.
You're sending back the list of users you read from the file, plus the single user you just added.
There's a step missing here - you never saved the updated list of users in any way. Some type of data should be returned to the user, but the next time you call add or get (or any other method), the user you just defined won't be present, since it was never added to users.json. Here's a great post on how to write a string to a file: Writing files in Node.js
It will probably end up looking like this:
fs.readFile( __dirname + "/" + "users.json", 'utf8', function (err, data) {
//First read existing users.
data = JSON.parse( data );
data["user4"] = user["user4"];
console.log( data );
// Convert your updated user object into a JSON string
var strData = JSON.stringify(data);
// Write the updated JSON string out to the file
fs.writeFile(__dirname + "/" + "users.json", strData, function(err) {
if(err) {
return console.log(err);
}
console.log("The file was saved!");
});
res.end( JSON.stringify(data));
});
This covers the addUser endpoint, but you'll need to introduce similar changes for your deleteUser endpoint. If you're having trouble past this point, I'd recommend adding the contents of users.json to your question, as well as adding more detail on what you get back when you make the call into addUser and deleteUser (you can view the response body in Chrome dev tools -> Network tab).
I'm working on a SPA website with node.js, jQuery, mongoose and MongoDB for a shopping website.
The ajax requests and responses work perfectly when starting from the index.html file. So for example begining on http://localhost:3000 and someone clicks on a link called 'products' I send an ajax request to the the server and the server sends the necessary product information back asynchronously which lead to http://localhost:3000/products. But the problem is that if someone types http://localhost:3000/products directly in the search bar it will show the json representation of the products.
This is my code:
script.js
function redirect (link) {
$.ajax({
type: 'GET',
url: 'http://localhost:3000/' + link,
contentType: 'application/json',
data: {
link
},
success: function (res) {
let container = $('#contentToSwap');
container.html('');
res.products.forEach(function (products_) {
...
});
}
});
}
app.js
var Product = require('./models/product');
var mongoose = require('mongoose');
var bodyParser = require('body-parser');
var path = require('path');
var express = require('express');
var app = express();
mongoose.connect('mongodb://localhost:27017/shopping');
var PORT = process.env.PORT || 3000;
app.use(express.static(path.join(__dirname, 'public')));
app.use(bodyParser.json());
app.get('*', function(req, res) {
Product.find(function(err, docs) {
let productChunks = [];
let chunksize = 4;
let display = [];
for (var i = 0; i < docs.length; i++) {
if (docs[i].productType == req.query.link) display.push(docs[i]);
}
for (var i = 0; i < display.length; i += chunksize) {
productChunks.push(display.slice(i, i + chunksize));
}
res.send({ products: productChunks });
});
});
app.listen(PORT, function () {
console.log('Listening on port ' + PORT);
});
So I need some sort of frontend routing if the user doesn't start at the index.html file. I know that I could write my own router to route the urls correctly and that I could route all requests back to the index.html like
app.get('*', function(req, res) {
res.sendFile(__dirname + '/public/index.html');
});
But then I cannot load all the necessary product information from the server when someone clicks a link. So I'm a little bit confused on hwo to tackle this issue. Any help is appreciated
This is usually achieved by separating api routes from normal ones by adding specific url prefixes such as /api for all routes that return json data. What you can do is to specify /api/whatever-you-want, make it the target for your ajax call and place it above app.get('*' ....
Since routes and middleware functions are resolved top to bottom, it will be matched by your ajax call only, leaving the /products unaffected.
answer to question -- Is it possible to redirect user from /api/products to /product if the request wasn't generated by ajax?
Yes, it is possible by adding request query parameter to ajax call which will not be present on normal call and then check those on the server side and decided what to do if it (that specific query parameter) is missing or not.
Let's assume some client side JS that generates ajax call.
fetch('/api/products?api=true')
.then((data) => data.json())
.then((json) => console.log(json));
Notice the request url - /api/products?api=true
Now assume a normal call from html file.
products
These two calls differ in that api query parameter (ajax call has it, the other one doesn't).
And for the server side part of the task -- request query parameters object can be accessed via query property on request object (req.query).
app.get('/api/products', (req, res) => {
if (!req.query.api) {
// if get request doesn't contain api param. then
// handle it accordingly, e.g. do redirect
return res.redirect('/products');
}
// request comming from ajax call, send JSON data back
res.json({ randomStuff: 'abcd' });
});
I am using node.js to launch a serve so that my html can communicate with R code. But I am facing a problem on node.js. In my html page, I have a browse selection button, user can use it to choose the data file they want to read into html and node.js will pass the file name to R, so R code will read data from the selected data file and then run the analytics model. But as i only have very basic knowledge of Node.js, so currently, r code would run only when I open the followling link "localhost:3000/vis/rio". So my question is how to make node.js run the R code in background automatically when the data file has been selected. Thank you very much for your help in advance.
Here are my codes:
Javascript-(sending the file name to node.js):
var dataset,availableTags;
function handleFileSelect(evt) {
var file = evt.target.files[0];
$.ajax({ //getting the file name and update to node.js
type:'post',
url:"/getFileName",
data:{filename:file.name}
});
Papa.parse(file, { //papa is a library I used to read csv file
header: true,
dynamicTyping: true,
complete: function(results) {
dataset=results.data;
}
});
}
$(document).ready(function(){
$("#csv-file").change(handleFileSelect);
});
Node.js script:
serve.js:
var express=require('express');
var path = require('path');
var vis = require('./routes/vis');
var index = require('./routes/index');
var bodyParser=require('body-parser');
var app=express();
require('./routes/main')(app);
app.get('/vis/rio',vis.rio); **//this is a package used to get connection with Rserve**
app.set('views',__dirname + '/views');
app.set('view engine', 'ejs');
app.engine('html', require('ejs').renderFile);
app.use(express.static(path.join(__dirname, 'public')));
app.use(bodyParser.urlencoded());
app.post("/getFileName",index.getFileName); **//this is the script to get the file name, it is from index.js**
var server=app.listen(3000,function(){
console.log("Express is running on port 3000");
});
index.js // this is the js file for getting file name
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res) {
res.render('index', { title: 'Express' });
});
getFileName=function (req,res){
global.filename=req.body.filename; **//this is the global variable which stores the file name**
res.send('true');
};
module.exports = {router:router,getFileName:getFileName};
vis.js // this is the file used to connect with Rserve and pass the name to R code
var rio = require("rio");
var arg={};
exports.rio = function(req, res){
arg={names:[global.filename]};
console.log(arg);
options = {
entryPoint:"nameoffile",
data: arg,
host : "127.0.0.1",
port : 6311,
callback: function (err, val) {
if (!err) {
console.log("RETURN:"+val);
return res.send({'success':true,'res':val});
} else {
console.log("ERROR:Rserve call failed")
return res.send({'success':false});
}
},
}
rio.enableDebug(true);
rio.sourceAndEval(__dirname + "/Rcode/test.R",options);
};
It looks like you aren't calling out to /vis/rio at any point when you make the call out to your server.
You'll either need to make a second call on the client side to /vis/rio or if you want to use that section, you can import/require the module in index.js and include it in getFileName and just call out to the function there before you return the file. I'm not super familiar with rio, but I don't see any access point in your code to that function.
Edit: If I understand what you're trying to do correctly, you can always make a second request (to /vis/rio) in the success callback of your first ajax call.
I am trying to write the binary body of a request to a file and failing. The file is created on server but I am unable to open it. I am getting 'Fatal error: Not a png' on Ubuntu. Here is how I am making the request:
curl --request POST --data-binary "#abc.png" 192.168.1.38:8080
And here is how I am trying to save it with the file. The first snippet is a middleware for appending all the data together and second one is the request handler:
Middleware:
app.use(function(req, res, next) {
req.rawBody = '';
req.setEncoding('utf-8');
req.on('data', function(chunk) {
req.rawBody += chunk;
});
req.on('end', function() {
next();
});
});
Handler:
exports.save_image = function (req, res) {
fs.writeFile("./1.png", req.rawBody, function(err) {
if(err) {
console.log(err);
} else {
console.log("The file was saved!");
}
});
res.writeHead(200);
res.end('OK\n');
};
Here's some info which might help. In the middleware, if I log the length of rawBody, it looks to be correct. I am really stuck at how to correctly save the file. All I need is a nudge in the right direction.
Here is a complete express app that works. I hit it with curl --data-binary #photo.jpg localhost:9200 and it works fine.
var app = require("express")();
var fs = require("fs");
app.post("/", function (req, res) {
var outStream = fs.createWriteStream("/tmp/upload.jpg");
req.pipe(outStream);
res.send();
});
app.listen(9200);
I would just pipe the request straight to the filesystem. As to your actual problem, my first guess is req.setEncoding('utf-8'); as utf-8 is for text data not binary data.
For fix your code: I'm with #Peter Lyons, that the error is probably the req.setEncoding('utf-8'); line.
I know the following don't ask your question directly, but proposes an alternative to it by using req.files functionality provided by Express.js, which you are using.
if (req.files.photo && req.files.photo.name) {
// Get the temporary location of the file.
var tmp_path = req.files.photo.path;
// set where the file should actually exists - in this case it is in the "images" directory.
var target_path = './public/profile/' + req.files.photo.name;
// Move the file from the temporary location to the intended location.
fs.rename(tmp_path, target_path, function (error) {
if (!error) {
/*
* Remove old photo from fs.
* You can remove the following if you want to.
*/
fs.unlink('./public/profile/' + old_photo, function () {
if (error) {
callback_parallel(error);
}
else {
callback_parallel(null);
}
});
}
else {
callback_parallel(error);
}
});
}
I am using Node.js and express to make a web chat application. I have a question about routing.
My route is:
app.get("/", function( req, res ) {
res.sendfile( __dirname + "/index.html" );
});
And as far as I know it means all clients should go to http://www.example.com/index.html page to access the chat. ( maybe, not sure )
Is it possible to have a pattern URL like this:
app.get("/*", function( req, res ) {
res.sendfile( __dirname + "/*" );
});
so that any user can access to chat on any URL
In short: Something like facebook chat. which is accessible in all pages.
thanks in advance
Is it possible to have a pattern URL like this:
Yeah, Express supports exactly the route you listed. The documentation refers to it as an "unnamed wild-card."
// GET /foo -> (200) "foo"
// GET /baz/qux -> (200) "baz/qux"
app.get('/*', function (req, res) {
res.send(req.params[0]);
});
Though, for your example, Express/Connect includes a static() middleware for serving files by combining the URL path to a base directory:
app.use(express.static(__dirname));
Something like facebook chat. which is accessible in all pages.
This wouldn't necessarily have much of a relation to routing. Your application may need a route to gather a list of contacts or other persisted data, but the actual "chat" will be managed separately.
In general, it would depend on including common content in each page -- perhaps via a "layout" or "inheritance" if you're using views/templates -- to display the form for inputting message and an area to display chat history. Also, a fair amount of the "work" for the chat will have to be done client-side.
A quick example would be to serve the same file for multiple URLs:
var app = require('express')();
var server = require('http').createServer(app);
var io = require('socket.io').listen(server);
app.get('/*', function (req, res) {
res.sendfile(__dirname + '/chat.html');
});
var chat = io
.of('/chat') // namespace
.on('connection', function (socket) {
socket.on('message', function (data) {
chat.emit('message', data);
});
});
server.listen(3000);
And, in that file:
<div id="chat-log"></div>
<form id="chat-send">
<input name="message">
<input type="submit" value="Send">
</form>
<script src="/socket.io/socket.io.js"></script>
<script>
var chatForm = document.getElementById('chat-send');
var chatLog = document.getElementById('chat-log');
var chatSocket = io.connect('/chat');
chatSocket.on('message', function (data) {
chatLog
.appendChild(document.createElement('div'))
.appendChild(document.createTextNode(data.text));
});
chatForm.onsubmit = function () {
chatSocket.emit('message', {
text: chatForm.message.value
});
chatForm.message.value = '';
chatForm.message.focus();
return false;
};
</script>
Then, from any address (GET /, GET /foo, GET /bar/baz/qux), you can access chat.
You're probably going to want to use a url param like this:
app.get("/:chatter",function(req,res){
console.log("the chatter is",req.param('chatter'));
res.sendfile( __dirname + "/index.html" );
...
});