Server Sent Event; `EventSource.onmessage` not firing - node.js

I'm trying to use the following example of Server Sent Events. Seems like the server is emitting the data, but the event is not firing and no data is recorded in the event stream (through the developer tools).
Angular code (service):
getAlertsEvent(fieldIds: Guid[]): Observable<responseModel.LoanAlert> {
return new Observable(obs => {
fieldIds.forEach(fieldId => {
const source = new EventSource(`http://localhost:3000/loan/alerts/${fieldId}`);
alert('Succesfully creates the EventSource, I see reuslt 200 in Networking tab but with 0 events');
source.onmessage = (ev): void => {
this.zone.run(() => {
alert('This alert will not happen');
obs.next(ev.data);
});
};
source.onerror = (err): void => this.zone.run(() => obs.error(err));
// Also tried this way with no luck:
// source.addEventListener('message', (event) => {
// obs.next(event.data);
// });
});
});
}
Component:
this.loansService.getAlertsEvent(this.fields.map(field => field.fieldId)).subscribe(alert => {
console.log(alert);
});
Node.js code:
const express = require('express');
const parser = require('body-parser');
const app = express();
const EventEmitter = require('events');
const Stream = new EventEmitter();
app.unsubscribe(parser.json());
app.use(
parser.urlencoded({
extended: true,
})
);
app.get('/loan/alerts/:fieldId', function(req, res) {
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Access-Control-Allow-Origin': "*",
Conection: 'keep-alive'
});
Stream.on(req.params.fieldId, function(event, data) {
res.write(JSON.stringify(data));
});
});
setInterval(function() {
const item = {
formId: 51415,
alertId: 'asdfasdfasdf',
messageStatus: 'NEW',
messageType: 'ACTION_MESSAGE_FROM_SERVER',
actionType: 'NAVIGATION',
message: 'New Message!',
archiverId: '12345',
documentCode: 3,
from: 'Internal Server Message',
messageTimestamp: new Date().toJSON(),
markedAsRead: false,
};
Stream.emit('aed29580-09fd-e411-b8e1-e61f13cf5d4b', 'message', item);
}, 5000);
app.listen(3000);
console.log('Express E2e Mock server is running');
When manually going to http://localhost:3000/loan/alerts/aed29580-09fd-e411-b8e1-e61f13cf5d4b I'm seeing the messages printed to the screen, so I guess that this is either an Angular or a missing security header.
Thanks!

I just realized, thanks to this answer, that events must be formatted in a specific way. I changed the value of res.write accordingly:
Stream.on(req.params.fieldId, function(event, data) {
res.write('event: ' + String(event) + '\n' + 'data: ' + JSON.stringify(data) + '\n\n');
});

Related

Laravel chat app : Unable to deliver messages to a specific user

I have been trying to develop a chat app on Laravel with socket.io. Now, I am facing problem that is when a user is sending a message to a specific user, the message is being delivered to all the available users. May I know the section of code you need to help me out? Or there's some other area where I can specifically look into.
const express = require("express");
const app = express();
const server = require('http').createServer(app);
const io = require("socket.io")(server, {
cors: { origin: "*" }
});
server.listen(3000, () => {
console.log('Server is running');
io.on("connection", function(socket) {
console.log("User" + socket.id);
socket.on("messageSent", function(message, senderId) {
socket.broadcast.emit("messageSent", message, this.socket.id)
console.log(this.socket.id);
});
//msg
socket.on("msgSent", function(message) {
socket.broadcast.emit("msgSent", message)
});
socket.on("clientMmsgSent", function(message) {
socket.broadcast.emit("clientMmsgSent", message)
});
});
});
Other code:
<sc ript>
var socket = io("{{config('app.server_url')}}");
function sendMessage(event) {
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
//console.log('test');
event.preventDefault();
if (event.keyCode === 13) {
var msg = document.getElementById('msg').value;
var client_id = document.getElementById('client_id').value;
var operator_id = document.getElementById('operator_id').value;
//console.log(smg);
$.ajax({
type: "POST",
url: "{{route('send.msg')}}",
data: {
msg: msg,
client_id: client_id,
operator_id: operator_id,
},
beforeSend: function() {
},
success: function(data) {
var msg = `
<div class="operator-msg">
${data.operator_msg}
</div>
`;
console.log(data);
socket.emit("msgSent", {
'data': data,
});
$('#opt_msg').append(msg);
},
error: function(error) {
console.log(error);
}
});
$('#msg').val(" ");
return true;
} else {
return false;
}
}
</sc ript>

Simple Fetch API Post Request Fails No Matter What

