How to link Node.js Post script to HTML form? - html

I have created a REST full APi, which works as I would be expecting if I am running Postman. I run the Test from an index.js file which would have the routes saved as per below file.
const config = require('config');
const mongoose = require('mongoose');
const users = require('./routes/users');
const auth = require('./routes/auth');
const express = require('express');
const app = express();
//mongoose.set();
if (!config.get('jwtPrivateKey'))
{
console.log('Fatal ERRORR: jwtPrivateKey key is not defined')
process.exit(1);
}
mongoose.connect(uri ,{
useNewUrlParser: true,
useUnifiedTopology: true,
useCreateIndex: true
})
.then(()=>console.log('Connected to MongoDB...'))
.catch(err=> console.log('Not Connected, bad ;(', err));
app.use(express.json());
//THis is only for posting the user, e.g. Registering them
app.use('/api/users', users);
app.use('/api/auth', auth);
const port = process.env.PORT || 3000;
app.listen(port, () => console.log(`Listening on port ${port}...`));
The real code is happening here. Testing this in Postmon I could establish, that the values are saved in MongoDB.
router.post('/', async (req, res) => {
//validates the request.
const { error } = validate(req.body);
if (error) return res.status(400).send(error.details[0].message);
let user = await User.findOne({email: req.body.email});
if (user) return res.status(400).send('User Already Register, try again!');
user = new User(_.pick(req.body, ['firstName','lastName','email','password','subscription']));
const salt = await bcrypt.genSaltSync(15);
user.password = await bcrypt.hash(user.password, salt);
//Here the user is being saved in the Database.
await user.save();
//const token = user.generateAuthToken();
//const token = jwt.sign({_id: user._id}, config.get('jwtPrivateKey'));
const token = user.generateAuthToken();
//We are sending the authentication in the header, and the infromation back to client
res.header('x-auth-token',token).send( _.pick(user, ['_id','firstName','lastName','email','subscription']));
});
Now my question's are:
How can I call the second code block from a , in one particular html file. When using Action="path to the users.js", the browser opens the js file code but doesn't do anything.
Do I need to rewrite the Post block part so that it would as well include the connection details to the DB? And would this mean I would keep open the connection to MongoDB once I insert Read etc.? Wouldn't this eat a lot of resources if multiple users would e.g. log in at the same time?
Or is there a way how I can use the index.js + the users.js which is refereed in the index.js file together?
All of these are theoretical questions, as I am not quite sure how to use the created API in html, then I created as walking through a tutorial.
Do I need to change the approach here?

After some longs hours I finally understood my own issue and question.
What I wanted to achieve is from an HTML page post data in MongoDB through API (this I assume is the best way how to describe this).
In order to do this I needed to:
Start server for the API function e.g. nodemon index.js, which has the information regarding the API.
Opened VS Code opened the terminal and started the API server (if I can call it like that)
Opened CMD and startet the local host for the index.html with navigating to it's folder and then writting http-server now I could access this on http://127.0.0.1:8080.
For the register.html in the form I needed to post:
This is the part which I didn't understood, but now it makes sense. Basically I start the server API seperatly and once it is started I can use e.g. Postmon and other apps which can access this link. I somehow thought html needs some more direct calls.
So After the localhost is started then the register.html will know where to post it via API.
Now I have a JOI validate issue, though on a different more simple case this worked, so I just need to fix the code there.
Thank You For reading through and Apologize if was not clear, still learning the terminology!

Related

How to execute HTML-Events with NodeJS?

I need the Nodejs-fileserver for saving some text but I want to do this with a website written in html.
How can I do something like this?
Here is an example but there only comes the failure: 'book() isn't defined'.
const http = require('http');
const fs = require('fs');
http.createServer( function (req, res) {
res.writeHead(200,{'Content-Type': 'text/html'})
res.write('<meta charset="utf-8">');
res.write('<button onclick="book(this)">Buchen</button>');
res.end();
}).listen(8080);
function book(sender)
fs.appendFile('test.csv',sender, function (err) {
if (err) {throw err};
console.log("Schreiben erfolgreich");
});
}
When I connect the nodejs file with the script tag, can I handle the code of the html file?
<script src="server.js"></script>
How can I execute the nodejs book() function with the html button?
You might need to read this answer first. Due to JavaScript, a single language on both client and server side, it might cause some confusion when you start with Node.js.
But, that doesn't mean you can't perform operations onClick from HTML. You surely can do it using Ajax or form submit. I would also suggest you to use Express.js framework.
Also, you can't include the file like this -
<script src="server.js"></script>
Because it's not a client-side normal JavaScript file even though it has .js extension. It is a server-side file.
Talking about example, you can do something like this -
const express = require('express');
const app = express();
app.set('view engine', 'ejs');
app.get('/book', function(req, res) {
res.render('index');
});
When you visit /book route, it'll open an index view which might have a form to submit. Then you can write code within /post POST url to do further modification.
app.post('/book', function(req, res) {
// req.body will have submitted form data.
// You can then do modification.
// You need to use body-parser.
});

