node.js: The POST method in my RESTAPI does not work - javascript

I start learning Node.js and Express.js and I'm trying to create a simple API to list data from JSON file (using the GET method) and add a new user using the POST method.
the GET method works fine but the POST method does not work
when I request http://127.0.0.1:8080/listusers the API sends all users in a JSON file.
when I request http://127.0.0.1:8080/adduser the API has to add new User Info and send the new data back to the browser.
NOTE: I read all the questions on Stackoverflow about this problem but
non of them help me so I have to ask again.
the problem is when I request http://127.0.0.1:8080/adduser I get the following error
Cannot GET /adduser
here is the server.js:
var express = require('express');
var app = express();
var fs = require('fs');
var user = {
"user4" : {
"name" : "mounir",
"password" : "password4",
"profession" : "teacher",
"id": 4
}
};
app.post('/adduser', function (req, res) {
// First read existing users.
fs.readFile( __dirname + "/" + "users.json", 'utf8', function (err, data) {
data = JSON.parse( data );
data["user4"] = user["user4"];
console.log( data );
res.end(JSON.stringify(data) );
});
});
app.get('/listusers', function (req, res) {
fs.readFile( __dirname + "/" + "users.json", 'utf8', function (err, data) {
console.log(data);
res.end(data);
});
});
var server = app.listen(8080, function () {
var host = server.address().address;
var port = server.address().port;
console.log("listening at http://%s:%s", "0.0.0.0", port)
});

The answer is in the error. Cannot GET /adduser. Keyword GET! If you are making a post request, be sure you include the appropriate headers and that you are making a POST request, with a body, and not a GET request. For instance if you are using fetch:
const myInit = {
method: 'POST',
headers: myHeaders,
body: {
...
}
};
fetch("http://127.0.0.1:8080/adduser", myInit)
.then(res => {
...
});

Related

Connect node app and server + post image to server

I have a very basic question about a node application, and a question about HTTP requests. It's the first time I create a node app with server, and I just can't seem to get the different components to work together.
This is my server.js
var express = require('express');
var multer = require('multer');
const request = require('request');
const upload = multer({dest: __dirname + '/uploads/images'});
const app = express();
const PORT = 3000;
app.use(express.static('public'));
app.post('/upload', upload.single('photo'), (req, res) => {
if(req.file) {
res.json(req.file);
}
else throw 'error';
});
app.listen(PORT, () => {
console.log('Listening at ' + PORT );
});
Then I have a file app.js with a motion-detection system. Every time motion is detected, a picture is taken. This all works fine.
Then the picture should be sent to the server. This is what I can't figure out.
I created a function toServer() that should post the detected data to the server
const request = require('request');
function toServer(data) {
const formData = {
// Pass data via Buffers
my_buffer: data,
// Pass optional meta-data with an 'options' object with style: {value: DATA, options: OPTIONS}
// Use case: for some types of streams, you'll need to provide "file"-related information manually.
// See the `form-data` README for more information about options: https://github.com/form-data/form-data
};
request.post({url:'http://localhost:3000/upload', formData: formData}, function optionalCallback(err, httpResponse, body) {
if (err) {
return console.error('Upload failed:', err);
}
console.log('Upload successful! Server responded with:', body);
});
};
Problem 1: when running the server.js on localhost:3000, it doesn't find any of the scripts loaded in index.html nor my app.js.
Problem 2: when running the index.html on live-server, all scripts are found, but i get the error "request is not defined".
I am pretty sure there is some basic node setup thing I'm missing.
The solution for toServer() might be more complicated.
Thanks for your time,
Mustard Shaper
Problem 1:
this could happen because you have not specified to render your index.html.
for example:
res.render('index')
if it's not because of the single quotes in upload.single('photo') try double quotes.
Another possible error could be that you are missing a default display engine setting.
an example: https://www.npmjs.com/package/hbs
Problem 2:
it may be because you are missing the header
var request = require('request');
request.post({
headers: {'content-type' : 'application/x-www-form-urlencoded'},
url: 'http://localhost',
body: "example"
}, function(error, response, body){
console.log(body);
});
See more at https://expressjs.com/

Connect Microsoft Azure Machine Learning Studio API using Vue Axios or using Express Server?

