I have a node.js application which I use to interact with a REST API provided by another server. I would like to expose a web interface (html + css + javascript) using express.js in order to control the first application.
How can I let the browser talk to the server and let it make node.js actions like using http from that machine or writing to its filesystem? I tried using XMLHttpRequest, but HTTP requests are sent by my local PC instead of from my server.
The only solution I found is using XMLHttpRequest in the javascript of my web interface to invoke some middleware functions on my server, but I had some problems: when I make POST requests, I cannot read data from server. I used FormData and its append method to make the "body" of the POST request, then used body-parser in express to read that body, but it turns out to be always empty. Also tried changing the 'Content-Type' of the header.
Any suggestions? Any better solution than mine (I think it is not efficient)?
As pointed by Jonas, using node server as proxy would be the right approach.
I'm providing sample code for both frontend as well as backend app. Hope this helps you.
Frontend App Code
<html>
<head>
<script type="text/javascript">
function sendData(data) {
if (!data) {
// lets define some dummy data for testing
data = { somekey: "somevalue", anotherkey: "anothervalues" };
}
var XHR = new XMLHttpRequest();
var FD = new FormData();
// Push our data into our FormData object
for (name in data) {
FD.append(name, data[name]);
}
// Define what happens on successful data submission
XHR.addEventListener("load", function(event) {
alert("Yeah! Data sent and response loaded.");
alert(event.target.responseText);
});
// Define what happens in case of error
XHR.addEventListener("error", function(event) {
alert("Oops! Something went wrong.");
});
// Set up our request
XHR.open("POST", "http://path/to/your/nodejs/server/app");
// Send our FormData object; HTTP headers are set automatically
XHR.send(FD);
}
</script>
</head>
<body>
<button onclick="sendData()">Send Test Request to the Server</button>
</body>
</html>
Backend App code
const http = require('http');
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
app.use(bodyParser.urlencoded({ extended: false }));
app.get('/', (req, res) => res.send('Yeah! Server is UP! Post some data'));
app.post('/', (req, res) => {
// You'll see the posted data in req.body, simply for testing purpose return it back to the calling user
res.json(req.body || {});
});
const server = http.createServer(app);
server.listen(3000);
server.on('error', console.error);
server.on('listening', () => console.log('Listening on 3000'));
process.on('exit', (code) => console.warn('Server terminated with code=' + code));
Please note that for this backend app to run, you must have installed following npm packages: express, body-parser
Related
I am trying to setup a very simple nodeJS HTTP server. When I call it from the browser, like this http://localhost:8081, it works fine, but when I call is using a JS fetch() method, I get a 404 error:
GET http://localhost/:8081?q=hi
JS:
fetch(":8081/?q=hi")
NODE JS:
const requestListener = function (req, res) {
res.writeHead(200);
res.end('Hello, World!');
}
const server = http.createServer(requestListener);
server.listen(8081);
Every thing is fine, you just need to enable cors that's it, use the below code
const http = require('http')
const requestListener = function (req, res) {
const headers = {
'Access-Control-Allow-Origin': '*', /* #dev First, read about security */
'Access-Control-Allow-Methods': 'OPTIONS, POST, GET',
'Access-Control-Max-Age': 2592000, // 30 days
/** add other headers as per requirement */
};
res.writeHead(200, headers);
res.end(JSON.stringify({"key":"value"}));
}
const server = http.createServer(requestListener);
server.listen(8081);
If you are running both frontend and backend code on the same server then you donโt have to use complete url while if you are running fronted and backed on different server you need to enable cors and use complete url.
When you're calling your local server through JS fetch, you don't need to add the port number you can call it like below:
fetch('/?q=hi')
the URL handed to fetch function looks wronge, it would work if you adjust it to:
fetch('http://localhost:8081/?q=hi');
// or
fetch('/?q=hi');
it should work just fine,
and ensure that you enable the cors if you need to works from any domain
I am a beginner and been playing around with some js code.
First I would like to know what this line of code exactly does. Let's assume n is some variable. My understanding was, that it sends a http request to herokuapp with the data of interest "n". How is that data incorporated?
const Http = new XMLHttpRequest();
const url='https://myapp.herokuapp.com/?data='+n;
Http.open("GET", url);
Http.send();
What is the most simple way to accept and log the data n in my heroku app?
Thanks in advance!
The code above sends a HTTP GET request to the application running at myapp.herokuapp.com passing a parameter called data with whatever value the variable n holds.
On Heroku typically you deploy an application (service) than can listen and process HTTP requests. You can use any language (JS, Python, Java, etc..) since they all are suitable to implement a web service.
Using NodeJS you would do something like:
const express = require('express');
const app = express();
app.get('/', (req, res) => {
const data = req.query.data // grab parameter
console.log(`Value of data is ${data}`);
res
.status(200)
.send('Ok')
.end();
});
// Start the server
const PORT = process.env.PORT || 8080;
app.listen(PORT, () => {
console.log(`App listening on port ${PORT}`);
});
Checkout NodeJS on Heroku to see how you setup and deploy a NodeJS application.
So I have this long confusion about creating webhook API for my local app. This project is for learning purpose only so I need to understand what is the difference between simple REST API and webhook, in terms of implementation. I know the difference in terms of working but I can't get the technical difference.
For example, when I use Firebase in my web app and use the real-time database to get the updated values on the client-side, it works seamlessly and I don't need to make the POST or GET call every second or minute. It gets updated instantaneously. I know they might not be using webhook as such but rather using web-socket to keep the connection open between a client web app.
Okay now back to the webhook on the local machine - How can I create my own webhook server where the client can hook to the endpoint and get updates automatically.
Let me share some code
WebHook NodeJS server
// Require express and body-parser
const express = require("express")
const bodyParser = require("body-parser")
// Initialize express and define a port
const app = express()
const PORT = 3000
// Tell express to use body-parser's JSON parsing
app.use(bodyParser.json())
// Start express on the defined port
app.listen(PORT, () => console.log(`๐ Server running on port ${PORT}`))
app.use(bodyParser.json())
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
if (req.method === 'OPTIONS') {
var headers = {};
// headers["Access-Control-Allow-Origin"] = req.headers.origin;
headers["Access-Control-Allow-Origin"] = "*";
headers["Access-Control-Allow-Methods"] = "POST, GET, PUT, DELETE, OPTIONS";
headers["Access-Control-Allow-Credentials"] = false;
headers["Access-Control-Max-Age"] = '86400'; // 24 hours
res.writeHead(200, headers);
res.end();
} else {
next();
}
})
const processSomething = callback => {
setTimeout(callback, 1000);
}
app.post("/hook", (req, res) => {
console.log(req.body) // Call your action on the request here
processSomething(() => {
res.status(200).send({
id: "ABC123",
message: "New record added!"
});
});
})
Web client running
index.html -
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Webhook Test Client</title>
</head>
<body>
<h1>Hello World</h1>
<div class="result">Data</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script>
$.post("http://localhost:3000/hook", function (data) {
console.log("data -- >",data);
$(".result").html("data -- > " + data);
});
</script>
</body>
</html>
nodejs to server the page -
const express = require('express'),
app = express(),
server = app.listen(1000);
app.use(express.static('public'));
console.log("server running...");
I have seen so many tutorials on Medium or other tech blogs but they mostly talk about connecting to webhook API hosted somewhere on a webserver that they have built as service or something.
So far I have understood and not understood is that.
I can't make webhook API call from the web client.
Only nodejs client-server can make webhook calls to the webhook endpoint. What I mean by this is - in my example webhook can't be called from HTML page but server serving that page can make the call. Maybe I am wrong.
Webhook is not so different from REST API.
Webhook is not made for the web client.
I will update this question as I get relevant replies and testing them.
Why I am interested in webhook because I wanted to create an API where the user doesn't have to make calls to an API to get an update but at the same time the API can be used from the web client, like firebase but avoid WebSocket at the same time. Or can I avoid WebSocket?
Edit: - So I got confirmation on webhooks are designed for server-to-server communication.
Most of the demos available online are using githud, discord, zapier, etc to create webhooks. Can you please share where we can just make custom webhooks without using third party libs ?
I recently started learning node.js with express framework and stumbled upon a problem.
I'm trying out a simple query search webapp and I want to pass a piece of data(a boolean called all)
from front-end plain javascript via ajax to the server side, but the current code
that I have written as of right now, it seems that my data was not passed to the server side,
the 3 console.log that I planted all return {}.
What concept am I missing here? What am I doing wrong?
If any additional info is needed, pls let me know, Thanks.
front end js
window.onload=function(){
console.log("window loaded");
const xhr = new XMLHttpRequest();
xhr.open("POST","http://127.0.0.1:3000/search", true);
xhr.onreadystatechange = function(){
if(xhr.readyState === 4 && xhr.status==200){
// code later to be implemented
}
}
let searchConditions = new SearchConditions(true);
console.log('data='+JSON.stringify(searchConditions));
xhr.send('data='+JSON.stringify(searchConditions));
}
class SearchConditions{
constructor(all) {
this.all = all;
}
}
backend node.js
// only partial code
const bodyParser = require("body-parser");
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(bodyParser.json());
app.post('/search', (req, res) => {
console.log(req.body);
console.log(req.query);
console.log(req.params);
});
my browser log
my backendlog
Because you send invalid data:
xhr.send('data='+JSON.stringify(searchConditions));
JSON Objects do not have variable declarations. What your Server gets is:
'data = {"all": true }'
This is not even a valid variable declaration.
What your server should get is:
{"all": true}
Try to send the plain JSON Object without a variable declaration and set the "Content-Type"-header to json:
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhr.send(JSON.stringify(searchConditions));
I'm currently teaching myself more about server code, specifically using Node.js and Express, and I'm having a lot of trouble with receiving and parsing a JSON object sent from a POST request. I have looked at numerous other posts (linked to below) and I can't figure out for the life of me what's going wrong. Here's what I've looked at:
Javascript: Send JSON Object with AJAX
Javascript : Send JSON Object with Ajax?
How do I consume the JSON POST data in an Express application
How do I consume the JSON POST data in an Express application
Send POST data using XMLHttpRequest
Send POST data using XMLHttpRequest
How do you extract POST data in Node.js?
How do you extract POST data in Node.js?
All of these are putting me on the right track, but I'm not quite there and thus looking for help. Here's the code I'm working with:
Send POST Request
var button = document.querySelector("#button");
button.onclick = function(){
console.log("Getting data from local server");
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://localhost:3000/data/test.json", true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.send(JSON.stringify({"latitude": 41.2418, "longitude": -70.8898}));
};
Handle POST Request In Server
var http = require("http");
var fs = require("fs");
var express = require("express");
var app = express();
var path = require("path");
var bodyParser = require("body-parser");
var port = process.env.PORT || 3000;
//tells express where to find all the static files (HTML, CSS, etc) and load them into the browser
app.use(express.static(path.join(__dirname, '../client')));
//tells the application to use body-parser as middleware so it can handle post requests
app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());
//routing methods
//deal with incoming GET and POST requests to the server
app.get("/", function(req, res){
res.send("Submitted GET Request");
})
//only handles incoming POST requests to the test.json resource
app.post("/data/test.json", function(req, res){
console.info("Submitting POST Request to Server");
console.info("Request body: " + req.body);
//write the file
fs.writeFile(__dirname + "/../client/data/test.json", req.body,
function(err){
if(err){
console.error(err); //print out the error in case there is one
return res.status(500).json(err);
}
//resolve the request with the client
console.info("updated test.json");
res.send();
});
})
//tell the express object to create the server and listen on the port
app.listen(port);
console.log("Listening on localhost:" + port);
Whenever I try to print out the contents of "req.body" I get the output of "[object Object]". Any ideas?
EDIT:
My issue has been solved. I have changed
console.info("Request body: " + req.body);
To
console.info("Request body: " + JSON.stringify(req.body));
I also changed my Content-Type in my POST XMLHTTPRequest to "application/json" to help with formatting.
"[object Object]" is the default result of JavaScript's implicit toString operation, which it uses when trying to write a string representation of that object to the file.
Try writing JSON.stringify(req.data) to the file instead.
Also, on the client side โ consider changing your Content-Type header to match:
xhr.setRequestHeader("Content-Type", "application/json");
If your post body is expected to be JSON, then change this line
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
To
xhr.setRequestHeader("Content-Type", "application/json");