I want my http respond script to respond with data from my SQL server. So I can use AJAX to update HTML with data from my SQL server. And I cant find a way to do this. I'm just learning about async and I have a feeling that if I can save the output of my async function to a global var then it will work. Any help would save my headache.
My simple Listen script is:
var test = "hello!"
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.write(test);
res.end();
}).listen(8080);
and my sql code is:
const util = require('util');
var mysql = require('mysql');
var con = mysql.createConnection({
host: "XXXXX",
user: "XXXXX",
password: "XXXXX",
database: "XXX"
});
var DBresult=null;
function getdb(){
const query = util.promisify(con.query).bind(con);
(async () => {
try {
const rows = await query('SELECT * FROM mylist');
DBresult=rows;
} finally {
con.end();
}
})()
}
Do NOT use any globals or shared, higher scoped variables for your asynchronous result in a server. Never do that. That is an anti-pattern for good reason because that can create intermittent concurrency problems because more than one request can be in process at the same time on your server so these would cause conflicting access to those variables, creating intermittent, very-hard-to-debug problems. I repeat again, NEVER.
You didn't describe an exact situation you are trying to write code for, but here's an example.
Instead, you use the result inside the context that it arrives from your asynchronous call. If you can use await, that generally makes the coding cleaner.
Here's a simple example:
const con = mysql.createConnection({
host: "XXXXX",
user: "XXXXX",
password: "XXXXX",
database: "XXX"
});
const query = util.promisify(con.query).bind(con);
http.createServer(async function(req, res) {
if (req.path === "/query" && req.method === "GET") {
try {
const rows = await query('SELECT * FROM mylist');
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify(rows));
} catch(e) {
console.log(e);
res.statusCode = 500;
res.end();
}
} else {
// some other respone
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write("hello");
res.end();
}
}).listen(8080);
Things to note here:
Checking both path and method before handling the request.
Making callback function async so it can use await.
Making sure any promise rejection from await is caught by try/catch and an error response is sent if there's an error.
Sending result as JSON and setting appropriate content-type.
You may be using the plain http module as a learning experience, but you will very quickly find that using the simple Express framework will save you lots of programming time and make things lots easier.
If you want to use async functions, it would be something like this, take care of "async" in function for the createServer
var http = require('http');
var server = http.createServer(async (req, res) => {
async function mgetdata() {
// Async code goes here
return 'Hello, world!';
}
// Wait for the async function to complete and get its return value
const response = await mgetdata();
// Send the response
res.end(response);
});
I'm just starting to learn Node.js and right now, I'm trying to use a Node.js Application through cPanel to provide a JSON response when its app's URL is accessed.
When visiting the app's URL, it's evident that the Node.js server is working as it should. So after editing the main JS file, and restarting the Node.js app, changes are reflected when visiting the URL again.
My problem:
Within the function of https.createServer( function (req, res) {});, I want to make an HTTPS request to a PHP file elsewhere, which returns a JSON response. At the moment, I can't even get a response or error from any type of request with the PHP file.
var https = require('https');
var server = https.createServer(function (req, res) {
var message = "";
res.writeHead(200, {
'Content-Type': 'text/plain'
});
var options = {
host: "mydomain.com",
path: '/myPhpScript.php'
};
https.get(options, function(res) {
var bodyChunks = [];
res.on('data', function(chunk) {
bodyChunks.push(chunk);
}).on('end', function() {
var body = Buffer.concat(bodyChunks);
message += body;
})
}).on('error', function(e) {
message += e;
});
res.end(message);
});
server.listen();
As you can see, message would be what's displayed to the browser window, but it's empty. Nothing appears when visiting the App URL. Is it possible to make an HTTPS request with a Node.js HTTPS server?
Note:
I've also tried with native-request and axios and have experienced the same issue.
Server code:
var http = require('http');
var https = require("https");
var server = http.createServer(function (req, res) {
let call = new Promise((resolve, reject) => {
var options = {
host: "jarrenmorris.com",
port: 443,
path: '/gamesense/r6_db/1.json'
};
https.get(options, function (res) {
var bodyChunks = [];
res.on('data', function (chunk) {
bodyChunks.push(chunk);
}).on('end', function () {
resolve(Buffer.concat(bodyChunks));
});
}).on('error', function (e) {
reject(e);
});
});
call.then((data) => {
// do something here with the successful request/json
res.writeHead(200, {
'Content-Type': 'text/plain'
});
res.end(data);
}).catch((err) => {
// do something here with the failure request/json
// res.write("ERROR:");
res.end(err);
});
});
server.listen(8081, "127.0.0.1", () => {
console.log(`Server listen on ${server.address().address}:${server.address().port} `);
});
Response:
{"name":"tim","age":"42"}
First thing i noticed, while i tried to run your code was, you cant establish a connection to your node.js.
The reason for this was you use the https module, but didnt specify an certificates/keyfiles. Skip this, and work with http till you get the result you want.
Then i wrapped you https request to the external api/file in a promise.
This allows a simple chaining and better readability of the code.
When the promises resolves/fullfill, we answer the request on the http server with the data we received from the external request.
The res.end in your code (where you put it) made no sense, since you didnt wait for the external request to complete. Thats the reason why its nothing is shown in the browser window.
I have a node web server with several api endpoints. One of those endpoints needs to make a request to another server in order to assemble its own response. I've seen a few different answers with links to libraries that allow purely synchronous web requests, but they're all associated with warnings that say not to use them in production.
Here is an example of what my server request handler looks like:
app.get('/my_api_endpoint', function (req, res) {
// Need to get data from other webservice using data
// from this request.
data = request_to_other_web_service(req.params.some_value);
res.status(200);
res.send("This is the " + data);
res.end();
});
Is there a standard pattern for handling requests like this?
The reason why you are getting errors/warnings when trying to synchronously call an HTTP request is that from the get-go node.js was built with the core philosophy of callbacks & the event loop. If you are trying to write asynchronous code in a synchronous way... May i point you in the direction of async/await. You could you use npm install node-fetch
const fetch = require('node-fetch');
app.get('/my_api_endpoint', async function (req, res) {
// Need to get data from other webservice using data
// from this request.
data = await fetch("http://...");
res.status(200);
res.send("This is the " + data);
res.end();
});
In general all javascript libraries/frameworks are friendly to non-synchronous operations. Those that are not will be ignored by the community. Express already allow you to perform asynchronous operations.
Have you ever wondered why express requires you to "return" responses by calling methods on res instead of simply returning?:
// frameworks in some other languages:
#Path("/my_api_endpoint")
Response myEndpoint() {
data = request_to_other_web_service(some_value);
return data; // Javascript frameworks don't use returns!!
}
It is because all javascript web frameworks are async friendly. The reason you use a callback (a function that you call back at some later time) to return from a route is because you can call functions inside other functions. In Express you call res.send() after you've performed async operations. How you do it depends on the API you're using:
API that accepts a callback:
app.get('/my_api_endpoint', function (req, res, next) {
request(req.params.some_value, function (error, data) {
if (!error) {
res.status(200);
res.send("This is the " + data);
}
else {
next(error);
}
}
});
API that returns a promise:
app.get('/my_api_endpoint', function (req, res, next) {
request(req.params.some_value)
.then(function (data) {
res.status(200);
res.send("This is the " + data);
})
.catch(function (error) {
next(error);
});
});
Using async/await with API that returns a promise:
app.get('/my_api_endpoint', async function (req, res, next) {
try {
let data = await request(req.params.some_value)
res.status(200);
res.send("This is the " + data);
}
catch (error) {
next(error);
}
});
Stream based API:
app.get('/my_api_endpoint', async function (req, res, next) {
let dataStream = request(req.params.some_value);
let buffer = "";
dataStream.on('data', function (data) {
buffer += data.toString('utf8');
});
dataStream.on('end', function () {
res.status(200);
res.send("This is the " + buffer);
});
dataStream.on('error', function () {
next("Stream error");
});
});
Express can handle any asynchronous program flow.
Im using sailsjs as a MVC for node js, i'm still learning it.
I managed to get data from my own database and use it.
But now i need/want to get data from an external rest api.
I used this in my controller:
// api/controllers/SomeController.js
test : function(res,req){
var j;
var https = require('https');
var options = {
hostname: 'testing.atlassian.net',
port: 443,
path: '/rest/api/2/search?jql=project=ABC',
method: 'GET',
headers: {'Authorization': 'Basic ' + 'SuperSecretLoginAndPassword'}
};
var req = https.request(options, function(res) {
res.setEncoding('utf8');
res.on('data', function(d) {
});
});
req.end();
}
The variable d is displaying the right result.
How can i use the request results in my view?
I've searched a lot but i cant find any ways to display this in my view.
And will this be realtime updated? So if something in de rest api changes I won't have to refresh.
Sorry if this is something stupid.
Basically you'll want to wait for your request to fire its callback and then feed the fetched data into res.locals. Assuming you are fetching JSON data, you could do this:
// api/controllers/SomeController.js
test: function(req, res) {
var https = require('https');
...
https.request(options, function(response) {
var responseData = '';
response.setEncoding('utf8');
response.on('data', function(chunk){
responseData += chunk;
});
response.once('error', function(err){
// Some error handling here, e.g.:
res.serverError(err);
});
response.on('end', function(){
try {
// response available as `responseData` in `yourview`
res.locals.requestData = JSON.parse(responseData);
} catch (e) {
sails.log.warn('Could not parse response from options.hostname: ' + e);
}
res.view('yourview');
});
}).end();
}
The example code you supplied has some issues:
test: function(res,req) ... Don't mixup the controller arguments, the first is _req_uest, the second one _res_ponse.
var req = https.request ... You really do not want to override the req argument passed into your controller action. Use some other name.
https.request(options, function(res) {...} Same here. Doing this overrides res for the https.request callback scope - preventing you from using all the goodies (e.g.: res.view) supplied by the res parameter passed to your controller.
I'd guess it would make sense for you to read up on closures and callbacks:
What are Closures and Callbacks?
How can I make an HTTP request from within Node.js or Express.js? I need to connect to another service. I am hoping the call is asynchronous and that the callback contains the remote server's response.
Here is a snippet of some code from a sample of mine. It's asynchronous and returns a JSON object. It can do any form of GET request.
Note that there are more optimal ways (just a sample) - for example, instead of concatenating the chunks you put into an array and join it etc... Hopefully, it gets you started in the right direction:
const http = require('http');
const https = require('https');
/**
* getJSON: RESTful GET request returning JSON object(s)
* #param options: http options object
* #param callback: callback to pass the results JSON object(s) back
*/
module.exports.getJSON = (options, onResult) => {
console.log('rest::getJSON');
const port = options.port == 443 ? https : http;
let output = '';
const req = port.request(options, (res) => {
console.log(`${options.host} : ${res.statusCode}`);
res.setEncoding('utf8');
res.on('data', (chunk) => {
output += chunk;
});
res.on('end', () => {
let obj = JSON.parse(output);
onResult(res.statusCode, obj);
});
});
req.on('error', (err) => {
// res.send('error: ' + err.message);
});
req.end();
};
It's called by creating an options object like:
const options = {
host: 'somesite.com',
port: 443,
path: '/some/path',
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
};
And providing a callback function.
For example, in a service, I require the REST module above and then do this:
rest.getJSON(options, (statusCode, result) => {
// I could work with the resulting HTML/JSON here. I could also just return it
console.log(`onResult: (${statusCode})\n\n${JSON.stringify(result)}`);
res.statusCode = statusCode;
res.send(result);
});
UPDATE
If you're looking for async/await (linear, no callback), promises, compile time support and intellisense, we created a lightweight HTTP and REST client that fits that bill:
Microsoft typed-rest-client
Try using the simple http.get(options, callback) function in node.js:
var http = require('http');
var options = {
host: 'www.google.com',
path: '/index.html'
};
var req = http.get(options, function(res) {
console.log('STATUS: ' + res.statusCode);
console.log('HEADERS: ' + JSON.stringify(res.headers));
// Buffer the body entirely for processing as a whole.
var bodyChunks = [];
res.on('data', function(chunk) {
// You can process streamed parts here...
bodyChunks.push(chunk);
}).on('end', function() {
var body = Buffer.concat(bodyChunks);
console.log('BODY: ' + body);
// ...and/or process the entire body here.
})
});
req.on('error', function(e) {
console.log('ERROR: ' + e.message);
});
There is also a general http.request(options, callback) function which allows you to specify the request method and other request details.
Request and Superagent are pretty good libraries to use.
note: request is deprecated, use at your risk!
Using request:
var request=require('request');
request.get('https://someplace',options,function(err,res,body){
if(err) //TODO: handle err
if(res.statusCode === 200 ) //etc
//TODO Do something with response
});
You can also use Requestify, a really cool and very simple HTTP client I wrote for nodeJS + it supports caching.
Just do the following for GET method request:
var requestify = require('requestify');
requestify.get('http://example.com/api/resource')
.then(function(response) {
// Get the response body (JSON parsed or jQuery object for XMLs)
response.getBody();
}
);
This version is based on the initially proposed by bryanmac function which uses promises, better error handling, and is rewritten in ES6.
let http = require("http"),
https = require("https");
/**
* getJSON: REST get request returning JSON object(s)
* #param options: http options object
*/
exports.getJSON = function (options) {
console.log('rest::getJSON');
let reqHandler = +options.port === 443 ? https : http;
return new Promise((resolve, reject) => {
let req = reqHandler.request(options, (res) => {
let output = '';
console.log('rest::', options.host + ':' + res.statusCode);
res.setEncoding('utf8');
res.on('data', function (chunk) {
output += chunk;
});
res.on('end', () => {
try {
let obj = JSON.parse(output);
// console.log('rest::', obj);
resolve({
statusCode: res.statusCode,
data: obj
});
}
catch (err) {
console.error('rest::end', err);
reject(err);
}
});
});
req.on('error', (err) => {
console.error('rest::request', err);
reject(err);
});
req.end();
});
};
As a result you don't have to pass in a callback function, instead getJSON() returns a promise. In the following example the function is used inside of an ExpressJS route handler
router.get('/:id', (req, res, next) => {
rest.getJSON({
host: host,
path: `/posts/${req.params.id}`,
method: 'GET'
}).then(({ statusCode, data }) => {
res.json(data);
}, (error) => {
next(error);
});
});
On error it delegates the error to the server error handling middleware.
Unirest is the best library I've come across for making HTTP requests from Node. It's aiming at being a multiplatform framework, so learning how it works on Node will serve you well if you need to use an HTTP client on Ruby, PHP, Java, Python, Objective C, .Net or Windows 8 as well. As far as I can tell the unirest libraries are mostly backed by existing HTTP clients (e.g. on Java, the Apache HTTP client, on Node, Mikeal's Request libary) - Unirest just puts a nicer API on top.
Here are a couple of code examples for Node.js:
var unirest = require('unirest')
// GET a resource
unirest.get('http://httpbin.org/get')
.query({'foo': 'bar'})
.query({'stack': 'overflow'})
.end(function(res) {
if (res.error) {
console.log('GET error', res.error)
} else {
console.log('GET response', res.body)
}
})
// POST a form with an attached file
unirest.post('http://httpbin.org/post')
.field('foo', 'bar')
.field('stack', 'overflow')
.attach('myfile', 'examples.js')
.end(function(res) {
if (res.error) {
console.log('POST error', res.error)
} else {
console.log('POST response', res.body)
}
})
You can jump straight to the Node docs here
Check out shred. It's a node HTTP client created and maintained by spire.io that handles redirects, sessions, and JSON responses. It's great for interacting with rest APIs. See this blog post for more details.
Check out httpreq: it's a node library I created because I was frustrated there was no simple http GET or POST module out there ;-)
For anyone who looking for a library to send HTTP requests in NodeJS, axios is also a good choice. It supports Promises :)
Install (npm): npm install axios
Example GET request:
const axios = require('axios');
axios.get('https://google.com')
.then(function (response) {
// handle success
console.log(response);
})
.catch(function (error) {
// handle error
console.log(error);
})
Github page
Update 10/02/2022
Node.js integrates fetch in v17.5.0 in experimental mode. Now, you can use fetch to send requests just like you do on the client-side. For now, it is an experimental feature so be careful.
If you just need to make simple get requests and don't need support for any other HTTP methods take a look at: simple-get:
var get = require('simple-get');
get('http://example.com', function (err, res) {
if (err) throw err;
console.log(res.statusCode); // 200
res.pipe(process.stdout); // `res` is a stream
});
Use reqclient: not designed for scripting purpose
like request or many other libraries. Reqclient allows in the constructor
specify many configurations useful when you need to reuse the same
configuration again and again: base URL, headers, auth options,
logging options, caching, etc. Also has useful features like
query and URL parsing, automatic query encoding and JSON parsing, etc.
The best way to use the library is create a module to export the object
pointing to the API and the necessary configurations to connect with:
Module client.js:
let RequestClient = require("reqclient").RequestClient
let client = new RequestClient({
baseUrl: "https://myapp.com/api/v1",
cache: true,
auth: {user: "admin", pass: "secret"}
})
module.exports = client
And in the controllers where you need to consume the API use like this:
let client = require('client')
//let router = ...
router.get('/dashboard', (req, res) => {
// Simple GET with Promise handling to https://myapp.com/api/v1/reports/clients
client.get("reports/clients")
.then(response => {
console.log("Report for client", response.userId) // REST responses are parsed as JSON objects
res.render('clients/dashboard', {title: 'Customer Report', report: response})
})
.catch(err => {
console.error("Ups!", err)
res.status(400).render('error', {error: err})
})
})
router.get('/orders', (req, res, next) => {
// GET with query (https://myapp.com/api/v1/orders?state=open&limit=10)
client.get({"uri": "orders", "query": {"state": "open", "limit": 10}})
.then(orders => {
res.render('clients/orders', {title: 'Customer Orders', orders: orders})
})
.catch(err => someErrorHandler(req, res, next))
})
router.delete('/orders', (req, res, next) => {
// DELETE with params (https://myapp.com/api/v1/orders/1234/A987)
client.delete({
"uri": "orders/{client}/{id}",
"params": {"client": "A987", "id": 1234}
})
.then(resp => res.status(204))
.catch(err => someErrorHandler(req, res, next))
})
reqclient supports many features, but it has some that are not supported by other
libraries: OAuth2 integration and logger integration
with cURL syntax, and always returns native Promise objects.
If you ever need to send GET request to an IP as well as a Domain (Other answers did not mention you can specify a port variable), you can make use of this function:
function getCode(host, port, path, queryString) {
console.log("(" + host + ":" + port + path + ")" + "Running httpHelper.getCode()")
// Construct url and query string
const requestUrl = url.parse(url.format({
protocol: 'http',
hostname: host,
pathname: path,
port: port,
query: queryString
}));
console.log("(" + host + path + ")" + "Sending GET request")
// Send request
console.log(url.format(requestUrl))
http.get(url.format(requestUrl), (resp) => {
let data = '';
// A chunk of data has been received.
resp.on('data', (chunk) => {
console.log("GET chunk: " + chunk);
data += chunk;
});
// The whole response has been received. Print out the result.
resp.on('end', () => {
console.log("GET end of response: " + data);
});
}).on("error", (err) => {
console.log("GET Error: " + err);
});
}
Don't miss requiring modules at the top of your file:
http = require("http");
url = require('url')
Also bare in mind that you may use https module for communicating over secured network. so these two lines would change:
https = require("https");
...
https.get(url.format(requestUrl), (resp) => { ......
## you can use request module and promise in express to make any request ##
const promise = require('promise');
const requestModule = require('request');
const curlRequest =(requestOption) =>{
return new Promise((resolve, reject)=> {
requestModule(requestOption, (error, response, body) => {
try {
if (error) {
throw error;
}
if (body) {
try {
body = (body) ? JSON.parse(body) : body;
resolve(body);
}catch(error){
resolve(body);
}
} else {
throw new Error('something wrong');
}
} catch (error) {
reject(error);
}
})
})
};
const option = {
url : uri,
method : "GET",
headers : {
}
};
curlRequest(option).then((data)=>{
}).catch((err)=>{
})