Currently I'm using the below code to connect with web service.
I need to connect to the Microsoft Azure Machine Learning Studio Api by using either Vue Axios or Express. Can someone help me.
var http = require("http");
var https = require("https");
var querystring = require("querystring");
var fs = require('fs');
function getPred(data) {
console.log('===getPred()===');
var dataString = JSON.stringify(data)
var host = 'ussouthcentral.services.azureml.net'
var path = '/workspaces/fda91d2e52b74ee2ae68b1aac4dba8b9/services/1b2f5e6f99574756a8fde751def19a0a/execute?api-version=2.0&details=true'
var method = 'POST'
var api_key = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=='
var headers = {'Content-Type':'application/json', 'Authorization':'Bearer ' + api_key};
var options = {
host: host,
port: 443,
path: path,
method: 'POST',
headers: headers
};
console.log('data: ' + data);
console.log('method: ' + method);
console.log('api_key: ' + api_key);
console.log('headers: ' + headers);
console.log('options: ' + options);
var reqPost = https.request(options, function (res) {
console.log('===reqPost()===');
console.log('StatusCode: ', res.statusCode);
console.log('headers: ', res.headers);
res.on('data', function(d) {
process.stdout.write(d);
});
});
// Would need more parsing out of prediction from the result
reqPost.write(dataString);
reqPost.end();
reqPost.on('error', function(e){
console.error(e);
});
}
//Could build feature inputs from web form or RDMS. This is the new data that needs to be passed to the web service.
function buildFeatureInput(){
console.log('===performRequest()===');
var data = {
"Inputs": {
"input1": {
"ColumnNames": ["gl10", "roc20", "uo", "ppo", "ppos", "macd", "macds", "sstok", "sstod", "pmo", "pmos", "wmpr"],
"Values": [ [ "0", "-1.3351", "50.2268", "-0.2693", "-0.2831", "-5.5310", "-5.8120", "61.9220", "45.3998", "-0.0653", "-0.0659", "-30.3005" ], ]
},
},
"GlobalParameters": {}
}
getPred(data);
}
function send404Reponse(response) {
response.writeHead(404, {"Context-Type": "text/plain"});
response.write("Error 404: Page not Found!");
response.end();
}
function onRequest(request, response) {
if(request.method == 'GET' && request.url == '/' ){
response.writeHead(200, {"Context-Type": "text/plain"});
fs.createReadStream("./index.html").pipe(response);
}else {
send404Reponse(response);
}
}
http.createServer(onRequest).listen(8050);
console.log("Server is now running on port 8050");
buildFeatureInput();
But can i do this by using axios call or express server.
can anyone help me with proper syntax if i can do this using either vue axios or express server.
It sounds like you want to use express in server with axios in Vue front page instead of Node http server with https client in server-side.
To replace Node http with express is very easy, it is as below.
const express = require('express')
const path = require('path');
const app = express()
const port = 8050
app.use(express.static(path.join(__dirname, '.')))
app.get('/', (req, res) => res.sendFile('index.html'))
app.use(function (req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err)
})
app.use(function (err, req, res, next) {
if(err.status == 404) {
res.status(404).send("Error 404: Page not Found!")
}
res.status(500).send("Error 500: Internal Error!")
})
app.listen(port, () => console.log("Server is now running on port 8050"))
But consider for the security of the api-key value for calling Azure Machine Learning Studio API, I recommended not to call the API with axios in Vue front page and still make the calling works in the server-side by express, as below.
const axios = require('axios');
var host = 'ussouthcentral.services.azureml.net'
var path = '/workspaces/fda91d2e52b74ee2ae68b1aac4dba8b9/services/1b2f5e6f99574756a8fde751def19a0a/execute?api-version=2.0&details=true'
var api_key = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=='
const pred = axios.create({
baseURL: 'https://'+host,
timeout: 1000,
headers: {'Content-Type':'application/json', 'Authorization':'Bearer ' + api_key}
});
app.post('/mls-api', (req, res) => pred.post(path, JSON.stringify(req.body)).then(function(resp) {
resp.pipe(res)
}))
Then, you can call /mls-api url from Vue front page with the data value below.
var data = {
"Inputs": {
"input1": {
"ColumnNames": ["gl10", "roc20", "uo", "ppo", "ppos", "macd", "macds", "sstok", "sstod", "pmo", "pmos", "wmpr"],
"Values": [ [ "0", "-1.3351", "50.2268", "-0.2693", "-0.2831", "-5.5310", "-5.8120", "61.9220", "45.3998", "-0.0653", "-0.0659", "-30.3005" ], ]
},
},
"GlobalParameters": {}
}
axios.post('/mls-api', data)
.then(function (response) {
console.log(response);
})

