Nodejs webhook server on local machine - javascript

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 ?

Related

Heroku basic http request

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.

Connection to nodejs (express) refused

I’m a long term programmer, but haven’t used nodejs much in my code. Now I need to use it in my current code and I’ve ran into a problem that I can’t seem to figure out myself, I have googled a lot but nothing seem to fix it.
I am trying to get my website to connect to the nodejs server running on same host.
If I visit the url in my browser, it works fine (http://localhost:6857/socket.io/?EIO=4&transport=polling) and I see this respond
0{"sid":"s_v860SbNO4toknPAAAA","upgrades":["websocket"],"pingInterval":25000,"pingTimeout":20000}
But when I try to connect thru the website, I just get
GET http://localhost:6857/socket.io/?EIO=3&transport=polling&t=N_gL_HZ net::ERR_CONNECTION_REFUSED
Can someone guide my in the right direction for how to fix this, so I can begin using nodejs inside my website?
This is my server.js
// use express
var express = require("express");
// create instance of express
var app = express();
// use http with instance of express
var http = require("http").createServer(app);
// start the server
var port = 6857;
http.listen(port, '0.0.0.0', function () {
console.log("Listening to port " + port);
});
// create socket instance with http
var io = require("socket.io")(http);
// add listener for new connection
io.on("connection", function (socket) {
// this is socket for each user
console.log("User connected", socket.id);
});
io.on("connect_error", (err) => {
console.log(`connect_error due to ${err.message}`);
});
And this is my JS code inside my website
<script>
var server = "http://localhost:6857/";
var io = io(server);
</script>
Socket IO requires you to enable CORS explicitly - Thus why you get the error stated above.
To enable CORS, please see the following link

Can't send POST request from React front-end to Node.js back-end

I have a simple node.js portfolio page built with which includes a contact page that I use a third-party API to send emails with (sendgrid). The information for the sendgrid API query is saved to sendgridObjand I make a POST request with it to my server at server.js upon submitting the contact form.
//CONTACT.JS PAGE
emailApi = () => {
let sendgridObj = {
to: 'caseyclinga#gmail.com',
from: this.state.from,
subject: this.state.subject,
text: this.state.text
}
this.resetState();
axios.post('/contact', sendgridObj)
.then(res => console.log(`CONTACT.JS RESPONSE: ${res}`))
.catch(err => console.log(`CONTACT.JS ERROR: ${err}`));
}
On the backend, I set up my route for /contact and make a POST request with the sendgridObj to sendgrid mail.
//SERVER.JS FILE
const express = require('express');
var app = express();
const SgMail = require('#sendgrid/mail');
const path = require('path');
SgMail.setApiKey(process.env.REACT_APP_SENDGRID_API_KEY);
//Middleware stuff
app.post('/contact', (req, res) => {
console.log(req.body)
SgMail.send(req.body)
.then(res => console.log(JSON.stringify(res, null, 2)))
.catch(err => console.log(`SERVER.JS ERROR: ${err}`));
});
app.listen(PORT, () => console.log(`Server running on port ${PORT}`))
All relatively straight forward stuff. This was all working well until a few days ago when it inexplicably stopped funcitoning. When I run console.log(req.body) on my back-end, it shows the object I sent so it's not an issue with the req.body. It's also not an issue with my API key and I receive a 202 in the response object from Sendgrid (catches no errors).
However, about 45 seconds or so after submitting the contact form, the front end catches a 500 error POST http://localhost:3000/contact 500 (Internal Server Error).
Then I noticed if I reset my server, I get a proxy error on my backend Proxy error: Could not proxy request /contact from localhost:3000 to http://localhost:5000/.
So it seems like I have an issue with my routes or somehow with sending the request to Sendgrid but I'm completely confused as to why. I can console log the query object to show it's being sent to the backend and then I get a 202 response but still I am getting an error? If it could not proxy my request, then why was the object still sent?
Here is my whole code: https://github.com/caseycling/portfolio
You should create baseURL for both on backend and frontend. Example:
const instance = axios.create({
baseURL: 'https://some-domain.com/api/',
timeout: 1000,
headers: {'X-Custom-Header': 'foobar'}
});
Then, you should use the created instance to get or post for integrating with backend.
Seem like your react server and your node js server is running in different port.
2 thing you need to handle is:
Specify full baseURL to node js backend
Add cors config for node js and run
npm install cors
Then add this in your node.js code
var cors = require('cors')
var app = express()
app.use(cors())

Use Express server to control a nodejs application

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

Need to acces Client IP not the server IP for a weather API

I want to create a server-side app using node.js with express. At the moment I am able to get the json document with the location and temperature but after I used pykite to get it online the application would only get the server location to the one who is accessing it. Here is the code in its current form:
var express = require('express');
var app = express();
var request = require('request');
app.get('/api/weather/current_temperature', function (req, res) {
request('http://api.wunderground.com/api/ebb3e0cf5059cce8/conditions/q/autoip.json', function(error, response, body){
if (!error && response.statusCode==200){
res.setHeader('Content-Type', 'aplication/json');
var result = JSON.parse(body);
res.json({ "location": result.current_observation.observation_location.city,"temperature": result.current_observation.temp_c });
}else{
console.log(error, response.statusCode, body);
}
res.end("")
});
});
var server = app.listen(3000, function () {
var host = server.address().address;
var port = server.address().port;
console.log('The app is up.');
});
I admit I'm new to this but I wanna learn. I would like some help implementing it in this code, if it's possible, a way to access the user's location and determine the weather at his/her location.
Thank you in advance.
P.S.: I would also like some links into some documentation, don't wanna skip anything.
The URL you are linking to http://api.wunderground.com/api/YOUR_KEY/conditions/q/autoip.json (which doesn't work because you didn't provide your key) has autoip in the name.
That implies that it will return a result from whatever IP address the request came from.
So you have two options:
Don't make the request from NodeJS. Make the request from the browser. (This probably isn't advisable given the use of an API key and might run into Same Origin Policy issues).
Find a different API (possibly one from the same site) that lets you specify what IP address or location to use.

Categories