ReactJS axios post: returns null when it comes/goes from/to backend - reactjs

I am stuck on this problem for 2 days. I am sending POSTrequest from frontend to the backend (and other GET requests too but the problem is only with POST). However, when my data goes to the backend it does not post anything to the rest api even though response is 200 OK. That's why when in response it should have given the posted data, it can't find it and gives null. This is my POST code in backend index.js:
const { response, request } = require('express');
require('dotenv').config()
const express = require('express');
const morgan = require('morgan');
const Contact = require('./models/contact.cjs');
const cors = require('cors')
const app = express();
app.use(express.json())
app.use(express.static('build'))
app.use(cors())
morgan.token('body', req => {
return JSON.stringify(req.body)
})
app.use(morgan(':method :url :status :res[content-length] - :response-time ms :body'));
const generateId = () => {
const randNum = Math.floor(Math.random() * 5000)
return randNum;
}
app.post('/api/persons', (req, res) => {
const body = req.body
console.log(body)
if (!body.name || !body.number) {
return res.status(400).json({
error: "missing data"
})
} else if (Contact.find({name: body.name})) {
Contact.findOneAndUpdate({name: body.name}, {$set: {number: body.number}}, {new:true})
.then(updatedContacts =>
res.json(updatedContacts)
)
.catch(err => console.log(err))
} else {
const contact = Contact({
id: generateId(),
name: body.name,
number: body.number,
date: new Date()
})
contact.save()
.then(savedContact => {
console.log(savedContact)
res.json(savedContact)
})
.catch(err => {
console.log(err)
})
}
})
const PORT = process.env.PORT
app.listen(PORT, () => {
console.log(`Server is working on ${PORT}`)
})
and this is how my frontend sends data to backend: contacts.js:
const create = (newObject) => {
const readyToPost = {
method: 'post',
url: `${baseUrl}`,
data: newObject,
headers: {'Content-Type': 'application/json'},
json: true
}
const request = axios(readyToPost)
return request.then(response => {
console.log(response.data)
return response.data
})
.catch(err => {
console.log(err)
})
}
And this is my react app's frontend.
Any ideas about why my data becomes null?
Any help would be appreciated!

Due to the synchronous nature of your code, the condition Contact.find({name: body.name}) was always returning the Query object which is true due to which the else if block was getting executed even when there was no such document. After entering the else if block, since there was no match, so findOneAndUpdate() was returning null.
Use findOne() instead of find(). find() returns a cursor which is empty but true whereas findOne() returns the first document matched (if matched) or else it will return null (if not matched).
// index.js (Backend)
app.post("/api/persons", async (req, res) => {
const body = req.body;
if (!body.name || !body.number) {
return res.status(400).json({
error: "missing data",
});
}
// Using findOne() instead of find(). Returns null if record not found.
const existing = await Contact.findOne({ name: body.name });
if (existing) {
Contact.findOneAndUpdate(
{ name: body.name },
{ $set: { number: body.number } },
{ new: true }
)
.then((updatedContacts) => {
console.log(updatedContacts);
res.status(200).json(updatedContacts);
})
.catch((err) => console.log(err));
} else {
const contact = Contact({
id: generateId(),
name: body.name,
number: body.number,
date: new Date(),
});
contact
.save()
.then((savedContact) => {
console.log(savedContact);
res.status(201).json(savedContact);
})
.catch((err) => {
console.log(err);
});
}
});

Related

500 Internal Server Error Express + Axios

