axios GET request not working in MERN application [closed] - javascript

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 1 year ago.
Improve this question
So, I am attempting a simple, single-page application on the MERN stack that takes notes - a note title and a note content and displays them on the same root route; the data is supposed to also be saved on the backend for later retrieval. At this time, there is no authentication. My backend seems to be working perfectly, but when I connect the front end React application to the backend MongoDB database, my GET request (using axios instance) fails.
My backend renders on localhost:5000, no problem.
But on localhost:3000, I'm seeing this error in App.jsx:
Error: Request failed with status code 404
at createError (createError.js:16)
at settle (settle.js:17)
at XMLHttpRequest.handleLoad (xhr.js:62)
Here's what I have going on:
BACKEND
// server.js
import express from 'express';
import cors from 'cors';
import notes from './api/notes.route.js';
const app = express();
app.use(cors());
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use('/api/v1/notes', notes);
app.use('*', (req, res) => res.status(404).json({ error: 'not found' }));
export default app;
// notes.route.js
import express from 'express';
import NotesController from './notes.controller.js';
const router = express.Router();
router
.route('/')
.get(NotesController.apiGetNotes)
.post(NotesController.apiPostNote)
.put(NotesController.apiUpdateNote)
.delete(NotesController.apiDeleteNote);
export default router;
// notes.controller.js
import NotesDAO from '../dao/notesDAO.js';
class NotesController {
static apiGetNotes = async (req, res, next) => {
const notesPerPage = req.query.notesPerPage
? parseInt(req.query.notesPerPage)
: 20;
const page = req.query.page ? parseInt(req.query.page) : 0;
const { notesList, totalNumNotes } = await NotesDAO.getNotes({
page,
notesPerPage
});
let response = {
notesList,
page,
notesPerPage,
totalNumNotes
};
res.json(response);
};
export default NotesController;
// notesDAO.js
import mongodb from 'mongodb';
const ObjectID = mongodb.ObjectId;
let notes;
class NotesDAO {
// call this on db connection:
static injectDB = async conn => {
if (notes) return;
try {
notes = await conn.db(process.env.NOTESDB_NS).collection('notes');
} catch (e) {
console.error(`unable to establish collection handle in notesDAO: ${e}`);
}
};
static getNotes = async ({ page = 0, notesPerPage = 20 } = {}) => {
let query;
let cursor;
try {
cursor = await notes.find(query);
} catch (e) {
console.error(`unable to issue find command, ${e}`);
return { notesList: [], totalNumNotes: 0 };
}
const displayCursor = cursor.limit(notesPerPage).skip(notesPerPage * page);
try {
const notesList = await displayCursor.toArray();
const totalNumNotes = await notes.countDocuments(query);
return { notesList, totalNumNotes };
} catch (e) {
console.error(
`unable to convert cursor to array or problem counting documents, ${e}`
);
return { notesList: [], totalNumNotes: 0 };
}
};
}
export default NotesDAO;
FRONTEND
// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter, Route } from 'react-router-dom';
import App from './App';
ReactDOM.render(
<React.StrictMode>
<BrowserRouter>
<Route path="/" component={App} />
</BrowserRouter>
</React.StrictMode>,
document.getElementById('root')
);
// App.jsx
import { useState, useEffect } from 'react';
import NoteDataService from './services/note.js';
import Header from './Header';
import Footer from './Footer';
import CreateArea from './CreateArea';
import Notes from './Notes';
const App = () => {
const [notes, setNotes] = useState([]);
useEffect(() => {
retrieveNotes();
}, []);
const retrieveNotes = async () => {
await NoteDataService.getAll()
.then(response => {
console.log(response.data);
setNotes(response.data.notes);
})
.catch(e => console.log(e));
};
return (
<>
<Header />
<CreateArea clicked={addNote} />
<Notes notes={notes} clicked={deleteNote} />
<Footer />
</>
);
};
export default App;
// http-common.js
import axios from 'axios';
export default axios.create({
baseURL: 'http://localhost:5000/api/vi/notes',
headers: {
'Content-type': 'application/json'
}
});
// note.js
import http from '../http-common.js';
class NoteDataService {
getAll() {
return http.get('/');
}
}
export default new NoteDataService();

You have a typo. The backend route is /api/v1/notes, but the frontend is sending requests to /api/vi/notes

Related

Keep getting error with simple ReactJS FORM posting to Express JS server

I am new to ReactJS and trying to find a way to connect my React front end to my Express js backend. To do this, I am just setting up a simple form that sends a POST request after I press a register button in a form.
The problem is I keep getting these error messages in the console.
These are the errors
POST http://localhost:3000/api/users 404 (Not Found)
Error: Request failed with status code 404
at createError (createError.js:16)
at settle (settle.js:17)
at XMLHttpRequest.onloadend (xhr.js:66)
This is the react code
import Proj from './Proj'
import React, {Fragment, useState} from 'react'
import axios from 'axios';
export const Homepage = () => {
const [formData, setFormData] = useState({
name:'',
});
const { name } = formData;
const onChange = e =>
setFormData({...formData, [e.target.name]:e.target.value})
const onSubmit = async e => {
console.log('submitted')
e.preventDefault();
const newUser = {
name,
}
try {
const config = {
headers:{
'Content-Type':'application/json'
} }
const body = JSON.stringify(newUser)
const res = await axios.post('/api/users',body, config)
console.log(res)
} catch (err) {
console.error(err)
}
}
return (
<div className="Landing">
<Proj/>
<section>
<form onSubmit = {e=>onSubmit(e)}>
<input
type="text"
placeholder="Name"
name="name"
value = {name}
onChange = {e =>onChange(e)}
required />
<input type="submit" className="btn btn-primary" value="Register" />
<h1>Contact</h1>
</form>
</section>
</div>
)
}
export default Homepage
This App.js
import { Navbar } from './components/Navbar';
import Homepage from './components/Homepage';
import Projects from './components/Projects';
import {BrowserRouter as Router, Route, Switch} from 'react-router-dom';
import './App.css';
function App() {
return (
<Router>
<div className="App">
<Navbar/>
</div>
<Route exact path="/" component={Homepage} />
<Switch>
<Route exact path="/Projects" component={Projects} />
</Switch>
</Router>
);
}
export default App;
This is my server side JS
const express = require ('express')
const path = require('path');
const app = express()
app.use(express.urlencoded({extended: false}));
app.use('/', require('./routes/api/users'))
// Serve static assets in production
if (process.env.NODE_ENV === 'production'){
app.use(express.static('client/build'))
app.get('*', (req,res)=>{
res.sendFile(path.resolve(__dirname, 'client', 'build', 'index.html'))
})
}
const PORT = 5000
app.listen(process.env.PORT || 5000)
and this is users.js in the api folder in routes
const express = require('express')
const router = express.Router();
router.post('/', async (req,res)=>
{
console.log('its working, and here is the data', req.body)
})
module.exports = router;
client side package.json
"proxy":"http://localhost:5000",
I would really appreciate it if someone can tell me what I am doing wrong or if there is a better way to do things.Thanks.
Instead of
app.use('/', require('./routes/api/users'))
type in
app.use('/api/users', require('./routes/api/users'))
You are posting currently to a route that does not exist.

React Native apisauce can't connect to server network

I'm learning react native and therefore I'm using an api package by the name of "apisauce" version ^2.1.2.
when backend be called with postman, I receive an array of data and when it be called with frontend application, I receive "Network_Error"
My question is what I'm doing wrong?
client.js :
import { create } from "apisauce";
const apiClient = create({
baseURL: "http://127.0.0.1:9000/api",
});
export default apiClient;
listings.js:
import client from "./client";
const endpoint = "/listings";
const getListings = () => client.get(endpoint);
export default { getListings };
App.js
import React, { useEffect } from "react";
import listingsApi from "./app/api/listings";
function App() {
const loadData = async () => {
const response = await listingsApi.getListings();
console.log(response);
};
useEffect(() => {
loadData();
}, []);
return (
<Screen>
</Screen>
);
}
export default App;
And here is the error when I do a console.log:
I have found a solution where instead to set the baseURL to backend URL, I had to set the baseURL to the ip-address of my computer.
information had been found at

React not able to fetch data from Node APiI

I have made an API in Node and can see the data using Postman and by hiting the endpoint in the browser. But, when I try to fetch it using React, I can't see it and am getting few errors. one of them is related to the CORS, which I tried to solve by adding a proxy in the package.json of the client folder but it's still not getting solved. Here's my code:
Error:
img
App.js
import React, { useState, useEffect } from "react";
import "./App.css";
//Pages
//components
import Navbar from "./Components/Navbar";
function App() {
let initialData = [];
const [data, setData] = useState(initialData);
const [isFetched, setIsFetched] = useState(false);
useEffect(() => {
let headers = new Headers({
"Content-Type": "application/json",
Accept: "application/json",
});
fetch(`http://localhost:4000/`, headers)
.then((res) => res.json())
.then(
(result) => {
setData(result);
setIsFetched(true)
console.log("result"+result)
},
// Note: it's important to handle errors here
// instead of a catch() block so that we don't swallow
// exceptions from actual bugs in components.
(error) => {
console.log(error);
}
);
});
return (
<div className="container">
<Navbar data={data} isFetched={isFetched} />
</div>
);
}
export default App;
NodeJs code:
const router = require('express').Router();
router.route('/').get((req, res) => {
let displayData=[{
user:'a',
id:1
},
{
user:'b',
id:2
}
]
res.status(200).json(displayData);
res.send("<h1>Home</h1>")
})
module.exports = router
server.js:
const express = require('express');
const cors = require('cors');
const { pool } = require("./db/dbConfig")
const app = express();
const port = process.env.PORT || 4000;
const homeRouter = require("./routes/home")
//middleware
app.use("/", homeRouter);
app.use(cors());
app.use(express.json());
app.listen(port, () => {
console.log(`We are live on port: ${port}`);
});

Next.js Example Auth - re-routing based on auth, wrapping around other functions

I'm trying to use the next.js with authentication for a small project. The authentication currently works but doesn't allow me to show the data in my navbar.
I was using it with firebase originally BUT NOT ANYMORE!! Now have the authentication set up separately below.
This is the example repo, it has my API in it for auth and the next.js, which i'm trying to integrate together to have login and logout working with header's set for api calls.
https://github.com/Hewlbern/example
Just getting the basic login and logout functionality, so I can control user access to my website. I know this is really simple - just quite confused how to do it with next.js with how document page an app works :S
I am trying to show a table of output from this API, and give the ability to download the outputed json (into a CSV or whatever). So having that available after a search with the query params, and only on a page after the user is logged in, is the point :)
Here's an example of the login functionality I'm using.
import { useRef, useState } from 'react';
import React from 'react'
import PropTypes from 'prop-types'
import Layout from "../components/Layout";
export default function Login() {
const emailRef = useRef<HTMLInputElement>(null);
const passRef = useRef<HTMLInputElement>(null);
const [message, setMessage] = useState<any>(null);
async function handleLogin() {
const resp = await fetch('http://localhost:3001/auth/login', {
method: 'POST',
headers: {
'Content-Type': "application/x-www-form-urlencoded"
},
body: JSON.stringify({
email: emailRef.current?.value,
password: passRef.current?.value
})
});
const json = await resp.json();
setMessage(json);
}
return (
<Layout>
{JSON.stringify(message)}
<input type="text" placeholder="email" ref={emailRef} />
<input type="password" placeholder="password" ref={passRef} />
<button onClick={handleLogin}>Login</button>
</Layout>
);
}
This is posting to this api request
router.post('/login', (req, res) => {
// console.log(req.body)
let email = req.body.email;
let password = req.body.password;
console.log(email,password)
DatabaseService.GetUser(email).then(user => {
if(user===null){
res.sendStatus(404);
}
else{
if(bcrypt.compareSync(password, user[0].password)) {
jwt.sign({user}, 'secretkey', { expiresIn: '30d' }, (err, token) => {
DatabaseService.SetSession(token,JSON.stringify(user[0].user_id)).then(inserted=>{
res.json({
token
});
});
});
} else {
res.sendStatus(500);
}
}
});
});
So just with this small example, hat's wrong with how I'm sending the requests currently? (thinking it's the format the login takes requests in?)
If someone has done something similar or knows how to solve these issues, I'd really appreciate it :)
Cheers!
What I'd recommend here is to create a custom hook which makes use of React's Context API in order to "monitor" the auth state changing. Then wrap you app in that provider and you'll have the flexibility do anything you want with that auth state using your new custom hook.
Here's an example of how that custom hook would look using a authentication with Firebase:
import React, { createContext, useContext, useState } from 'react'
import { auth } from './services' // this is just firebase.auth()
const UserContext = createContext()
export const UserProvider = ({ children }) => {
const [user, setUser] = useState(undefined)
auth.onAuthStateChanged(setUser)
return <UserContext.Provider value={user}>{children}</UserContext.Provider>
}
export const useUser = () => useContext(UserContext)
Now you just need to wrap your app in the UserProvider.
Like this:
import React, { StrictMode } from 'react'
import ReactDOM from 'react-dom'
import { BrowserRouter } from 'react-router-dom'
import App from './app'
import { UserProvider } from './hooks'
const rootElement = document.getElementById('root')
ReactDOM.render(
<StrictMode>
<BrowserRouter>
<UserProvider>
<App />
</UserProvider>
</BrowserRouter>
</StrictMode>,
rootElement
)
Then as an example, let's say you wanted to automatically direct away from your Login page if the use is logged it. You could make use of the useEffect hook, and useHistory hooks to navigate to / if the user is logged in.
Something like this will do:
import React, { useEffect } from 'react'
import { useHistory } from 'react-router-dom'
import { useUser } from './hooks'
const LoginPage = () => {
const history = useHistory()
const user = useUser() // user is undefined if not logged in
useEffect(() => {
if (user) { // will run the condition if user exists
history.push('/')
}
}, [user])
...
}
You could go on to actually use the user data in your navigation bar using something like this:
import React from 'react'
import { Link } from 'react-router-dom'
import { useUser } from './hooks'
const NavBar = () => {
const user = useUser()
return (
<div>
{user ?
<Link to="/profile">Welcome, {user.displayName}</Link> :
<Link to="/login">Login</Link>
}
</div>
)
}
Obviously you can change this for us according to your own needs, but all this should get you going with how work with authentication state in a clean robust manner.

React : POST and GET not found

I'm following this tutorial which I adapt to React Router v4.
I have these files :
auth.js
const express = require('express');
const validator = require('validator');
const router = new express.Router();
function validateLoginForm(payload) {
const errors = {};
let isFormValid = true;
let message = '';
if (!payload || typeof payload.email !== 'string' || payload.email.trim().length === 0) {
isFormValid = false;
errors.email = 'Please provide your email address.';
}
if (!payload || typeof payload.password !== 'string' || payload.password.trim().length === 0) {
isFormValid = false;
errors.password = 'Please provide your password.';
}
if (!isFormValid) {
message = 'Check the form for errors.';
}
return {
success: isFormValid,
message,
errors
};
}
router.post('/login', (req, res) => {
console.log("lol");
const validationResult = validateLoginForm(req.body);
if (!validationResult.success) {
return res.status(400).json({
success: false,
message: validationResult.message,
errors: validationResult.errors
});
}
return res.status(200).end();
});
router.get('/login', (req, res) => {
console.log(req.url);
});
router.get('/', (req, res) => {
console.log(req.url);
console.log("lmao")
});
module.exports = router;
index.js
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
const router = new express.Router();
// tell the app to look for static files in these directories
app.use(express.static('./server/static/'));
app.use(express.static('./client/dist/'));
app.use(bodyParser.urlencoded({extended:false}));
const authRoutes = require('./server/routes/auth');
app.use('/login', authRoutes);
// start the server
app.listen(3000, () => {
console.log('Server is running on http://localhost:3000 or http://127.0.0.1:3000');
});
Base.jsx
import React from 'react';
import PropTypes from 'prop-types';
import { Link, NavLink } from 'react-router-dom';
const Base = ({ child }) => (
<div>
<div className="top-bar">
<div className="top-bar-left">
<NavLink to="/">React App</NavLink>
</div>
<div className="top-bar-right">
<Link to="/login">Log in</Link>
</div>
</div>
{child.render()}
</div>
);
Base.propTypes = {
child: PropTypes.object.isRequired
};
export default Base;
and app.jsx
import React from 'react';
import ReactDom from 'react-dom';
import injectTapEventPlugin from 'react-tap-event-plugin';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import {BrowserRouter, Switch, Route} from 'react-router-dom';
import Base from './components/Base.jsx';
import HomePage from './components/HomePage.jsx';
import LoginPag from './components/LoginPag.jsx';
// for MaterialUI to work properly
injectTapEventPlugin();
const TestLogin = (props) => {
return (<Base child={LoginPag}/>)
};
const TestBase = (props) => {
return(<Base child={HomePage}/>)
};
ReactDom.render((<BrowserRouter><MuiThemeProvider muiTheme={getMuiTheme()}>
<div>
<Switch>
<Route exact path="/" component={TestBase}/>
</Switch>
<Route exact path="/login" component={TestLogin}/>
</div>
</MuiThemeProvider>
</BrowserRouter>), document.getElementById('react-app'));
As you can see, I did a little "workaround" to have everything rendered nicely and it works. But it only works for Client-side routing.
I can't reload pages via f5 or refresh button, nor can I send form and get it through router.post(). It automatically results in a 404 not found.
I printed req.url in router.get('*') to see where the thing goes down and it appears that everywhere I go, the server still receives the address /. I believe the matter is with the <Link to> tag..
How can I fix this and get the server "follow" the client side routing ?
I'm using latest versions of Express, React, and React-Router. Thanks in advance
EDIT : Edited to take into account the remarks made by VivekN
Change your index.js file to the below one:-
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
const router = new express.Router();
// tell the app to look for static files in these directories
app.use(express.static('./server/static/'));
app.use(express.static('./client/dist/'));
app.use(bodyParser.urlencoded({extended:false}));
const authRoutes = require('./server/routes/auth');
app.use('/', authRoutes);
// start the server
app.listen(3000, () => {
console.log('Server is running on http://localhost:3000 or http://127.0.0.1:3000');
});
The problem with your code is that you had written when a request comes to your server which has /login in its path, then that should go inside auth.js file and inside that you should check for router.post('/') method.
Either this or you change the index.js file to be
app.use('/', authRoutes);

Categories