I have been working on this issue for 2 days, looked at various pages and cannot find a single solution that would work.
Please only reply if you know how to write them with async await functions and please reply if you know the answer of fetch api. I am not looking for axios solutions for the time being.
I have a backend server which runs on port 8000 of localhost, frontend runs on port 3000. Front end is written in React, backend is written in Node/Express.
I am able to successfully make a GET request from backend server but the POST request fails for some reason with the error "VM942:1 POST http://localhost:8000/frontend-to-backend 500 (Internal Server Error)"
Backend server has this error: SyntaxError: Unexpected token u in JSON at position 0
at JSON.parse ()
// React-To-Node-Connection
// React "App.js" file
// "package.json" file contains this
// "proxy": "http://localhost:8000"
useEffect(() => {
const getBackend = async () => {
const res = await fetch('backend-to-frontend');
const data = await res.json();
if (!res.ok) {
throw new Error(`Cannot get data from backend server. HTTP Status: ${res.status}`);
}
console.log(data.message);
// Prints "Hi from backend!"
}
getBackend();
const postBackend = async () => {
try {
const res = await fetch('http://localhost:8000/frontend-to-backend',
{
method: 'POST',
mode: 'no-cors',
body: JSON.stringify({ message: 'Hi from frontend!' }),
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
}
);
if (res.ok) {
const data = await res.json();
console.log(data);
}
} catch (error) {
console.error(error);
}
}
postBackend();
}, []);
Now the backend code:
app.get('/backend-to-frontend', (req, res) => {
res.json({ message: 'Hi from backend!' });
});
app.post('/frontend-to-backend', (req, res) => {
try {
const reactMessage = JSON.parse(req.body.data);
console.log(`message: ${reactMessage}`);
} catch (err) {
console.error(err);
}
});
How to fix this? Please help!
Full backend server code can be found here:
const express = require("express");
const app = express();
app.use(express.urlencoded({ extended: true }));
app.get('/backend-to-frontend', (req, res) => {
res.json({ message: 'Hi from backend!' });
});
app.post('/frontend-to-backend', (req, res) => {
try {
const reactMessage = JSON.parse(req.body.data);
console.log(`message: ${reactMessage}`);
} catch (err) {
console.error(err);
}
});
const port = process.env.PORT || 8000;
app.listen(port, function () {
console.log(`Backend server started on port ${port}.`);
});
with no-cors, you can only use simple headers, so you cannot POST JSON (see: Supplying request options)
Try urlencoded:
const postBackend = async() => {
try {
const res = await fetch('http://localhost:8000/frontend-to-backend', {
method: 'POST',
mode: 'no-cors',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: new URLSearchParams({
'message': 'Hi from frontend!'
})
});
if (res.ok) {
const data = await res.json();
console.log(data);
}
} catch (error) {
console.error(error);
}
}
postBackend();
and on the server, don't parse req.body, as it's already done by middleware:
app.post('/frontend-to-backend', (req, res) => {
console.log('req.body: ', req.body);
try {
const reactMessage = req.body.message;
req.body.data may be an object (check with debugger). If so, you might try to stringify before parsing :
JSON.parse(JSON.stringify(req.body.data))
I finally found the answer, here is my sample code. I did not change the React code that much so it is pretty much same, I removed the no cors section and added cors to Express JS code.
Here is my React code.
// React-To-Node-Connection
// "package.json" file has the following line
// "proxy": "http://localhost:8000"
// React Code
useEffect(() => {
const getBackend = async () => {
const res = await fetch('/backend-to-frontend');
const data = await res.json();
if (!res.ok) {
throw new Error(`Cannot get data from backend server. HTTP Status: ${res.status}`);
}
console.log(data.message);
}
getBackend();
const postBackend = async () => {
try {
await fetch('http://localhost:8000/frontend-to-backend',
{
method: 'POST',
body: JSON.stringify({ message: 'Hi from frontend!' }),
headers: {
'Content-Type': 'application/json'
}
}
);
} catch (err) {
console.error(err);
}
}
postBackend();
}, []);
And here is my Express JS code.
const express = require("express");
const app = express();
app.use(express.urlencoded({ extended: true }));
// Express JS Code
const cors = require('cors');
app.use(express.json());
app.use(cors());
app.get('/backend-to-frontend', (req, res) => {
res.json({ message: 'Hi from backend!' });
});
app.post('/frontend-to-backend', (req, res) => {
try {
console.log(req.body.message);
} catch (err) {
console.error(err);
}
});
const port = process.env.PORT || 8000;
app.listen(port, function () {
console.log(`Backend server started on port ${port}.`);
});
Thanks.

Node EventEmitter manage listener pool

I'm trying to notify periodically all clients about changes in sports matches, for which I use Eventemitter in node. The notification works fine, the issue I have is that if the client closes/refreshes the browser window, I should remove the listener on the server and decrease the pool of listeners, otherwise I could easily bump into memory leak warnings.
Code:
const EventEmitter = require('events');
const Stream = new EventEmitter();
exports.getScheduleUpdates = async (req, res) => {
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
Connection: 'keep-alive'
});
Stream.on('push', (data) => {
let isAlive = res.write(`data: ${JSON.stringify(data)}\n\n`);
if (!isAlive) {
console.log("Should terminate");
}
console.log(isAlive);
});
}
setInterval(() => {
Stream.emit('push', { match: 'sending some data' });
}, 10000);
When I run it locally and refresh the browser for example 2 times, the event fires for 3 clients, 2 of which are closed and the res.write returned false.
I got this far with the help of Google, but I can't figure out how to handle the listener pool for the event and remove them if the isAlive flag is false. Not 100% sure if relying on res.write return value is correct.
Thank you
In the end, I found this tutorial:
https://alligator.io/nodejs/server-sent-events-build-realtime-app/
Which ended up working well for my case.
let connectedClients = [];
exports.getScheduleUpdates = async (req, res) => {
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
Connection: 'keep-alive'
});
const clientId = Date.now();
const newclient = {
id: clientId,
res
}
connectedClients.push(newclient);
req.on('close', () => {
connectedClients = connectedClients.filter(c => c.id !== clientId);
});
}
function sendScheduleUpdates(changesToSend) {
connectedClients.forEach(client => {
client.res.write(`data: ${JSON.stringify(changesToSend)}\n\n`);
});
}
setInterval(() => {
sendScheduleUpdates([{ match: 'sending some data' }]);
}, 10000);
Closing of old, unused responses is done in res.on('close', () => {...}) part.

How to save a text to speech audio file client side?

