What is the best way to connect react.js UI to my node.js API and mongoDB? - node.js

I'm working on my first project and would like to know if socket.io is the only or the best solution to connect my UI to node.
Is there anything else you could recommend me? Real-time is not important, I just want to access my data. Simple keywords would already help me a lot.
Thank you!
GT

It is pretty straightforward:
Make sure your node.js server returns (JSON) data on certain calls, e.g.
//this is your API endpoint
app.use('/api/endpoint', (req, res, next) => {
res.send({
key: 'value'
});
});
//this sends your html file with react bundle included
//has to be placed after the api handling
app.use('*', (req, res, next) => {
res.sendFile(path.join(__dirname, 'public', 'index.html'));
});
You don't have to serve your html with the same server, but it normally makes sense.
Now, you can make API calls inside your React app to fetch the data. I like to use axios (https://github.com/mzabriskie/axios), but you can make the calls however you want.
You should make the call and save it somehow, either in state or in your store if you use redux.
E.g.:
...
componentDidMount() {
axios.get('http://yourserver.com/api/endpoint')
.then(function (response) {
this.setState({
data: response.data
});
})
.catch(function (error) {
console.log(error);
});
}
...
Sending Data to your node server to store it in a DB is pretty similar.
Please note, that this is just a basic example, you will encounter some issues along the way, especially when you go to production, such as CSRF protection or JWT for securing your API. However, this should get you started!

Related

NodeJS/Express API real time notification with React frontend

I am trying to implement real time notifications. The current code looks something like:
exports.doFooBar = asyncHandler(async (req, res, next) => {
// doing something here
// ...................
const onlyAfewUsers = getUsersWhoShouldBeNotified();
// somehow notify the users that are in "onlyAfewUsers"
// ... something else
res.status(200).json({
status: "success",
message: "......"
});
});
The frontend is a react webapp that consumes this API. I've looked into socket.io and that seems like something that I can use in my case. But, how do I figure out how to "look"/"poll" for notifications on the React frontend?
Please explain a little more about the usecase.
Also tell you need to send the push notifications(Firebase messaging) or basic in app notification in navbar like stackoverflow.

Is all communication from frontend to backend done via routes?

I'm working on a vuejs/express fullstack web app, and I know you can specify endpoints on the server like:
app.get('/', function (req, res) {
res.send('GET request to the homepage')
})
Which you can then hit from the client to display the home page.
But I'm wondering what about when you don't need to go to a 'route'? For example, you just want to send some data from client to server to do some calculations and then send data back to the client - do you still specify an endpoint e.g /FunctionName and access it from the frontend in the same way or is there some other way to call a function in the backend?
This is the 'express' way to define endpoints (or routes), regardless if it will return an html page like the example you've specified, or do some computation by calling other functions with user-specified parameters.
As a basic example:
app.post('/myendpoint', function (req, res) {
returnValues = callMyFunction(req)
res.send(returnValues)
})

How do I redirect a failed login attempt in node-oidc-provider

I'm setting up an OpenID Connect Provider using node.js, express.js, and node-oidc-provider. I've been working my way through the examples at https://github.com/panva/node-oidc-provider-example/tree/master/03-oidc-views-accounts, but it never deals with a failed authentication. How do I redirect the user back to the login page if they mis-type their password?
expressApp.get('/interaction/:grant', async (req, res) => {
// The initial route hit by the client (Relying Party) that renders the login view if needed.
...
});
expressApp.post('/interaction/:grant/login', parse, (req, res, next) => {
User.authenticate(req.body.email, req.body.password)
.then((users) => {
// returns an array of user objects that match the credentials
if(!users.length)
{
// What now? I can't just redirect back to /interaction/:grant - I get session not found
}
// the rest works well enough (for now)....
...
}).catch(next);
});
Just like in any express app. Think of it this way. Only resolve the interactions with success, or error if you wish to exit the interactions and return control back to the client.
I tend to develop interactions separately and only plug them to oidc-provider when they’re done.

Is it bad practice to wrap express app within socketio connection?

I'm making a webgame, and if I have a route that looks like:
app.post('/create_account', (req, res) => {
var email = req.body.email
var pass = req.body.pass
res.json({response: "created"})
})
Anyone can post data to mywebsite.com/create_account using postman, or curl or something, and my website will start creating account for them even though they are not even on my webpage.
I found an interesting workaround, and I wanted to know if this is safe, or even a good idea. Basically I wrap my app routes within a socket.io connection:
io.on('connection', function(socket) {
app.post('/create_account', (req, res) => {
//code goes here
})
})
I tested it, and it seems that this way you can only post to /create_account if you are actually connected to the webpage.
What (if any) are the disadvantages to doing this? If this is a bad idea, whats's a better way to prevent people from posting data if they aren't on my site.
#Ruslan's suggestion about CSRF tokens is sound and probably your best option, wrapping everything in socket.io seems like too much complexity. Here's a library that does that: https://github.com/expressjs/csurf

Node Express API + Front-End

I'm coding my first "solo" nodejs webapp. Its based on a previous app (that I coded by following some kind of tutorial/course) which was an Express REST API that allows you to add/remove/update/list a Todo list. I've also implemented user authentication using jwt/bcrypt. All this is stored in a MongoDB database.
Also note that all the endpoints return JSON.
I'm now trying to add a front-end to the app. The API endpoints are at /api/endpoint1, /api/endpoint2, etc., and the views are rendered on /view1, /view2, etc. I'm doing this on purpose so that I can get the responses in plain JSON from the API, or show it in a webpage rendered.
I started by using jQuery's ajax to make the calls but I realized this was not the way I wanted to do this. I removed all the js scripts on my webpage and started working directly on the server, rendering the pages with the info fetched from the api.
This is what I have now:
server.js (main file) [sample]
// RENDER 'GET TODOs'
app.get('/todos', authenticate, (req, res) => {
let auth = req.cookies['x-auth'];
request({
url: 'http://localhost:3000/api/todos',
headers: {
'x-auth': auth
}
}, function (error, response, body) {
if (error || response.statusCode !== 200) {
return res.status(response.statusCode || 500).send('Error'); // TODO
}
let bodyJSON = JSON.parse(body);
res.render('todos', {
title: 'Todo App - Todos',
todos: bodyJSON.todos
});
});
});
// API endpoint to 'GET TODOs' (JSON)
app.get('/api/todos', authenticate, (req, res) => {
Todo.find({
_creator: req.user._id
}).then((todos) => {
res.send({todos});
}, (err) => {
res.status(400).send(err);
});
});
I don't know why, but all this looks weird to me. I'm wondering if this is how I'm supposed to do this. I mean, is this a good approach/practice on making a API+front-end node app ?
Also, I'm using an auth middleware twice: in the views and in the API itself. I guess this is OK?
It would probably be better to use React/Angular but this is such a small app and I just wanted to make a really simple front-end.
Just keep things simple.
If you go with server-side HTML rendering, you don't need a REST API, just drop it. You need an API in case of an ajax frontend or mobile app.
If you needed a combined approach (server-side rendering + mobile app or server side rendering with some ajax), at the very first step you would want to isolate your database querying code into a separate module (which is actually always a good idea) and use the module from your API and from your views directly, avoiding API usage from server-side views.
This way you will eliminate excessive auth and make debugging much easier, also your code will become cleaner, thus more maintainable.
Also, React is not that complex, i would definitely give it a shot :)

Resources