Slack webhooks cause cls-hooked request context to orphan mysql connections

The main issue:
We have a lovely little express app, which has been crushing it for months with no issues. We manage our DB connections by opening a connection on demand, but then caching it "per request" using the cls-hooked library. Upon the request ending, we release the connection so our connection pool doesn't run out. Classic. Over the course of months and many connections, we've never "leaked" connections. Until now! Enter... slack! We are using the slack event handler as follows:
app.use('/webhooks/slack', slackEventHandler.expressMiddleware());
and we sort of think of it like any other request, however slack requests seem to play weirdly with our cls-hooked usage. For example, we use node-ts and nodemon to run our app locally (e.g. you change code, the app restarts automatically). Every time the app restarts locally on our dev machines, and you try and play with slack events, suddenly when our middleware that releases the connection tries to do so, it thinks there is nothing in session. When you then use a normal endpoint... it works fine and essentially seems to reset slack to working okay again. We are now scared to go to prod with our slack integration, because we're worried our slack "requests" are going to starve our connection pool.
Background
Relevant subset of our package.json:
{
"#slack/events-api": "^2.3.2",
"#slack/web-api": "^5.8.0",
"express": "~4.16.1",
"cls-hooked": "^4.2.2",
"mysql2": "^2.0.0",
}
The middleware that makes the cls-hooked session
import { session } from '../db';
const context = (req, res, next) => {
session.run(() => {
session.bindEmitter(req);
session.bindEmitter(res);
next();
});
};
export default context;
The middleware that releases our connections
export const dbReleaseMiddleware = async (req, res, next) => {
res.on('finish', async () => {
const conn = session.get('conn');
if (conn) {
incrementConnsReleased();
await conn.release();
}
});
next();
};
the code that creates the connection on demand and stores it in "session"
const poolConn = await pool.getConnection();
if (session.active) {
session.set('conn', poolConn);
}
return poolConn;
the code that sets up the session in the first place
export const session = clsHooked.createNamespace('our_company_name');
If you got this far, congrats. Any help appreciated!
Side note: you couldn't pay me to write a more confusing title...
Figured it out! It seems we have identified the following behavior in the node version of slack's API (seems to only happen on mac computers... sometimes)
The issue is that this is in the context of an express app, so Slack is managing the interface between its own event handler system + the http side of things with express (e.g. returning 200, or 500, or whatever). So what seems to happen is...
// you have some slack event handler
slackEventHandler.on('message', async (rawEvent: any) => {
const i = 0;
i = i + 1;
// at this point, the http request has not returned 200, it is "pending" from express's POV
await myService.someMethod();
// ^^ while this was doing its async thing, the express request returned 200.
// so things like res.on('finished') all fired and all your middleware happened
// but your event handler code is still going
});
So we ended up creating a manual call to release connections in our slack event handlers. Weird!

Can nodejs be use on a static website for form submission?

I have this website that right now has a home page and a contact page. The page navigation is done through HTML and href links.
I have also made a server with node.js to handle the form submission on the contact page. It is using express, nodemailer, nodemailer-mailgun-transport for that.
I have been able to get the form submission to work running the node server.js command and going to localhost on my computer. It submits and sends it to my email just fine.
What I am running into, is how can I have that working when I just navigate to my contact page and not using the node command to run the server?
Anything will help.
Several ways you can go about that ...
you have a static HTML page that you want to process form submissions in a NodeJs application
There are 2 smart ways to accomplish such idea
1. You host a NodeJs application
by making use of the express.static(), for example:
server.js
const express = require('express');
const bodyParser = require('body-parser');
const engine = require('./engine');
const app = express();
const PORT = process.env.PORT || 3001;
app.use('/', express.static('public'));
app.use(bodyParser.urlencoded({ extended: true }));
app.get('/api', async (req, res) => {
res.json(await engine.processForm(req.body));
});
app.listen(PORT, () => {
console.log(`ready on http://localhost:${PORT}`);
});
and your engine.js
exports.processForm = formData => {
// process form...
return { message: 'Email sent', error: null };
};
in this particular example, you should have a directory called public with an index.html file that would contain your form and in that form, upon submission, you could have something like:
<script>
$( "#contactForm" ).submit(function( evt ) {
alert( "Handler for .submit() called." );
evt.preventDefault();
$.post( "/api", $(this).serialize(), function( data ) {
$( ".result" ).html( data.response );
});
});
</script>
You will need to HOST the whole project in a hosting environment that can process NodeJs applications, like Heroku.
2. use Cloud functions, like Google Cloud or AWS Lambda
where you write your NodeJs application as a function, and you will have an HTTP Endpoint to run that function, and you simply add to your form
<form action="https://your.endpoint.com/abcd123" ... >...</form>
either Google Cloud, Azure Functions or AWS Lambda can help you with that
No. Node.js is server-side software: you can't embed it in static webpages.
If you mean "used on a static website" as running the code on the frontend, you can't. What you can do is, if you have a node.js server hosted elsewhere, you can send the form data to this server through a request.
If you want a node.js server only for handling form submissions, it might be a good idea to consider using Cloud Functions.
There is this tutorial on medium that might interest you.