Node proxy server modify response after query in database

I am troubling with nodejs proxy server modified(write) response.
I want to achieve auto login for one site via node proxy server and for that i have to query in database then i can modified response but it seems req ended before req.write and getting Error: write after end
Below is my implementation so far.
var express = require('express');
var proxy = require('http-proxy-middleware');
var options = {
target: 'http://example.com/', // target host
changeOrigin: true,
onProxyReq: function onProxyReq(proxyReq, req, res) {
var _write = res.write;
var body = "";
proxyReq.on('data', function(data) {
data = data.toString('utf-8');
body += data;
});
res.write = function (data) {
try{
//I have database query here instead of setTimeout
setTimeout(function(){
/* Modified response here and write */
_write.call(res, data); //can't write because req already end
},3000);
} catch (err) {
console.log('err',err);
}
}
}
}
// create the proxy (without context)
var exampleProxy = proxy(options);
// mount `exampleProxy` in web server
var app = express();
app.use('/', exampleProxy);
app.listen(8080);
Can anyone guide me how to achieve this ?

NodeJS - 'Error: Invalid URI "/"'

I'm using request-promise to request two JSON data files which exist locally in my local project directory folder.
ie:
However, I am getting a 500 internal server error, when trying to pass the data to the view and my node console outputs 'Error: Invalid URI "/"',
Please see below:
server.js
let express = require('express');
let app = express();
let path = require('path');
const rp = require("request-promise");
//STORE PATH for local JSON files on variables
let guest = require('./public/data/Companies');
let hotel = require('./public/data/Guests');
app.set("port", process.env.PORT || 5000);
//GET JSON
//Question: Is it okay to pass uri:guest
app.get('/data', function(req, res) {
Promise.all([rp({uri: guest, json: true}), rp({uri: hotel, json: true})]).then(function([hotels, guests]) {
//res.json({hotels, guests});
res.send({hotels, guests});
console.log(hotels, guests);
}).catch(function(err) {
console.log(err);
res.status(500).end();
});
});
//CATCHALL
app.get("/*", function(req,res){
let file = req.params[0] || "/views/index.html";
res.sendFile(path.join(__dirname, "/public/", file));
});
//SET PORT
app.listen(app.get("port"), function(){
console.log("Listening on port: " , app.get("port"));
});
then on client.js:
$(function() {
$.ajax({
type: "GET",
url: "/data",
success: function (res) {
console.log(res);
}
});
});
Why do you use request to get the data? Why don't you use the filesystem module from Node.js (fs) to get the data? When you call rp(), you should pass an absolute URI and not a local path.
To use it in your code, you need to "promisify" the readFile function:
let readFileAsAPromise = function(filename){
return new Promise(function(resolve, reject) {
fs.readFile(filename, (data, err) => {
if(err) reject(err);
resolve(data)
})
})
}
You can then you Promise.all.
Why aren't you simply returning the variables?
I mean:
app.get('/data', function(req, res) {
res.send({hotels, guests});
});

Node js use variable outside main function and set order of functions