desired behaviour
allow user to download text to speech audio file by clicking a button, like this official demo:
https://text-to-speech-starter-kit.ng.bluemix.net
what i've tried
i am using:
https://github.com/watson-developer-cloud/node-sdk
i can generate an audio file server side but can't figure out how to send that file back to the client for them to save - so i am trying to generate it client side instead.
attempt 01: generate audio file server side
server.js (works)
const fs = require('fs');
const TextToSpeechV1 = require('ibm-watson/text-to-speech/v1');
const textToSpeech = new TextToSpeechV1({
iam_apikey: '{apikey}',
});
const synthesizeParams = {
text: 'Hello world',
accept: 'audio/wav',
voice: 'en-US_AllisonVoice',
};
textToSpeech.synthesize(synthesizeParams)
.then(audio => {
audio.pipe(fs.createWriteStream('hello_world.wav'));
})
.catch(err => {
console.log('error:', err);
});
for reference, according to the docs, the .synthesize() method response type is:
NodeJS.ReadableStream|FileObject|Buffer
attempt 02: generate audio file client side
server.js - required to get token (works)
var AuthorizationV1 = require('ibm-watson/authorization/v1');
var iam_apikey = local_settings.TEXT_TO_SPEECH_IAM_APIKEY;
var url = local_settings.TEXT_TO_SPEECH_URL;
var authorization = new AuthorizationV1({
iam_apikey: iam_apikey,
url: url
});
const api_tts_token_get = async (req, res) => {
authorization.getToken(function(err, token) {
if (!token) {
console.log('error:', err);
} else {
res.json({ token: token, url: url });
}
});
}
app.route("/api/:api_version/text-to-speech/token")
.get(api_tts_token_get);
client.js (doesn’t work)
var TextToSpeechV1 = require('ibm-watson/text-to-speech/v1');
const get_token = (parameters) => {
$.ajax({
url: "/api/v1/text-to-speech/token",
data: parameters,
dataType: 'json',
cache: false,
headers: headers,
success: function(results) {
var token = results.token;
var url = results.url;
var textToSpeech = new TextToSpeechV1({ token: token, url: url });
var synthesizeParams = {
text: 'hello world!',
accept: 'audio/wav',
voice: 'en-US_AllisonV3Voice'
};
textToSpeech.synthesize(synthesizeParams, function(err, result) {
if (err) {
return console.log(err);
}
console.log(result);
});
},
statusCode: {
500: function() {
console.log("that didn't work");
}
}
});
}
webpack.config.js
added per instructions at:
https://github.com/watson-developer-cloud/node-sdk/tree/master/examples/webpack#important-notes
node: {
// see http://webpack.github.io/docs/configuration.html#node
// and https://webpack.js.org/configuration/node/
fs: 'empty',
net: 'empty',
tls: 'empty'
},
chrome dev tools errors:
xhr.js:108 Refused to set unsafe header "User-Agent"
The provided value 'stream' is not a valid enum value of type XMLHttpRequestResponseType.
Access to XMLHttpRequest at 'https://***.watsonplatform.net/text-to-speech/api/v1/synthesize?voice=en-US_AllisonV3Voice'
from origin 'http://localhost:3000' has been blocked by CORS policy:
Request header field x-ibmcloud-sdk-analytics is not allowed by
Access-Control-Allow-Headers in preflight response.
Error: Response not received. Body of error is HTTP ClientRequest object
at RequestWrapper.formatError (requestwrapper.js:218)
at eval (requestwrapper.js:206)
Here is one solution i have figured out.
It generates the audio file server side and sends it back via res.download().
The only caveat is that you can't use $.ajax() but rather something like:
window.open("/api/v1/audio?file_id=12345");
server.js
var TextToSpeechV1 = require('ibm-watson/text-to-speech/v1');
const api_audio_get = async (req, res) => {
var query_parameters = req.query;
var file_id = query_parameters.file_id;
var textToSpeech = new TextToSpeechV1({
iam_apikey: local_settings.TEXT_TO_SPEECH_IAM_APIKEY,
url: local_settings.TEXT_TO_SPEECH_URL
});
const synthesizeParams = {
text: 'here is test voice',
accept: 'audio/wav',
voice: 'en-US_AllisonV3Voice',
};
textToSpeech.synthesize(
synthesizeParams,
function(err, audio) {
if (err) {
console.log(err);
return;
}
// see: https://stackoverflow.com/a/46413467
// this allows you to create temp file on server, send it, then delete it
var filename = file_id + ".wav";
var absPath = path.join(__dirname, "/my_files/", filename);
var relPath = path.join("./my_files", filename); // path relative to server root
// see: https://nodejs.org/en/knowledge/advanced/streams/how-to-use-fs-create-write-stream/
var write_stream = fs.createWriteStream(relPath);
// audio is written to the writestream
audio.pipe(write_stream);
// see: https://stackoverflow.com/questions/19829379/detecting-the-end-of-a-writestream-in-node
write_stream.on('finish', function() {
res.download(absPath, (err) => {
if (err) {
console.log(err);
}
fs.unlink(relPath, (err) => {
if (err) {
console.log(err);
}
console.log("FILE [" + filename + "] REMOVED!");
});
});
});
}
);
}
// route handler
app.route("/api/:api_version/audio")
.get(api_audio_get);
client.js
$(document).on("click", ".download_audio", function() {
window.open("/api/v1/audio?file_id=12345");
});

How is an HTTP POST request made in node.js?