Raspberry PI server - GPIO ports status JSON response

I'm struggling for a couple of days. Question is simple, is there a way that can I create a server on Raspberry PI that will return current status of GPIO ports in JSON format?
Example:
Http://192.168.1.109:3000/led
{
"Name": "green led",
"Status": "on"
}
I found Adafruit gpio-stream library useful but don't know how to send data to JSON format.
Thank you
There are a variety of libraries for gpio interaction for node.js. One issue is that you might need to run it as root to have access to gpio, unless you can adjust the read access for those devices. This is supposed to be fixed in the latest version of rasbian though.
I recently built a node.js application that was triggered from a motion sensor, in order to activate the screen (and deactivate it after a period of time). I tried various gpio libraries but the one that I ended up using was "onoff" https://www.npmjs.com/package/onoff mainly because it seemed to use an appropriate way to identify changes on the GPIO pins (using interrupts).
Now, you say that you want to send data, but you don't specify how that is supposed to happen. If we use the example that you want to send data using a POST request via HTTP, and send the JSON as body, that would mean that you would initialize the GPIO pins that you have connected, and then attach event handlers for them (to listen for changes).
Upon a change, you would invoke the http request and serialize the JSON from a javascript object (there are libraries that would take care of this as well). You would need to keep a name reference yourself since you only address the GPIO pins by number.
Example:
var GPIO = require('onoff').Gpio;
var request = require('request');
var x = new GPIO(4, 'in', 'both');
function exit() {
x.unexport();
}
x.watch(function (err, value) {
if (err) {
console.error(err);
return;
}
request({
uri: 'http://example.org/',
method: 'POST',
json: true,
body: { x: value } // This is the actual JSON data that you are sending
}, function () {
// this is the callback from when the request is finished
});
});
process.on('SIGINT', exit);
I'm using the npm modules onoff and request. request is used for simplifying the JSON serialization over a http request.
As you can see, I only set up one GPIO here. If you need to track multiple, you must make sure to initialize them all, distinguish them with some sort of name and also remember to unexport them in the exit callback. Not sure what happens if you don't do it, but you might lock it for other processes.
Thank You, this was very helpful. I did not express myself well, sorry for that. I don't want to send data (for now) i just want to enter web address like 192.168.1.109/led and receive json response. This is what I manage to do for now. I don't know if this is the right way. PLS can you review this or suggest better method..
var http = require('http');
var url = require('url');
var Gpio = require('onoff').Gpio;
var led = new Gpio(23, 'out');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
var command = url.parse(req.url).pathname.slice(1);
switch(command) {
case "on":
//led.writeSync(1);
var x = led.readSync();
res.write(JSON.stringify({ msgId: x }));
//res.end("It's ON");
res.end();
break;
case "off":
led.writeSync(0);
res.end("It's OFF");
break;
default:
res.end('Hello? yes, this is pi!');
}
}).listen(8080);

node.js code to open a page in browser with localhost URL

I have written a simple server using node.js. At the moment the server responds by writing "hello world" to the browser.
The server.js file looks like this:
var http = require("http");
http.createServer(function(request, response) {
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("Hello World");
response.end();
}).listen(8080);
I use this URL in the browser to trigger the "hello world" response:
http://localhost:8080/
I want to be able to open a basic html page when I pass a URL like this:
http://localhost:8080/test.html
I have looked through many tutorials and some stackoverflow posts but there was not much out there on this specific task. Does anyone know how to achieve this with a simple modification to the server.js file?
If you wish to open .html file through nodejs with the help of "http://localhost:8080/test.html" such url, you need to convert .html page to .jade format.Use rendering engine with the help of expressjs framework.Express rendering engine will help you to render .jade file on nodejs server.
It is better to use a front end javascript frameworks such as Angular, React or Vue to route to different pages. Though, if you want to do it in Node, you could do something like this using express:
var express = require('express');
var app = express();
app.get('/', function(req, res) {
res.sendFile('views/index.html', { root: __dirname })
});
app.get('/test', function(req, res) {
res.sendFile('views/test.html', { root: __dirname })
});
app.listen(8080);
This is an ok solution for static pages. Express is very useful for writing REST API's.