When I make a fetch request, I get a 500 error, but when I just return an array of values, everything goes well, please tell me.
My server.js file:
const express = require('express');
const cors = require("cors");
const CoinGecko = require("coingecko-api")
const app = express();
const CoinGeckoClient = new CoinGecko();
app.use(cors())
app.get('/coins', (req, res) => {
await axios.get<ICoin[]>(`https://api.coingecko.com/api/v3/coins/markets?`, {params: {
vs_currency: "usd",
per_page: 100,
page: 1,
}})
.then((response) => {
console.log(response);
res.json(response.data);
}).catch((error) => {
console.log(error);
})
})
app.listen(5000, () => {
console.log('Server listening on port 5000');
});
My fetch request:
export default class CoinsService {
static async getAll(page ) {
let response: ICoin[] = []
await axios.get('/coins').then(data => console.log(data)
)
}
}
I tried to output the exact error but got the same message:
enter image description here
enter image description here
as montionned in #Vahid Alimohamadi comment you don't need await if you you are using promise
most probably the error is from this line :
await axios.get<ICoin[]>
here you are expecting the Response type to be ICoin[] which is probably not, replace it with
axios.get<any>
if the error disappears then you have understood the reason.
but this is only for debugging, REMEMBER:
using the any type is not recommanded
I solved this problem, it was my carelessness.
I used
app.get('/coins', async (req, res) => {
CoinGeckoClient.coins.markets({
vs_currency: 'usd',
per_page: 100,
page: page,
sparkline: false
}).then((response) => {
res.json(response.data);
}).catch((error) => {
console.log(error);
})
Replacing this option, I got the data.
app.get('/coins', async (req, res) => {
await axios.get('https://api.coingecko.com/api/v3/coins/markets?', {
params: {
vs_currency: "usd", // Convert prices to USD
per_page: 100, // Get top 100 coins
page: 1, // Get first page
}
})
.then((response) => {
res.json(response.data);
}).catch((error) => {
console.log(error);
})
I would like to know why I could not use the 1st option?

firebase react cloud messaging push notification [duplicate]

I was working on a project using Firebase cloud messaging react. I was sending this to my server, but it doesn't work. Surely I have tried, but I don't know what's wrong again.
Below is the code.
Here it sends a POST request to Firebase, and it should send a notification to the user.
async function sendNotification(id, userMessage) {
const headers = {
'Authorization': `key=${code}`,
'Content-Type': 'application/json'
}
const message = {
'to': `${id}`,
'content_available': true,
'apns_priority': 5,
'notification': {
body: `${userMessage}`
},
const url = 'https://fcm.googleapis.com/fcm/send'
//console.log(code)
await axios.post(url, message, {
headers: headers
})
}
const sendMessageToServer = async (e) => {
//e.preventDefault();
toggle()
const docRe = doc(database, "help", mailer);
const data = {
email: user.email,
user: newMessage,
}
//console.log(data, 'not clear')
setNewMessage('')
//console.log(data, newMessage, 'cleared')
setShow(false)
if(newMessage === '') {
}
else {
const docRef = doc(database, "users", mailer);
await updateDoc(docRe, {
msg: arrayUnion(data)
})
.then(() => {
async function p() {
const id = await getDoc(docRef)
//console.log(id.data())
sendNotification(id.data().notice, `Admin : ${data.user}`)
}
p()
})
}
Sometimes it sends to my localhost because I tested there, but it doesn't work on my Netlify app. Secondly, I noticed that it keeps generating the same token for each user, but that's not the issue, but if you can help in both I would be grateful.
export default function Dashboard() {
async function callToken() {
await getToken(messaging, {vapidKey: process.env.NOTIFICATION})
.then((code) => {
//console.log(code)
async function docRef() {
const dc = doc(database, "users", auth.currentUser.email);
await updateDoc(dc, {
notice: code
});
}
docRef()
})
}
async function requestPermission() {
await Notification.requestPermission()
.then((permission) => {
if (permission === 'granted') {
console.log('Notification permission granted.')
callToken()
}
})
}
const goTo = useNavigate();
useEffect(() => {
onAuthStateChanged(auth, (data) => {
if(!data) {
goTo('/login')
}
else {
currentBalance();
requestPermission()
}
})
})
}
Please know I imported all required modules.

Nock not mocking GET request

I'm trying to follow run a cypress test with next.js and nock. Based on other examples and following the video, I tried to mock a simple GET request. However, my test fails on the cy.request as it makes an actual call instead of the mock call.
index.js
const nock = require('nock');
const http = require('http');
const next = require('next');
const injectDevServer = require('#cypress/react/plugins/next');
// start the Next.js server when Cypress starts
module.exports = async (on, config) => {
if (process.env.CUSTOM_SERVER == 'false') {
injectDevServer(on, config);
} else {
await startCustomServer(on, config);
}
return config;
};
async function startCustomServer(on, config) {
config.supportFile = false;
const app = next({ dev: true });
const handleNextRequests = app.getRequestHandler();
await app.prepare();
const customServer = new http.Server(async (req, res) => {
return handleNextRequests(req, res);
});
await new Promise((resolve, reject) => {
customServer.listen(3000, (err) => {
if (err) {
return reject(err);
}
console.log('> Ready on http://localhost:3000');
resolve();
});
});
// register handlers for cy.task command
on('task', {
clearNock() {
nock.restore();
nock.cleanAll();
return null;
},
async nock({ hostname, method, path, statusCode, body }) {
nock.activate();
console.log(
'nock will: %s %s%s respond with %d %o',
method,
hostname,
path,
statusCode,
body
);
// add one-time network stub like
method = method.toLowerCase();
nock(hostname)[method](path).reply(statusCode, body);
return null;
},
});
}
my-test.spec.js
describe('my-test', () => {
beforeEach(() => {
cy.task('clearNock');
})
it('execute', () => {
cy.task('nock', {
hostname: 'https://localhost:3000',
method: 'GET',
path: '/myapi/api/layout',
statusCode: 200,
body: {
id: 'NmbFtH69hFd',
status: 200,
success: true
}
})
cy.request(
'https://localhost:3000/myapi/api/layout/'
).as('API'); // <-- Fails here with error
cy.get('API').then((response) => {
assert.exists(response.success);
});
});
});

React & Express: app.use() routes not working with socket.io

React Beginner Here. I'm trying to connect an existing react project and socket.io but now I can't access the routes with app.use(). I can see the console logs of the connections and disconnections but when I login with '/login', It doesn't run. Front end runs at 3000, Server at 9000
Edit: It does run because I receive a token which is sent at the end of it. However I get a status 404 Cannot POST /login.
Socket.js
const express = require('express')
const router = express.Router()
const http = require('http')
const cors = require('cors')
const server = http.createServer(router)
router.use(cors())
const {Server} = require("socket.io")
const io = new Server(server, {
cors: {
origin: 'http://localhost:3000',
methods: ['GET', 'POST', 'PUT', 'DELETE'],
}
})
io.on('connection', (socket) => {
console.log('a user connected')
socket.on('disconnect', () => {
console.log('user disconnected', socket.id)
})
socket.on('chat message', (msg) => {
console.log('message: ' + msg)
io.emit('chat message', msg)
})
})
module.exports = {server}
Server.js
const express = require('express')
const app = express()
const {server} = require('./socket/socket')
const cors = require('cors')
app.use(cors({
origin: ['http://localhost:3000', 'http://localhost:9000', 'http://localhost:3001'],
credentials: true,
}))
app.use(express.json())
app.use(express.urlencoded({extended: true}))
const login = require('./routes/login')
const signup = require('./routes/verify/signup')
const home = require('./routes/home')
const checkRefreshToken = require('./routes/_checkRT')
const logout = require('./routes/_logout')[![enter image description here][1]][1]
const verify = require('./routes/verify/_verify')
app.use('/login', login)
app.use('/signup', signup)
app.use('/', home)
app.use('/check_refresh_token', checkRefreshToken)
app.use('/logout', logout)
app.use('/verification', verify)
const PORT = process.env.PORT || 9000
server.listen(PORT, () => {
console.log(`Listening on http://localhost:${PORT}`)
})
front end messages.jsx
import React from 'react'
import Navbar from '../../components/navbar/navbar'
import io from 'socket.io-client'
const socket = io.connect('http://localhost:9000/')
const Messages = () => {
return (
<div>
<Navbar />
</div>
)
}
export default Messages
Login.js
require('dotenv').config()
const express = require('express')
const router = express.Router()
const jwt = require('jsonwebtoken')
const cors = require('cors')
const bcrypt = require('bcrypt')
const mysql = require('mysql')
const connection = mysql.createConnection({
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_DATABASE
})
// middleware
router.use(cors({
origin: ['http://localhost:3000', 'http://localhost:9000', 'http://localhost:3001'],
credentials: true,
}))
router.use(express.json())
router.use(express.urlencoded({extended: true}))
/**
* Flow of the code:
* 1. Check if email exists in the database
* 2. If it does, check if the password matches
* 3. If it does, generate an access token
* 4. Then generate a refresh token
* 5. Then send the access token and refresh token to the client
*/
router.post('/', (req, res) =>
{
// Even these doesn't run
// console.log("HERE");
// res.send("HELLO")
const { email, password } = req.body
function getInput() {
return new Promise((resolve, reject) => {
let sql = `
SELECT * FROM account_table
LEFT JOIN section_table
ON account_table.account_section_id = section_table.section_id
WHERE account_email = ?
;`
connection.query(sql, [email], (err, results) => {
if (err) return reject({status: 500, message: 'Internal server error'})
else if (results.length === 0) return reject({status: 401, message: 'Invalid email or password'})
return resolve(results)
})
})
}
function checkPassword(input) {
return new Promise((resolve, reject) => {
bcrypt.compare(password, input[0].account_password, (err, result) => {
if (err) return reject({status: 500, message: 'Internal server error'})
else if (!result) return reject({status: 401, message: 'Invalid email or password'})
return resolve(input)
})
})
}
function generateAccess(result) {
return new Promise((resolve, reject) => {
const userAccessToken = {
user_id: result[0].account_id,
user_section_id: result[0].account_section_id
}
jwt.sign(userAccessToken, process.env.ACCESS_TOKEN_SECRET, {expiresIn: '15m'}, (err, token) => {
if (err) return reject({status: 500, message: 'Internal server error'})
return resolve(token)
})
})
}
function generateRefresh(result) {
return new Promise((resolve, reject) => {
const userAccessToken = {
user_id: result[0].account_id,
user_section_id: result[0].account_section_id
}
jwt.sign({userAccessToken}, process.env.REFRESH_TOKEN_SECRET, (err, token) => {
if (err) return reject({status: 500, message: 'Internal server error'})
return resolve(token)
})
})
}
function insertSend(access, refresh, result) {
return new Promise((resolve, reject) => {
const userInfo = {
user_f_name: result[0].account_first_name,
user_l_name: result[0].account_last_name,
section_grade: result[0].section_grade,
section_strand: result[0].section_strand,
section_name: result[0].section_name,
}
let expiryDate = new Date(Date.now())
expiryDate.setDate(expiryDate.getDate() + 7) // 7 days
let sql = `INSERT INTO refresh_token_table (token_content, token_owner_id, token_timestamp) VALUES (?, ?, ?)`
connection.query(sql, [refresh, result[0].account_id, expiryDate], (err, results) => {
if (err) return reject({status: 500, message: 'Internal server error'})
return resolve(
res.cookie("hello_world_cookie69", refresh, {
origin: "http://localhost:9000",
expires: expiryDate,
httpOnly: true,
secure: true,
sameSite: "strict",
}).json({userInfo, access})
)
})
})
}
try {
let vEmail = await getInput()
let vData = await checkPassword(vEmail)
let accessToken = await generateAccess(vData)
let refreshToken = await generateRefresh(vData)
let send = await insertSend(accessToken, refreshToken, vData)
} catch (err) {
return res.status(err.status).json({ message: err.message })
}
})
module.exports = router

Problem with request in react and express.js

so when i send a request which looks like that:
everythig in this api:
router.post('', async (req, res) => {
try {
if(!req.files || !req.body.format) {
res.send({
status: false,
message: 'No file or format'
});
} else {
let uuidv4 = () =>{
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
let r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
let video = req.files.video;
let video_name = uuidv4()
let video_format = req.body.format
if (allowedFormats.includes(video_format)) {
let oldVideoPath = './public/uploads/' + video_name + "." + video_format
const newVideoPath = './public/converted/' + video_name + ".mp3"
let video_path = oldVideoPath
video.mv(oldVideoPath)
let proc = new ffmpeg({source: video_path, nolog: true})
proc.setFfmpegPath("./ffmpeg/bin/ffmpeg.exe")
proc
.toFormat('mp3')
.on('end', function () {
res.send({
status: true,
message: 'File has been uploaded',
file: newVideoPath.substring(1)
});
})
.on('error', function (err) {
res.send({
status: false,
message: 'An error occurred ' + err,
});
})
.saveToFile(newVideoPath)
} else {
res.send({
status: false,
message: 'Wrong format!',
})
}
}
} catch (err) {
res.status(500).send(err);
}
});
works perfectly, but the second i send it from react
const fileHandler = (file) => {
const data = new FormData()
data.append('file', file)
data.append('format', baseFormat)
fetch(process.env.REACT_APP_API_IP+'/upload-video', {
method: 'POST',
body: data
})
.then(response => response.json())
.then(data => console.log(data))
}
it gives me an 500 (Internal Server Error).
I checked and when sent from react the file and format reach the api but it breaks somewhere after the uuidv4 function.
Any help appreciated!
You should specify that it is form data.
Add to your fetch
headers: { 'Content-Type': 'multipart/form-data' },
Other issue is that express does not handle multipart/form-data by itself. You have to use some middleware like multer - https://github.com/expressjs/multer
Express part:
const multer = require('multer');
const upload = multer({ dest: "uploads/" });
app.post("/upload-video", upload.single("video"), (req, res) => {
let video = req.file
// rest of your code
}
And in you react code remember to use video field name:
const fileHandler = (file) => {
const data = new FormData()
data.append('video', file)
// ...

Resources