I followed a tutorial for making an api with express and postgres. I can get all my data in json form no problem. But I have no idea how to use the data in the frontend of a site.
These are what I have in 2 different files that are linked.
index.js:
const db = require('../queries')
router.get('/classes/:id', db.getClassById)
router.get('/classes/:id/edit', db.getClassById, (req, res) => {
res.render('dashboard/editClass')
})
queries.js:
const getClassById = (req, res) => {
const id = parseInt(req.params.id)
pool.query('SELECT * FROM classes WHERE state = 1 AND classId = $1', [id], (err, results) => {
if(err){
throw err
}
res.status(200).json(results.rows)
})
}
module.exports = {
getClassById
}
The getClassById query is called by the express middleware and automatically sends the json data to the page, which will not allow the res.render('dashboard/editClass') to work.
So how would I call this query so that I can fill in a form with the data from the query so a user can see the existing data and make any changes they want?
Thanks to Mark and Marc who commented, I realized I needed to fetch the data from my own api when rendering the front end pages. I am now using axios to get this done in node and so far it is doing exactly what I was looking for.
Related
I am working on my first full stack application, specifically with the MERN stack, and have run into a bit of an issue. I am trying to implement a leaderboard stored in a db for a unity game on my website. I have everything working wherein the client can post and get scores from my MongoDB Atlas database using my Express api. However, in the case of a leaderboard, I need to insure that the scores can ONLY be sent by the client based on how the game goes. With the current working configuration, anyone can send spoof scores via the api without having to play the game.
I first thought was to try to implement JWT to authenticate that the api call was coming from the site, but in my head any auth token like JWT could still be copied down by a user and sent with spoofed scores easily with Postman.
I am not extensively familiar with databases and suspect that this could possibly be solved if I wasn't using a DBaaS provider like Atlas but I am not entire sure.
Any thoughts or recommendations would be greatly appreciated!
You could define a middleware function and check the method of the incoming request:
const allowOnlyPost = (req, res, next) => {
if (req.method !== 'POST') {
return res.status(401).send(`Method ${req.method} not allowed`)
}
next()
}
module.exports = { allowOnlyPost }
And then apply it to the routes you want to protect:
const { allowOnlyPost } = require('./your/middleware/folder')
app.use('/route/to/protect', allowOnlyPost, (req, res) => { ... })
An improvement to current answer's function could be:
const allowMethods = (...methods) => {
return (req, res, next) => {
if (!methods.map(m => m.toUpperCase()).includes(req.method.toUpperCase())) {
return res.status(401).send(`Method ${req.method} not allowed`)
}
next()
}
}
module.exports = { allowMethods }
So you could use it like this:
const { allowMethods } = require('./your/middleware/folder')
app.use('/route/to/protect', allowMethods('get','post'), (req, res) => { ... })
I have created a delete route in express.js that looks like the following:
router.delete("/notes/:id", (req, res) => {
console.log("delete route called")
const noteToRemove = findById(req.params.id, notes);
const result = notes.filter(note => note !== noteToRemove)
console.log(result);
fs.writeFileSync(
path.join(__dirname, '../../db/db.json'),
JSON.stringify({ notes: result }, null, 2)
);
)}
findById is a function I have declared in another file to locate an item in my database db/db.json that locates an item based on an ID I created earlier.
The issue here is that this code will remove an item from the database, but I want the frontend to show the updated list from the database. How does one reload the frontend to see the updated changes in the database?
Two things:
You will need to include a response in your server side method to let the client know that the resource was deleted. You should also add responses with error codes in cases something goes wrong, but for simplicity here we only address the nominal case.
router.delete("/notes/:id", (req, res) => {
console.log("delete route called")
const noteToRemove = findById(req.params.id, notes);
const result = notes.filter(note => note !== noteToRemove)
console.log(result);
fs.writeFileSync(
path.join(__dirname, '../../db/db.json'),
JSON.stringify({ notes: result }, null, 2)
);
res.end(); // respond to the client to let them know we are finished
)}
On the front-end you will need to react to this response and reload the resources. This highly depends on how your front end is structured and how it gets data from the server. As a hack, for now, you can just call location.reload(), which will do the trick in the vast majority of cases -- but isn't very elegant of course nowadays where you could refetch and render just parts of the data and page.
I wrote two node js applications, they are fetching data properly but they are not taking post values 1st applications is this TinderClone this is just an api with no frontend i am posting data from postman and it is returning auto generated id but not the data i am posting,
Other application i cloned from github, it has proper frontend with working CRUD, but when i tried to post values from postman it wont take any values it will just add record in database with null values, so is there anything wrong im doing on postman? cause it is still working if i post data with the form on its frontend the application url is MernCRUD
Postman Screenshots:
posting data,
fetching data
Code:
//Cards Schema (Cards.js)
import mongoose from 'mongoose'
const cardSchema = mongoose.Schema({
name: String,
imgUrl: String
})
export default mongoose.model('cards', cardSchema)
//Posting Data (Server.js)
app.post('/tinder/cards', (req, res) => {
const dbCard = req.body;
Cards.create(dbCard, (err, data) => {
if(err){
res.status(500).send(err)
}
else{
res.status(201).send(data)
}
})
})
//Fetching Data
app.get('/tinder/cards', (req, res) => {
Cards.find((err, data) => {
if(err){
res.status(500).send(error);
}
else{
res.status(200).send(data);
}
});
});
in postman you don't have to add content type manually . You should select json from the drop down and it will add content type by default. **
Now you have text in your raw dropdown change to json .
**
I was learning to build a weather app using Node (Express) + React. I successfully fetched weather data from open weather API.
However I was directly using the open weather API key in my React app like this const weatherURL = 'http://api.openweathermap.org/data/2.5/weather?q=london,uk&APPID=1234567qwerty';. Obviously this is not safe as it exposed the API key to the client. I thought about storing the API key in .env file, but according to [this answer][1], I should never store API key in .env file or .gitignore. The right way is to make a request to backend API and make an API call to backend and send the data back. I could not find out how to do it. Can anyone help?
Following is my node js code:
const express = require('express');
const cors = require('cors');
const app = express();
const SELECT_ALL_QUERY = 'SELECT * FROM `mySchema`.`myTable`;';
app.use(cors());
app.get('/', (req, res) => {
res.send('go to /myTable to see content')
});
const pool = require('./awsPool');
pool.getConnection((err, connection) => {
if (err) {
return console.log('ERROR! ', err);
}
if(!connection) {
return console.log('No connection was found');
}
app.get('/myTable', (req, res) => {
console.log(connection);
connection.query(SELECT_ALL_QUERY, (err, results) => {
if (err) {
return res.send(err)
}
else {
return res.json({
data: results
})
};
});
});
});
let port=process.env.PORT||4000;
app.listen(port, () => {
console.log(`App running on port ${port} `);
});```
[1]: https://stackoverflow.com/a/57103663/8720421
What the linked answer was suggesting is to create a route in your Node/Express backend API that will make the call to the weather API for you, instead of the front end. This way the request and your API key are not public-facing whenever your front end makes a call.
The method for doing this would essentially be the same as what you have done in React, making an HTTP request using a built-in or 3rd party library. This resource I just found has some information on how to do both.
The simplest pure http-request in node looks like this:
const http = require('http')
const url = 'http://api.openweathermap.org/data/'
http.request(url, callback).end()
function callback (weatherResponse) {
let jsonString = ''
weatherResponse.on('data', chunk => {
jsonString += chunk
})
weatherResponse.on('end', () => {
// Now you have the complete response and can do whatever you want with it
// like return it to your user `res.send(jsonString)`
console.log(jsonString)
})
}
Many people find it bulky to having to handle chunks and the whole asynchronous thing, so there are many popular npm modules, like: https://www.npmjs.com/package/axios. (And here's a list of other contenders https://github.com/request/request/issues/3143).
Also, it is normal to store API-keys in environment variables on the backend. It makes things easy if you ever try to dockerize your app, or just scale up to using two backend servers instead of one.
I found a solution based on #ippi answer, add the following part to the original code:
const request = require('request');
const url = 'http://api.openweathermap.org/data/2.5/weather?q=london,uk&APPID=1234567';
app.get('/weather', (req, res) => {
request(url, (error, response, body) => {
if (!error && response.statusCode == 200) {
var info = JSON.parse(body)
res.send(info);
}
})
})
The url can be stored in .env file and passed into the above code. The returned weather data can be viewed in JSON format at http://localhost:4000/weather. In React the weather data can be fetched via this localhost url.
EDIT: request is deprecated, so here is a solution using axios
app.get('/weather', (req, res) => {
axios.get(url)
.then(response => {res.json(response.data)})
.catch(error => {
console.log(error);
});
})
User Passport middleware for nodeJs/Express. They provide passport-headerapikey strategy using which you can create and authorize apiKeys. http://www.passportjs.org/packages/passport-headerapikey/
I'm converting an MS Access database to a webapp. I'm using Angular JS, Node JS with the express framework and MySQL as database.
In ms access you don't have any edit/save features. When you edit something, the database changes instantly. I like this. Feels smooth. So I want to have this the same way in the web app. My question is. Will there be any problems with this approach in my webbapp?
This is a piece of my node js code which updates the database with a restcall:
/*
Post /api/products/ HTTP/1.1
*/
exports.editProduct = function(req, res) {
console.log(req.body);
var post = [{title_en: req.body.title_en},req.params.id];
if (connection) {
connection.query("UPDATE products SET ? WHERE id = ?", post, function(err, rows, fields) {
if (err) throw err;
res.contentType('application/json');
res.write(JSON.stringify(rows));
res.end();
});
}
};
And on the client side I use the a the $resource object
$scope.save = function(){
$scope.product.$save(function(){
console.log('Save successfull);
});
};
And in the view. I simply have inputs with ng-change:
<input ng-model="product.title_en" ng-change="save()".
Will this work good in production mode with a couple hundred users? Is the chances of blocking/crashing etc?
The only thing I see is if (err) throw err;
if there is an error the server crash so change it with a json response with a 500 status.
By the way express has a build-in way to output json
It's better off to validate title_en and id
exports.editProduct = function(req, res) {
console.log(req.body);
var post = [{title_en: req.body.title_en},req.params.id];
if (connection) {
connection.query("UPDATE products SET ? WHERE id = ?", post, function(err, rows, fields) {
if (err) {
return res.json(500,{ error: 'Cannot update the product' });
}
res.json(200,rows);
});
}
an other thing try to use restangular instead of resource it's a lot of fun :)
};