I built a REST API using Express, a JSON file (database), and deployed it on Heroku. I consume this API from my React.JS app which I run on localhost. It seems my data is not persist after I restart my React.JS app.
Here is my server.js file:
const express = require('express');
const bodyParser = require('body-parser');
const path = require('path');
const fs = require('fs');
const port = process.env.PORT || 3000;
const app = express();
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
res.header('Access-Control-Allow-Methods', 'GET, PUT, POST, DELETE, PATCH, OPTIONS');
if (req.method === 'OPTIONS') {
res.send(200);
} else {
next();
}
});
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
// GET ALL TODOS
app.get('/api/todos', (req, res) => {
let data = '';
fs.readFile(path.resolve(__dirname, 'data.json'), (err, resp) => {
if (err) return console.log('Error::reading tasks from data.json file ', err);
data = JSON.parse(resp);
res.send(data.todos);
});
});
// GET A TODO
app.get('/api/todos/:id', (req, res) => {
fs.readFile(path.resolve(__dirname, 'data.json'), (err, resp) => {
if (err) return console.log('Error::reading tasks from data.json file ', err);
let data = JSON.parse(resp);
let todoData = data.todos.filter(todo => todo.id === parseInt(req.params.id))
if (todoData.length > 0) {
res.status(200).send(todoData[0]);
} else {
res.status(500).send({ message: 'Error: not found any task with that id' });
}
});
});
// POST A TODO
app.post('/api/todo', (req, res) => {
fs.readFile(path.resolve(__dirname, 'data.json'), (err, resp) => {
if (err) return console.log('Error::reading tasks from data.json file ', err);
const { id, task, status } = req.body
if (id && task && status) {
let json = JSON.parse(resp);
json.todos.push(req.body);
fs.writeFile(path.resolve(__dirname, 'data.json'), JSON.stringify(json), err => {
if (err) return console.log('Error::writing task to the data.json file ', err);
});
res.status(200).send({ message: 'Success: data have been added' });
} else {
res.status(500).send({ message: 'Error: all fields must be filled with data' })
}
});
});
// EDIT A TODO
app.put('/api/todo/:id', (req, res) => {
fs.readFile(path.resolve(__dirname, 'data.json'), (err, resp) => {
if (err) return console.log('Error::reading tasks from data.json file ', err);
const id = parseInt(req.params.id)
const { task, status } = req.body
if (task && status) {
let json = JSON.parse(resp);
let newTodo = json.todos.map(todo => {
if(todo.id === id) {
return {
id,
task,
status
}
} else {
return todo
}
})
let result = {
todos: newTodo
}
fs.writeFile(path.resolve(__dirname, 'data.json'), JSON.stringify(result), err => {
if (err) return console.log('Error::editing task to the data.json file ', err);
res.status(200).send({ message: 'Success: task have been edited' });
});
} else {
res.status(500).send({
message: 'Error: all fields must be filled with data'
})
}
});
});
// DELETE A TODO
app.delete('/api/todo/:id', (req, res) => {
fs.readFile(path.resolve(__dirname, 'data.json'), (err, resp) => {
if (err) return console.log('Error::reading tasks from data.json file ', err);
let json = JSON.parse(resp);
let isDataExist = json.todos.some(todo => todo.id === parseInt(req.params.id))
if (isDataExist) {
let leftTodo = json.todos.filter(todo => todo.id !== parseInt(req.params.id))
let result = {
todos: leftTodo
}
fs.writeFile(path.resolve(__dirname, 'data.json'), JSON.stringify(result), err => {
if (err) return console.log('Error::deleting task to the data.json file ', err);
res.status(200).send({ message: 'Success: a task has been deleted' });
});
} else {
res.status(500).send({ message: 'Error: a task you want to delete is not exist' })
}
});
});
app
.listen(port, () => {
console.info(`Your api server is running on http://localhost:${port}`);
})
.on('error', () => {
console.error('Error::server ', error);
});
I save the data in data.json file. You could see the logic in every API block URL / route. What are wrong in my server code?
Note: If you want to see my repo for this project: https://github.com/ridoansaleh/api
a JSON file (database)
A JSON file isn't a proper database, and Heroku's ephemeral filesystem makes this an especially bad choice: any changes you make to it will be lost the next time your dyno restarts. This happens frequently (at least once per day).
If you want to persist data permanently you need to use a proper client-server database. Heroku provides a hosted PostgreSQL service that has a free tier. I recommend starting there.
Related
I have a very similar problem with respect to this fellow community contributor. How do i produce multer error message in my postman I followed through the comments made by other users and it was successful! However, when i tried to post a image that is a jpg formatted image( which i managed to do before the editing), it now fails and state that TypeError: Cannot read property 'filename' of undefined.
// multer.js file
successfully setup multer
**please tell me why this error comes on my code and give me a solution**
const multer = require('multer');
const storage = multer.diskStorage({
fileSize: 1024*1024*2,
destination: function (req, file, cb) {
cb(null, './uploads')
},
filename: function (req, file, cb) {
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9)
cb(null, file.fieldname + '-' + uniqueSuffix)
}
})
const filter = function (req, file, cb) {
if (file.mimetype === 'image/jpeg' || file.mimetype === 'image/png') {
cb(null, true);
} else {
cb(new Error('unsupported files'), false)
}
}
var upload = multer({
storage: storage,
limits: {
fileSize: 1024 * 1024 * 5
},
fileFilter : filter
});
module.exports = upload;
//controller.js file
//create function
here's my logic to create a new user
exports.create = (req, res, next) => {
if (!req.body) {
res.status(400).send({ message: "content cannot be empty !!" })
return
}
let data = { name: req.body.name, description: req.body.description, brand_url:
req.body.brand_url, image_file: req.body.file.filename }; getting error here
let sql = "INSERT INTO influencer SET ?";
db.query(sql, data, (err, results) => {
if (err) throw err;
console.log('data inserted succesfully')
res.redirect('/admin');
});
}
//api.js file
//post API
router.post('/api/create', upload.single('image') ,controller.create) //when I am
sending file its throw back error undefined filename
Please make sure you have added enctype="multipart/form-data"
<form action="/api/create" enctype="multipart/form-data" method="post">
I have tested the codes & found the problem.
exports.create = (req, res, next) => {
if (!req.body) {
res.status(400).send({ message: "content cannot be empty !!" })
return
}
let data = {
name: req.body.name,
description: req.body.description,
brand_url: req.body.brand_url,
image_file: req.file.filename
}; // Remove "body", I have tested, it works well.
let sql = "INSERT INTO influencer SET ?";
db.query(sql, data, (err, results) => {
if (err) throw err;
console.log('data inserted succesfully')
res.redirect('/admin');
});
}
I have created an API in Nodejs. I have tried creating a call which returns HTML to display a site in the browser.
My Call looks like this:
router.get('/displayHTML', checkAccessToken, (req, res, next) => {
if (req.query.data === undefined) {
return res.status(900).json({
message: 'Data does not exist'
});
}
Data.find({ data: req.query.data}).exec()
.then(data => {
if (data.length < 1) {
return res.status(400).json({
message: "Nothing found"
});
}
// I need to return HTML here so the user sees something in his browser
return res.status(200).json({
data: data
});
}).catch(error => {
return res.status(500).json({
message: error
});
});
});
Check the fs_library: https://nodejs.org/docs/v0.3.1/api/fs.html
var http = require('http'),
lib = require('fs');
lib.readFile('./page.html', function (err, html) {
if (err) {
throw err;
}
http.createServer(function(request, response) {
response.writeHeader(200, {"Content-Type": "text/html"});
response.write(html);
response.end();
}).listen(8000);
});
How can I resolve Cannot set headers after they are sent to the client:
app.js
var express = require('express');
var session = require('express-session');
var mongoose = require('mongoose');
var app = express();
var ejs = require('ejs');
var port = 3000;
var bodyParser = require('body-parser');
var mongoDB = "mongodb://localhost:27017/vinavdb";
app.set('views', __dirname + '/admin') app.engine('html', ejs.renderFile);
app.set('view engine', 'ejs');
app.set('trust proxy', 1);
app.use(session({
secret: 'dsghbrtdfhbdfg64545TRYFFHGGJNN',
resave: false,
saveUninitialized: true
}))
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
var sess;
mongoose.Promise = global.Promise;
mongoose.connect(mongoDB, {
useNewUrlParser: true
});
var nameSchema = new mongoose.Schema({
firstname: String,
lastname: String,
email: String,
password: String
});
var User = mongoose.model("User", nameSchema);
app.get("/", (req, res) => {
sess = req.session;
if (sess.email) {
res.redirect("/admin");
} else {
res.sendFile(__dirname + "/index.html");
}
});
app.get("/login", (req, res) => {
res.sendFile(__dirname + "/login.html");
});
app.post("/addname", function(req, res) {
var myData = new User(req.body);
User.findOne({
email: req.body.email
}, function(err, resv) {
if (resv == null) {
myData.save().then(item => {
res.send("Name saved to database")
}).catch(err => {
res.status(400).send("Unable to save to database");
});
res.send("ThankYou For your Registration")
} else if (resv.email == req.body.email) {
res.send("Email is already registered");
} else {
res.send("Srry data is not allowed");
}
});
});
app.post("/login", function(req, res, next) {
User.findOne({
email: req.body.email
}, function(err, vals) {
if (vals == null) {
res.end("Invalid Logins");
} else if (vals.email == req.body.email && vals.password == req.body.password) {
sess = req.session;
sess.email = req.body.email;
res.redirect('/admin');
} else {
res.send("Srry data is not allowed");
}
});
});
app.route('/admin').get(function(req, res, next) {
sess = req.session;
if (sess.email) {
res.send(__dirname + "/admin/index.html");
} else {
res.write('Please login first.');
}
})
app.listen(port, () => {
console.log("Server listening on port " + port);
});
Cause of your error : You are trying to send a response of a single request twice.
One request have one response.
Once response is send, you cannot send it again for the same request.In your /addname API, You are trying to send response twice. So remove one.
Here .save() is asynchronous function so node will not wait and execute
res.send("ThankYou For your Registration") first and later once record will be saved it will try to send res.send("Name saved to database") so you are getting error here.
app.post("/addname", function(req, res) {
var myData = new User(req.body);
User.findOne({
email: req.body.email
}, function(err, resv) {
if (resv == null) {
myData.save().then(item => {
console.log("Name saved to database")
res.send("ThankYou For your Registration")
}).catch(err => {
res.status(400).send("Unable to save to database");
});
} else if (resv.email == req.body.email) {
res.send("Email is already registered");
} else {
res.send("Srry data is not allowed");
}
});
});
After you execute a res.send you cannot call it again in the same request, it only allows one response per request. In your code, I think in this part it can happens:
if (resv == null) {
myData.save().then(item => {
res.send("Name saved to database")
}).catch(err => {
res.status(400).send("Unable to save to database");
});
res.send("ThankYou For your Registration")
}
In this if, when you are saving myData you are sending a response, but asynchronously you already sent another response previously ("ThankYou For your Registration").
Hope it helps
I am making a http request from my angular2+ code to database present in node.js file. The ajax call from angular2+ hits the controller.js file and then redirects to service.js file which has the connection to the database:
angular.ts ==> controller.js ==> service.js
From the database the service.js file gives the output to controller.js file and then answers the ajax call to angular.ts file:
service.js ==> controller.js ==> angular.ts
However, I am getting the error:
POST http://localhost:8096/dashboard/abcEntireSuccess1/ 404 (Not Found)
UPDATED
Cannot GET /dashboard/experianEntireSuccess1/
And one more issue -
UnauthorizedError: No authorization token was found
And one more issue -
After coming back from the hit in service.js which has the data i want ==> to => controller.js , here the data is acquired is undefined. As seen below -
The output on Nodejs -
output -
service.js
closed connection
yessss [ RowDataPacket { ....
controller.js
we are coming back to controller undefined
some error occured of abcEntireSuccess1
My Entire Code:
UPDATED
abc.component.ts
viewAbcEntireSuccess1() {
var url = config.url;
var port = config.port;
this.http.post("http://" + url + ":" + port + "/dashboard
/abcEntireSuccess1/", this.emptyObj
, { headers: new Headers({ 'Authorization': 'Bearer ' +
localStorage.getItem('Token') }) })
.map(resultConnection => this.resultConnection =
resultConnection.json(), )
.subscribe((res: Response) => {
this.records = res;
this.resultConnectionlength = this.resultConnection.length;
});
}
abc.controller.js
router.post('/experianEntireSuccess1',experianEntireSuccess1);
module.exports = router;
function abcEntireSuccess1(req, res) {
dashboardService.abcEntireSuccess1(req.body)
.then(function (result) {
console.log("we are coming back to controller",result)
if (result.length > 0) {
console.log("we get data in node of abcEntireSuccess1 ::
" + Object.values(result));
console.log(result.length + " record found ");
res.send(result);
}
else {
result=[];
res.send(result);
}
})
.catch(function (err) {
res.status(400).send(err);
console.log("some error occured of abcEntireSuccess1");
});
}
abc.service.js
async function abcEntireSuccess1() {
console.log("function called")
const db = new Database();
await db.query(`select * from TRANSACTION_PAYLOAD where INTERFACE_NAME
= 'Abc' AND (STATUS ='SUCCESS_RESPONSE')`
).then(rows => {
console.log("closed connection");
console.log("yessss",rows)
return rows;
});
};
class Database {
constructor() {
this.connection = mysql.createConnection({
host: "127.0.0.1",
user: "abc",
password: "abc",
database: "DB"
});
}
query(sql, args) {
console.log("sql is", sql)
return new Promise((resolve, reject) => {
this.connection.query(sql, (err, rows) => {
console.log("connection function called")
if (err) {
console.log("error is", err)
return reject(err);
}
console.log("rows are",rows);
resolve(rows);
});
});
}
close() {
console.log("calling connection close")
return new Promise((resolve, reject) => {
console.log("called connection close")
this.connection.end(err => {
if (err){
return reject(err);
}
resolve();
});
});
}
}
with my client js i have perform a fetch and send along some data.
And i've attempted to do a res.send or res.json to send a result back.
Do I need to create a new json and send it?
Express Server
const express = require('express');
const app = express();
const pg = require('pg');
const conString = 'postgres://postgres:password#localhost/postgres';
const bodyParser = require('body-parser');
app.use(bodyParser.json()); //support json encoded bodies
app.use(bodyParser.urlencoded({ extended: true})); //support encoded bodies
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
app.listen(3000, function () {
console.log('Server listening on port 3000!');
});
app.post('/', function(req, res){
var uname = req.body.username;
var pw = req.body.password;
QueryByUserName(uname, function(err, result){
if(err){
console.error('error happened', err);
//handle error
}
if(uname == result.username){
//name is in our database
if(pw == result.password){
console.log("User and Password Correct!");
res.json({ message: 'correct' });
} else {
console.log("Password Incorrect!");
res.json({ message: "incorrect" });
}
} else if(result.username == "undefined"){ //placeholder
console.log("username does not exist");
res.send( {message: "dne"} );
console.log(res);
}
});
});
function QueryByUserName(input, callback) {
pg.connect(conString, function(err, client, done){
if(err){
callback(err);
return;
}
client.query(SelectAll(), function(err, result){
//Query database for all usernames
done();
var isFound = false;
for(var x = 0; x < result.rows.length; x++){
//loop through all usernames from database.
if(result.rows[x].username == input){
isFound = true;
//username exists, now we obtain the rest of the data.
client.query(findDataInDatabase(input, '*'), function(err, result){
done();
if(err){
callback(err);
return;
}
console.log(result.rows[0]);
callback(null, result.rows[0]);
//return all information regarding user to callback function
});
} else if(x == (result.rows.length - 1) && !isFound){
callback(null, {username: "undefined"}); //placeholder
//Username does not exist in database
}
} //end of For Loop
});
});
}
function findDataInDatabase(username, WhatWeLookingFor) {
return 'select ' + WhatWeLookingFor + ' from users where username = \'' + username + '\'';
}
Express server side will try to send a message to the client.
but when I do this i did a console.log(res) it shows that the body is { null, null, null}
Client login Function
handleLogin: function(){
let fetchData = {
method: "post",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
username: this.state.user,
password: this.state.password,
message: null
})
}
var fromServer = fetch('http://localhost:3000/', fetchData)
.then(function(response){
if( !response.ok){
throw Error (response.statusText);
}
console.log(response);
console.log(response.message);
console.log(response.body);
console.log(response.body.text);
return response.json();
})
.catch(error => console.log("there was an error --> " + error));
},
Edit : Screenshots below
Since you have returned, res.json({ message: 'correct' });
use,
response.message
Instead of,
response.body
var fromServer = fetch('http://localhost:3000/', fetchData)
.then(response => response.json())
.then(response => {
console.log(response.message);
})
After talking to Sraven, who was a huge help.
The code is sending a req, and the server is responding with a response with the message included. The problem was on the client side where it was not getting the response correctly.
Below is the working code and was able to finally produce a response.
var fromServer = fetch('http://localhost:3000/', fetchData)
.then(response => response.json())
.then(response => {
console.log(response.message);
})