Introduction
I have a three functions, each one would feed data into then next. The objective is first to retrieve data then authenticate a API key then finally using the generated API key and data retrieve from the first function post to the API in the third function.
Order
First function function to retrieve data from a post.
Second function gets API key requested from a API.
Third function posts data to the API.
Needed functionality
I need the variables retried in the first function and the API key generated in the second function to be available for use in the third function.
Problems and questions
emailUser is not being found to use in the third function
api_key is not being found in the third function
also the functions need to run in order first, second then third
This all works if I was to insert the data manual but when input the variables it dose not work, I understand that it is because the variables being within the function but how do I fix this, also how do I set the order of the functions ?
Full code
// Grab the packages needs and sets server
//---------------------------------- Grab the packages we need and set variables --------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------------------
var express = require('express');
var request = require('request');
var nodePardot = require('node-pardot');
var bodyParser = require('body-parser');
var app = express();
var port = process.env.PORT || 8080;
// Varibles to use in second and third function
var password = 'password';
var userkey = '6767712';
var emailAdmin = 'admin#admin.com';
// start the server
app.listen(port);
app.use(bodyParser.json()); // support json encoded bodies
app.use(bodyParser.urlencoded({extended: true})); // support encoded bodies
console.log('Server started! At http://localhost:' + port);
// First Retrieve posted data from Front-End
//---------------------------------- Retrieve posted data from Front-End -----------------------------------------------------
// ---------------------------------------------------------------------------------------------------------------------------
// POST http://localhost:8080/api/index
app.post('/api/data', function (req, res) {
console.log(req.body);
var Fname = req.body.fname;
var Lname = req.body.lname;
var emailUser = req.body.email;
res.send(Fname + ' ' + Lname + ' ' + emailUser);
});
app.get('/', function (req, res) {
res.send('hello world, Nothing to see here...');
});
// Second Get Posted variables
//---------------------------------- Now authenticate the api and get api_key -----------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------------------
nodePardot.PardotAPI({
userKey: userkey,
email: emailAdmin,
password: password,
// turn off when live
DEBUG: true
}, function (err, client) {
if (err) {
// Authentication failed
// handle error
console.error("Authentication Failed", err)
} else {
// Authentication successful
// gets api key
var api_key = client.apiKey;
console.log("Authentication successful !", api_key);
}
});
// Third Retrieve posted data from Front-End
//---------------------------------- Send all data to API -----------------------------------------------------
// ------------------------------------------------------------------------------------------------------------
// Set the headers
var headers = {
'User-Agent': 'Super Agent/0.0.1',
'Content-Type': 'application/x-www-form-urlencoded'
};
// Configure the request
var options = {
url: 'https://pi.pardot.com/api/prospect/version/4/do/create/email',
method: 'POST',
headers: headers,
form: {
'email': emailUser,
'user_key': userkey,
'api_key': api_key
}
};
// Start the request
request(options, function (error, response, body) {
if (!error && response.statusCode == 200) {
// Print out the response body
console.log("error",body)
}
else {
console.log("Sent Data",body);
}
});
best way is using async package (install with npm install async) that is very famous and useful package in npm your functions will be something like this:
var async=require('async');
var handler = function (req,res) {
async.auto
(
{
getBody: function (cb, results) {
var body=req.body;
//prepare body here then send it to next function
cb(null, body)
},
getApi: ['getBody', function (results, cb) {
var preparedBody=results.getBody;
// get the api here and send it to next function
var apiKey=getApi()
cb(null, {apiKey:apiKey,preparedBody:preparedBody})
}],
third: ['getApi', function (results, cb) {
var preparedBody=results.getApi.preparedBody;
var apiKey=results.getApi.apiKey;
// now data are here
cb(null,true)
}]
},
function (err, allResult) {
// the result of executing all functions goes here
}
)
}
Another way to handle this problem is by allowing the express middleware flow to do those things for you on a separate Router.
I have setup a sample Glitch for your reference using stand in functions to simulate network calls HERE.
In your case, you would have to do something like:
//API route
var express = require('express');
var router = express.Router();
router.post('/data', function (req, res, next) {
console.log(req.body);
req.bundledData = {};
req.bundledData.fname = req.body.fname;
req.bundledData.lname = req.body.lname;
req.bundledData.emailUser = req.body.email;
next();
});
router.use(function(req, res, next){
nodePardot.PardotAPI({
userKey: userkey,
email: emailAdmin,
password: password,
// turn off when live
DEBUG: true
}, function (err, client) {
if (err) {
// Authentication failed
// handle error
console.error("Authentication Failed", err)
} else {
// Authentication successful
// gets api key
req.bundledData.api_key = client.apiKey;
console.log("Authentication successful !", api_key);
next();
}
});
});
router.use(function(req, res, next){
// Set the headers
var headers = {
'User-Agent': 'Super Agent/0.0.1',
'Content-Type': 'application/x-www-form-urlencoded'
};
// Configure the request
var options = {
url: 'https://pi.pardot.com/api/prospect/version/4/do/create/email',
method: 'POST',
headers: headers,
form: {
'email': emailUser,
'user_key': userkey,
'api_key': api_key
}
};
// Start the request
request(options, function (error, response, body) {
if (!error && response.statusCode == 200) {
// Print out the response body
console.log("error",body)
}
else {
console.log("Sent Data",body);
//Processing is complete
res.json({
success:true,
body:body
});
}
});
});

Categories

Resources