How can I make an outbound HTTP POST request, with data, in node.js?
request is now deprecated. It is recommended you use an alternative
In no particular order and dreadfully incomplete:
native HTTP/S, const https = require('https');
node-fetch
axios
got
superagent
bent
make-fetch-happen
unfetch
tiny-json-http
needle
urllib
Stats comparision
Some code examples
Original answer:
This gets a lot easier if you use the request library.
var request = require('request');
request.post(
'http://www.yoursite.com/formpage',
{ json: { key: 'value' } },
function (error, response, body) {
if (!error && response.statusCode == 200) {
console.log(body);
}
}
);
Aside from providing a nice syntax it makes json requests easy, handles oauth signing (for twitter, etc.), can do multi-part forms (e.g. for uploading files) and streaming.
To install request use command npm install request
Here's an example of using node.js to make a POST request to the Google Compiler API:
// We need this to build our post string
var querystring = require('querystring');
var http = require('http');
var fs = require('fs');
function PostCode(codestring) {
// Build the post string from an object
var post_data = querystring.stringify({
'compilation_level' : 'ADVANCED_OPTIMIZATIONS',
'output_format': 'json',
'output_info': 'compiled_code',
'warning_level' : 'QUIET',
'js_code' : codestring
});
// An object of options to indicate where to post to
var post_options = {
host: 'closure-compiler.appspot.com',
port: '80',
path: '/compile',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength(post_data)
}
};
// Set up the request
var post_req = http.request(post_options, function(res) {
res.setEncoding('utf8');
res.on('data', function (chunk) {
console.log('Response: ' + chunk);
});
});
// post the data
post_req.write(post_data);
post_req.end();
}
// This is an async file read
fs.readFile('LinkedList.js', 'utf-8', function (err, data) {
if (err) {
// If this were just a small part of the application, you would
// want to handle this differently, maybe throwing an exception
// for the caller to handle. Since the file is absolutely essential
// to the program's functionality, we're going to exit with a fatal
// error instead.
console.log("FATAL An error occurred trying to read in the file: " + err);
process.exit(-2);
}
// Make sure there's data before we post it
if(data) {
PostCode(data);
}
else {
console.log("No data to post");
process.exit(-1);
}
});
I've updated the code to show how to post data from a file, instead of the hardcoded string. It uses the async fs.readFile command to achieve this, posting the actual code after a successful read. If there's an error, it is thrown, and if there's no data the process exits with a negative value to indicate failure.
You can use request library. https://www.npmjs.com/package/request
var request = require('request');
To post JSON data:
var myJSONObject = { ... };
request({
url: "http://josiahchoi.com/myjson",
method: "POST",
json: true, // <--Very important!!!
body: myJSONObject
}, function (error, response, body){
console.log(response);
});
To post xml data:
var myXMLText = '<xml>...........</xml>'
request({
url: "http://josiahchoi.com/myjson",
method: "POST",
headers: {
"content-type": "application/xml", // <--Very important!!!
},
body: myXMLText
}, function (error, response, body){
console.log(response);
});
EDIT: As of February 2020 request has been deprecated.
Simple and dependency-free. Uses a Promise so that you can await the result. It returns the response body and does not check the response status code.
const https = require('https');
function httpsPost({body, ...options}) {
return new Promise((resolve,reject) => {
const req = https.request({
method: 'POST',
...options,
}, res => {
const chunks = [];
res.on('data', data => chunks.push(data))
res.on('end', () => {
let resBody = Buffer.concat(chunks);
switch(res.headers['content-type']) {
case 'application/json':
resBody = JSON.parse(resBody);
break;
}
resolve(resBody)
})
})
req.on('error',reject);
if(body) {
req.write(body);
}
req.end();
})
}
Usage:
async function main() {
const res = await httpsPost({
hostname: 'sentry.io',
path: `/api/0/organizations/org/releases/${changesetId}/deploys/`,
headers: {
'Authorization': `Bearer ${process.env.SENTRY_AUTH_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
environment: isLive ? 'production' : 'demo',
})
})
}
main().catch(err => {
console.log(err)
})
There are dozens of open-source libraries available that you can use to making an HTTP POST request in Node.
1. Axios (Recommended)
const axios = require('axios');
const data = {
name: 'John Doe',
job: 'Content Writer'
};
axios.post('https://reqres.in/api/users', data)
.then((res) => {
console.log(`Status: ${res.status}`);
console.log('Body: ', res.data);
}).catch((err) => {
console.error(err);
});
2. Needle
const needle = require('needle');
const data = {
name: 'John Doe',
job: 'Content Writer'
};
needle('post', 'https://reqres.in/api/users', data, {json: true})
.then((res) => {
console.log(`Status: ${res.statusCode}`);
console.log('Body: ', res.body);
}).catch((err) => {
console.error(err);
});
3. Request
const request = require('request');
const options = {
url: 'https://reqres.in/api/users',
json: true,
body: {
name: 'John Doe',
job: 'Content Writer'
}
};
request.post(options, (err, res, body) => {
if (err) {
return console.log(err);
}
console.log(`Status: ${res.statusCode}`);
console.log(body);
});
4. Native HTTPS Module
const https = require('https');
const data = JSON.stringify({
name: 'John Doe',
job: 'Content Writer'
});
const options = {
hostname: 'reqres.in',
path: '/api/users',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': data.length
}
};
const req = https.request(options, (res) => {
let data = '';
console.log('Status Code:', res.statusCode);
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
console.log('Body: ', JSON.parse(data));
});
}).on("error", (err) => {
console.log("Error: ", err.message);
});
req.write(data);
req.end();
For details, check out this article.
I use Restler and Needle for production purposes.
They are both much more powerful than native httprequest. It is possible to request with basic authentication, special header entry or even upload/download files.
As for post/get operation, they also are much simpler to use than raw ajax calls using httprequest.
needle.post('https://my.app.com/endpoint', {foo:'bar'},
function(err, resp, body){
console.log(body);
});
Update 2020:
I've been really enjoying phin - The ultra-lightweight Node.js HTTP client
It can be used in two different ways. One with Promises (Async/Await) and the other with traditional callback styles.
Install via: npm i phin
Straight from it's README with await:
const p = require('phin')
await p({
url: 'https://ethanent.me',
method: 'POST',
data: {
hey: 'hi'
}
})
Unpromisifed (callback) style:
const p = require('phin').unpromisified
p('https://ethanent.me', (err, res) => {
if (!err) console.log(res.body)
})
As of 2015 there are now a wide variety of different libraries that can accomplish this with minimal coding. I much prefer elegant light weight libraries for HTTP requests unless you absolutely need control of the low level HTTP stuff.
One such library is Unirest
To install it, use npm.
$ npm install unirest
And onto the Hello, World! example that everyone is accustomed to.
var unirest = require('unirest');
unirest.post('http://example.com/helloworld')
.header('Accept', 'application/json')
.send({ "Hello": "World!" })
.end(function (response) {
console.log(response.body);
});
Extra:
A lot of people are also suggesting the use of request [ 2 ]
It should be worth noting that behind the scenes Unirest uses the request library.
Unirest provides methods for accessing the request object directly.
Example:
var Request = unirest.get('http://mockbin.com/request');
You can also use Requestify, a really cool and simple HTTP client I wrote for nodeJS + it supports caching.
Just do the following:
var requestify = require('requestify');
requestify.post('http://example.com', {
hello: 'world'
})
.then(function(response) {
// Get the response body (JSON parsed or jQuery object for XMLs)
response.getBody();
});
var https = require('https');
/**
* HOW TO Make an HTTP Call - POST
*/
// do a POST request
// create the JSON object
jsonObject = JSON.stringify({
"message" : "The web of things is approaching, let do some tests to be ready!",
"name" : "Test message posted with node.js",
"caption" : "Some tests with node.js",
"link" : "http://www.youscada.com",
"description" : "this is a description",
"picture" : "http://youscada.com/wp-content/uploads/2012/05/logo2.png",
"actions" : [ {
"name" : "youSCADA",
"link" : "http://www.youscada.com"
} ]
});
// prepare the header
var postheaders = {
'Content-Type' : 'application/json',
'Content-Length' : Buffer.byteLength(jsonObject, 'utf8')
};
// the post options
var optionspost = {
host : 'graph.facebook.com',
port : 443,
path : '/youscada/feed?access_token=your_api_key',
method : 'POST',
headers : postheaders
};
console.info('Options prepared:');
console.info(optionspost);
console.info('Do the POST call');
// do the POST call
var reqPost = https.request(optionspost, function(res) {
console.log("statusCode: ", res.statusCode);
// uncomment it for header details
// console.log("headers: ", res.headers);
res.on('data', function(d) {
console.info('POST result:\n');
process.stdout.write(d);
console.info('\n\nPOST completed');
});
});
// write the json data
reqPost.write(jsonObject);
reqPost.end();
reqPost.on('error', function(e) {
console.error(e);
});
This is the simplest way I use to make request: using 'request' module.
Command to install 'request' module :
$ npm install request
Example code:
var request = require('request')
var options = {
method: 'post',
body: postData, // Javascript object
json: true, // Use,If you are sending JSON data
url: url,
headers: {
// Specify headers, If any
}
}
request(options, function (err, res, body) {
if (err) {
console.log('Error :', err)
return
}
console.log(' Body :', body)
});
You can also use Node.js's built-in 'http' module to make request.
I like the simplicity of superagent (https://github.com/visionmedia/superagent). Same API on both node and browser.
;(async function() {
var response = await superagent.post('http://127.0.0.1:8125/', {age: 2})
console.log(response)
})
There is also node-fetch (https://www.npmjs.com/package/node-fetch), which has an API that matches fetch from the browsers - however this requires manual query string encoding, does not automatically handle content types, or so any of the other work superagent does.
In Node.js 18
Fetch
The fetch() method in JavaScript is used to request data from a
server. The request can be of any type of API that returns the data in
JSON or XML.
Say goodbye to the node-fetch package ,axios and request ,... now the fetch API is available on the global scope by default.
app.get('/', (req, res, next) => {
// Make a post Request.
fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
body: JSON.stringify({
title: 'foo',
body: 'bar',
userId: 1,
}),
headers: {
'Content-type': 'application/json; charset=UTF-8',
},
})
.then((response) => response.json())
.then((json) => console.log(json))
.catch(error => {
console.log(error)
})
res.send('Fetch API is available on the global scope by default')
})
We can make requests as we do in browsers.
For More Information
If you are looking for promise based HTTP requests, axios does its job nicely.
const axios = require('axios');
axios.post('/user', {firstName: 'Fred',lastName: 'Flintstone'})
.then((response) => console.log(response))
.catch((error) => console.log(error));
OR
await axios.post('/user', {firstName: 'Fred',lastName: 'Flintstone'})
To Post Rest/JSON Request
We can simply use request package and save the values we have to send in Json variable.
First install the require package in your console by
npm install request --save
var request = require('request');
var options={
'key':'28',
'key1':'value',
'key2':'value'
}
request({
url:"http://dev.api.ean.com/ean-services/rs/hotel/v3/ping?
minorRev="+options.key+
"&cid="+options.key1+
"&apiKey="+options.key2,
method:"POST",
json:true},function(error,response,body){
console.log(body)
}
);
This my solution for POST and GET.
About the Post method:
If the body is a JSON object, so it's important to deserialize it with JSON.stringify and possibly set the Content-Lenght header accordingly:
var bodyString=JSON.stringify(body)
var _headers = {
'Content-Length': Buffer.byteLength(bodyString)
};
before writing it to the request:
request.write( bodyString );
About both Get and Post methods:
The timeout can occur as a socket disconnect, so you must register its handler like:
request.on('socket', function (socket) {
socket.setTimeout( self.timeout );
socket.on('timeout', function() {
request.abort();
if(timeout) return timeout( new Error('request timed out') );
});
});
while the request handler is
request.on('timeout', function () {
// Timeout happend. Server received request, but not handled it
// (i.e. doesn't send any response or it took to long).
// You don't know what happend.
// It will emit 'error' message as well (with ECONNRESET code).
req.abort();
if(timeout) return timeout( new Error('request timed out') );
});
I strongly suggest to register both the handlers.
The response body is chunked, so you must concat chunks at the data handler:
var body = '';
response.on('data', function(d) {
body += d;
});
At the end the body will contain the whole response body:
response.on('end', function() {
try {
var jsonResponse=JSON.parse(body);
if(success) return success( jsonResponse );
} catch(ex) { // bad json
if(error) return error(ex.toString());
}
});
It is safe to wrap with a try...catchtheJSON.parse` since you cannot be sure that it is a well-formatted json actually and there is no way to be sure of it at the time you do the request.
Module: SimpleAPI
/**
* Simple POST and GET
* #author Loreto Parisi (loretoparisi at gmail dot com)
*/
(function() {
var SimpleAPI;
SimpleAPI = (function() {
var qs = require('querystring');
/**
* API Object model
* #author Loreto Parisi (loretoparisi at gmail dot com)
*/
function SimpleAPI(host,port,timeout,ssl,debug,json) {
this.host=host;
this.port=port;
this.timeout=timeout;
/** true to use ssl - defaults to true */
this.ssl=ssl || true;
/** true to console log */
this.debug=debug;
/** true to parse response as json - defaults to true */
this.json= (typeof(json)!='undefined')?json:true;
this.requestUrl='';
if(ssl) { // use ssl
this.http = require('https');
} else { // go unsafe, debug only please
this.http = require('http');
}
}
/**
* HTTP GET
* #author Loreto Parisi (loretoparisi at gmail dot com)
*/
SimpleAPI.prototype.Get = function(path, headers, params, success, error, timeout) {
var self=this;
if(params) {
var queryString=qs.stringify(params);
if( queryString ) {
path+="?"+queryString;
}
}
var options = {
headers : headers,
hostname: this.host,
path: path,
method: 'GET'
};
if(this.port && this.port!='80') { // port only if ! 80
options['port']=this.port;
}
if(self.debug) {
console.log( "SimpleAPI.Get", headers, params, options );
}
var request=this.http.get(options, function(response) {
if(self.debug) { // debug
console.log( JSON.stringify(response.headers) );
}
// Continuously update stream with data
var body = '';
response.on('data', function(d) {
body += d;
});
response.on('end', function() {
try {
if(self.json) {
var jsonResponse=JSON.parse(body);
if(success) return success( jsonResponse );
}
else {
if(success) return success( body );
}
} catch(ex) { // bad json
if(error) return error( ex.toString() );
}
});
});
request.on('socket', function (socket) {
socket.setTimeout( self.timeout );
socket.on('timeout', function() {
request.abort();
if(timeout) return timeout( new Error('request timed out') );
});
});
request.on('error', function (e) {
// General error, i.e.
// - ECONNRESET - server closed the socket unexpectedly
// - ECONNREFUSED - server did not listen
// - HPE_INVALID_VERSION
// - HPE_INVALID_STATUS
// - ... (other HPE_* codes) - server returned garbage
console.log(e);
if(error) return error(e);
});
request.on('timeout', function () {
// Timeout happend. Server received request, but not handled it
// (i.e. doesn't send any response or it took to long).
// You don't know what happend.
// It will emit 'error' message as well (with ECONNRESET code).
req.abort();
if(timeout) return timeout( new Error('request timed out') );
});
self.requestUrl = (this.ssl?'https':'http') + '://' + request._headers['host'] + request.path;
if(self.debug) {
console.log("SimpleAPI.Post",self.requestUrl);
}
request.end();
} //RequestGet
/**
* HTTP POST
* #author Loreto Parisi (loretoparisi at gmail dot com)
*/
SimpleAPI.prototype.Post = function(path, headers, params, body, success, error, timeout) {
var self=this;
if(params) {
var queryString=qs.stringify(params);
if( queryString ) {
path+="?"+queryString;
}
}
var bodyString=JSON.stringify(body)
var _headers = {
'Content-Length': Buffer.byteLength(bodyString)
};
for (var attrname in headers) { _headers[attrname] = headers[attrname]; }
var options = {
headers : _headers,
hostname: this.host,
path: path,
method: 'POST',
qs : qs.stringify(params)
};
if(this.port && this.port!='80') { // port only if ! 80
options['port']=this.port;
}
if(self.debug) {
console.log( "SimpleAPI.Post\n%s\n%s", JSON.stringify(_headers,null,2), JSON.stringify(options,null,2) );
}
if(self.debug) {
console.log("SimpleAPI.Post body\n%s", JSON.stringify(body,null,2) );
}
var request=this.http.request(options, function(response) {
if(self.debug) { // debug
console.log( JSON.stringify(response.headers) );
}
// Continuously update stream with data
var body = '';
response.on('data', function(d) {
body += d;
});
response.on('end', function() {
try {
console.log("END", body);
var jsonResponse=JSON.parse(body);
if(success) return success( jsonResponse );
} catch(ex) { // bad json
if(error) return error(ex.toString());
}
});
});
request.on('socket', function (socket) {
socket.setTimeout( self.timeout );
socket.on('timeout', function() {
request.abort();
if(timeout) return timeout( new Error('request timed out') );
});
});
request.on('error', function (e) {
// General error, i.e.
// - ECONNRESET - server closed the socket unexpectedly
// - ECONNREFUSED - server did not listen
// - HPE_INVALID_VERSION
// - HPE_INVALID_STATUS
// - ... (other HPE_* codes) - server returned garbage
console.log(e);
if(error) return error(e);
});
request.on('timeout', function () {
// Timeout happend. Server received request, but not handled it
// (i.e. doesn't send any response or it took to long).
// You don't know what happend.
// It will emit 'error' message as well (with ECONNRESET code).
req.abort();
if(timeout) return timeout( new Error('request timed out') );
});
self.requestUrl = (this.ssl?'https':'http') + '://' + request._headers['host'] + request.path;
if(self.debug) {
console.log("SimpleAPI.Post",self.requestUrl);
}
request.write( bodyString );
request.end();
} //RequestPost
return SimpleAPI;
})();
module.exports = SimpleAPI
}).call(this);
Usage:
// Parameters
// domain: example.com
// ssl:true, port:80
// timeout: 30 secs
// debug: true
// json response:true
var api = new SimpleAPI('posttestserver.com', 80, 1000 * 10, true, true, true);
var headers = {
'Content-Type' : 'application/json',
'Accept' : 'application/json'
};
var params = {
"dir" : "post-test"
};
var method = 'post.php';
api.Post(method, headers, params, body
, function(response) { // success
console.log( response );
}
, function(error) { // error
console.log( error.toString() );
}
, function(error) { // timeout
console.log( new Error('timeout error') );
});
I found a video which explains on how to achieve this: https://www.youtube.com/watch?v=nuw48-u3Yrg
It uses default "http" module together with "querystring" and "stringbuilder" modules. The application takes two numbers (using two textboxes) from a web page and upon submit, returns sum of those two (along with persisting the values in the textboxes). This is the best example I could find anywhere else.
var http = require("http");
var qs = require("querystring");
var StringBuilder = require("stringbuilder");
var port = 9000;
function getCalcHtml(req, resp, data) {
var sb = new StringBuilder({ newline: "\r\n" });
sb.appendLine("<html>");
sb.appendLine(" <body>");
sb.appendLine(" <form method='post'>");
sb.appendLine(" <table>");
sb.appendLine(" <tr>");
sb.appendLine(" <td>Enter First No: </td>");
if (data && data.txtFirstNo) {
sb.appendLine(" <td><input type='text' id='txtFirstNo' name='txtFirstNo' value='{0}'/></td>", data.txtFirstNo);
}
else {
sb.appendLine(" <td><input type='text' id='txtFirstNo' name='txtFirstNo' /></td>");
}
sb.appendLine(" </tr>");
sb.appendLine(" <tr>");
sb.appendLine(" <td>Enter Second No: </td>");
if (data && data.txtSecondNo) {
sb.appendLine(" <td><input type='text' id='txtSecondNo' name='txtSecondNo' value='{0}'/></td>", data.txtSecondNo);
}
else {
sb.appendLine(" <td><input type='text' id='txtSecondNo' name='txtSecondNo' /></td>");
}
sb.appendLine(" </tr>");
sb.appendLine(" <tr>");
sb.appendLine(" <td><input type='submit' value='Calculate' /></td>");
sb.appendLine(" </tr>");
if (data && data.txtFirstNo && data.txtSecondNo) {
var sum = parseInt(data.txtFirstNo) + parseInt(data.txtSecondNo);
sb.appendLine(" <tr>");
sb.appendLine(" <td>Sum: {0}</td>", sum);
sb.appendLine(" </tr>");
}
sb.appendLine(" </table>");
sb.appendLine(" </form>")
sb.appendLine(" </body>");
sb.appendLine("</html>");
sb.build(function (err, result) {
resp.write(result);
resp.end();
});
}
function getCalcForm(req, resp, data) {
resp.writeHead(200, { "Content-Type": "text/html" });
getCalcHtml(req, resp, data);
}
function getHome(req, resp) {
resp.writeHead(200, { "Content-Type": "text/html" });
resp.write("<html><html><head><title>Home</title></head><body>Want to some calculation? Click <a href='/calc'>here</a></body></html>");
resp.end();
}
function get404(req, resp) {
resp.writeHead(404, "Resource Not Found", { "Content-Type": "text/html" });
resp.write("<html><html><head><title>404</title></head><body>404: Resource not found. Go to <a href='/'>Home</a></body></html>");
resp.end();
}
function get405(req, resp) {
resp.writeHead(405, "Method not supported", { "Content-Type": "text/html" });
resp.write("<html><html><head><title>405</title></head><body>405: Method not supported</body></html>");
resp.end();
}
http.createServer(function (req, resp) {
switch (req.method) {
case "GET":
if (req.url === "/") {
getHome(req, resp);
}
else if (req.url === "/calc") {
getCalcForm(req, resp);
}
else {
get404(req, resp);
}
break;
case "POST":
if (req.url === "/calc") {
var reqBody = '';
req.on('data', function (data) {
reqBody += data;
if (reqBody.length > 1e7) { //10MB
resp.writeHead(413, 'Request Entity Too Large', { 'Content-Type': 'text/html' });
resp.end('<!doctype html><html><head><title>413</title></head><body>413: Request Entity Too Large</body></html>');
}
});
req.on('end', function () {
var formData = qs.parse(reqBody);
getCalcForm(req, resp, formData);
});
}
else {
get404(req, resp);
}
break;
default:
get405(req, resp);
break;
}
}).listen(port);
After struggling a lot while creating a low level utility to handle the post and get requests for my project, I decided to post my effort here. Much on the lines of accepted answer, here is a snippet for making http and https POST requests for sending JSON data.
const http = require("http")
const https = require("https")
// Request handler function
let postJSON = (options, postData, callback) => {
// Serializing JSON
post_data = JSON.stringify(postData)
let port = options.port == 443 ? https : http
// Callback function for the request
let req = port.request(options, (res) => {
let output = ''
res.setEncoding('utf8')
// Listener to receive data
res.on('data', (chunk) => {
output += chunk
});
// Listener for intializing callback after receiving complete response
res.on('end', () => {
let obj = JSON.parse(output)
callback(res.statusCode, obj)
});
});
// Handle any errors occurred while making request
req.on('error', (err) => {
//res.send('error: ' + err.message)
});
// Request is made here, with data as string or buffer
req.write(post_data)
// Ending the request
req.end()
};
let callPost = () => {
let data = {
'name': 'Jon',
'message': 'hello, world'
}
let options = {
host: 'domain.name', // Your domain name
port: 443, // 443 for https and 80 for http
path: '/path/to/resource', // Path for the request
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(data)
}
}
postJSON(options, data, (statusCode, result) => {
// Handle response
// Process the received data
});
}
Axios is a promise based HTTP client for the browser and Node.js. Axios makes it easy to send asynchronous HTTP requests to REST endpoints and perform CRUD operations. It can be used in plain JavaScript or with a library such as Vue or React.
const axios = require('axios');
var dataToPost = {
email: "your email",
password: "your password"
};
let axiosConfiguration = {
headers: {
'Content-Type': 'application/json;charset=UTF-8',
"Access-Control-Allow-Origin": "*",
}
};
axios.post('endpoint or url', dataToPost, axiosConfiguration)
.then((res) => {
console.log("Response: ", res);
})
.catch((err) => {
console.log("error: ", err);
})
let request = require('request');
let jsonObj = {};
request({
url: "https://myapii.com/sendJsonData",
method: "POST",
json: true,
body: jsonObj
}, function (error, resp, body){
console.log(resp);
});
Or you could use this library:
let axios = require("axios");
let jsonObj = {};
const myJsonAPI = axios.create({
baseURL: 'https://myapii.com',
timeout: 120*1000
});
let response = await myJsonAPI.post("sendJsonData",jsonobj).catch(e=>{
res.json(e);
});
console.log(response);
Posting another axios example of an axios.post request that uses additional configuration options and custom headers.
var postData = {
email: "test#test.com",
password: "password"
};
let axiosConfig = {
headers: {
'Content-Type': 'application/json;charset=UTF-8',
"Access-Control-Allow-Origin": "*",
}
};
axios.post('http://<host>:<port>/<path>', postData, axiosConfig)
.then((res) => {
console.log("RESPONSE RECEIVED: ", res);
})
.catch((err) => {
console.log("AXIOS ERROR: ", err);
})
By using request dependency.
Simple solution :
import request from 'request'
var data = {
"host":"127.1.1.1",
"port":9008
}
request.post( baseUrl + '/peers/connect',
{
json: data, // your payload data placed here
headers: {
'X-Api-Key': 'dajzmj6gfuzmbfnhamsbuxivc', // if authentication needed
'Content-Type': 'application/json'
}
}, function (error, response, body) {
if (error) {
callback(error, null)
} else {
callback(error, response.body)
}
});
Request-Promise Provides promise based response.
http response codes other than 2xx will cause the promise to be rejected. This can be overwritten by setting options.simple = false
var options = {
method: 'POST',
uri: 'http://api.posttestserver.com/post',
body: {
some: 'payload'
},
json: true // Automatically stringifies the body to JSON
};
rp(options)
.then(function (parsedBody) {
// POST succeeded...
})
.catch(function (err) {
// POST failed...
});
In case you need an XML request I'll share my codes with axios library.
const {default: axios} = require('axios');
let xmlString = '<XML>...</XML>';
axios.post('yourURL', xmlString)
.then((res) => {
console.log("Status: ", res.status);
console.log("Body: ", res.data);
})
.catch((err) => {
console.error("Error: ", err);
});
Make arbitrary HTTP requests with the Node.js http library.
Don't use third-party packages that don't provide any new functionality.
Use the Node.js built-ins.
https://nodejs.org/api/http.html#httprequesturl-options-callback
The example from the documentation for http.request shows you how to make a "hello world" POST request.
Here is the example. Ask questions in the comments, e.g., if you are learning Node.js and want more resources.
const http = require('node:http');
const postData = JSON.stringify({
'msg': 'Hello World!',
});
const options = {
hostname: 'www.google.com',
port: 80,
path: '/upload',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(postData),
},
};
const req = http.request(options, (res) => {
console.log(`STATUS: ${res.statusCode}`);
console.log(`HEADERS: ${JSON.stringify(res.headers)}`);
res.setEncoding('utf8');
res.on('data', (chunk) => {
console.log(`BODY: ${chunk}`);
});
res.on('end', () => {
console.log('No more data in response.');
});
});
req.on('error', (e) => {
console.error(`problem with request: ${e.message}`);
});
// Write data to request body
req.write(postData);
req.end();
~
~
~

Resources