I'm making a script to add Q&A in react.js and mongodb. I have a problem when pressing a button creates the following errors
Failed to load resource: the server responded with a status of 404 (Not Found)
create-quest.component.js:40
Object
data: "↵↵↵↵Error↵↵↵Cannot POST /create↵↵↵"
status: 404
statusText: "Not Found"
headers: {access-control-allow-origin: "*", connection: "close", content-length: "146", content-security-policy: "default-src 'none'", content-type: "text/html; charset=utf-8", …}
config: {url: "http://localhost:3000/create", method: "post", data: "{"title":"aaa","content":"aaa"}", headers: {…}, transformRequest: Array(1), …}
request: XMLHttpRequest {readyState: 4, timeout: 0, withCredentials: false, upload: XMLHttpRequestUpload, onreadystatechange: ƒ, …}
proto: Object
my code is:
import React, { Component } from 'react';
import axios from 'axios';
export default class CreateQuest extends Component {
constructor(props) {
super(props)
this.onChangeTitle = this.onChangeTitle.bind(this);
this.onChangeContent = this.onChangeContent.bind(this);
this.onSubmit = this.onSubmit.bind(this);
this.state = {
title: '',
content: ''
}
}
onChangeTitle(e) {
this.setState({ title: e.target.value })
}
onChangeContent(e) {
this.setState({ content: e.target.value })
}
onSubmit(e) {
e.preventDefault()
const questionObject = {
title: this.state.title,
content: this.state.content
};
axios.post('http://localhost:3000/create', questionObject)
.then(response => {
console.log(response)
})
.catch(error => {
console.log(error.response)
});
this.setState({ title: '', content: '' })
}
render() {
return (
<div className="wrapper">
<form onSubmit={this.onSubmit}>
<div className="form-group">
<label>Add title</label>
<input type="text" value={this.state.title} onChange={this.onChangeTitle} className="form-control" />
</div>
<div className="form-group">
<label>Add content</label>
<input type="text" value={this.state.content} onChange={this.onChangeContent} className="form-control" />
</div>
<div className="form-group">
<input type="submit" value="Create Question" className="btn btn-success btn-block" />
</div>
</form>
</div>
)
}
}
I am beginner in node react and mongo and I dont understand where is error
this is my routes code
module.exports = (app) => {
const questions = require('../controllers/question.controller.js');
const answers = require('../controllers/answer.controller.js');
// Create a new Note
app.post('/questions', questions.create);
app.post('/questions/:questionId/answers', answers.create);
// Retrieve all Notes
app.get('/questions', questions.findAll);
// Retrieve a single Note with noteId
app.get('/questions/:questionId', questions.findOne);
app.get('/questions/:questionId/answers', questions.findOne); // find answers by question id
// Update a Note with noteId
app.put('/questions/:questionId', questions.update);
// Delete a Note with noteId
app.delete('/questions/:questionId', questions.delete);
}
let mongoose = require('mongoose'),
express = require('express'),
router = express.Router();
let question = require('../models/question.model');
router.route('/create').post((req, res, next) => {
questions.create(req.body, (error, data) => {
if (error) {
return next(error)
} else {
console.log(data)
res.json(data)
}
})
});
router.route('/').get((req, res) => {
questions.find((error, data) => {
if (error) {
return next(error)
} else {
res.json(data)
}
})
})
router.route('/edit/:id').get((req, res) => {
questions.findById(req.params.id, (error, data) => {
if (error) {
return next(error)
} else {
res.json(data)
}
})
})
router.route('/update/:id').put((req, res, next) => {
questions.findByIdAndUpdate(req.params.id, {
$set: req.body
}, (error, data) => {
if (error) {
return next(error);
console.log(error)
} else {
res.json(data)
console.log('Question updated successfully !')
}
})
})
router.route('/delete/:id').delete((req, res, next) => {
questions.findByIdAndRemove(req.params.id, (error, data) => {
if (error) {
return next(error);
} else {
res.status(200).json({
msg: data
})
}
})
})
module.exports = router;
my app.js
import React, { Component } from 'react'
import { BrowserRouter as Router, Route } from 'react-router-dom'
import Navbar from './components/Navbar'
import Landing from './components/Landing'
import Login from './components/Login'
import Register from './components/Register'
import Profile from './components/Profile'
import Question from './components/Question'
import Answers from './components/Answer'
import CreateQuest from './components/create-quest.component'
class App extends Component {
render() {
return (
<Router>
<div className="App">
<Navbar />
<Route exact path="/" component={Landing} />
<div className="container">
<Route exact path="/register" component={Register} />
<Route exact path="/login" component={Login} />
<Route exact path="/profile" component={Profile} />
<Route exact path="/questions" component={Question} />
<Route exact path="/create" component={CreateQuest} />
<Route exact path="/answers" component={Answers} />
</div>
</div>
</Router>
)
}
}
export default App
This is an issue with your backend code, rather than your frontend code. The line Cannot POST /create is the key information here. Look at where you defined your route handlers and, if you're using Express, make sure you have something like app.post('/create', (req, res) => { /** some code here **/ }
Edit:
As you have included some of your code, I'm guessing you either didn't tell your Express to app use the router, or you gave it a mount point that is not the root ('/'), so it's looking for your requests as /<mount point>/create rather than /create. Make sure you have a line in your backend app/server file saying app.use(router) and notice that no mount path was provided, so it will look for requests on /create.
However, in your routes file, you are trying to export both the routes function as well as your router, but you are overwriting the module.exports object, rather than exporting them both. You probably want to change those lines to:
module.exports.routes = (app) => ...
and
module.exports.router = router
Related
I am trying to send formdata from react to express server. When sending json payload, i get what is expected. However, when sending data using formdata.append, i get empty req body.
I tried various solutions posted here for similar problem but nothing seemed to work for me.
Hope someone can help
app.js
require('./database/db')
const express = require('express')
const cors = require('cors')
const userRouter = require('./routes/user')
const menuRouter = require('./routes/menu')
const app = express()
app.use(express.json())
app.use(express.urlencoded({ extended: true }))
app.use(cors())
app.use(express.static('public'))
app.use(userRouter)
app.use(menuRouter)
app.listen(9000, () => console.log('Server started at port: 9000'))
route i want to call
router.post(
'/addMenu',
[
check('name', 'Menu name is required!').not().isEmpty(),
check('price', 'Price is required!').not().isEmpty(),
check('category', 'Category is required!').not().isEmpty(),
],
verifyAuth,
(req, res) => {
console.log(req.body)
// body is empty here
})
react bootstrap form
import { Component } from 'react'
import axios from '../axios'
import { Link } from 'react-router-dom'
import { Button, Form, Card } from 'react-bootstrap'
export default class AddMenu extends Component {
constructor(props) {
super(props)
this.state = {
name: '',
price: '',
category: '',
image: '',
}
this.inputHandler = this.inputHandler.bind(this)
this.inputHandler = this.inputHandler.bind(this)
this.addMenu = this.addMenu.bind(this)
}
inputHandler = (e) => {
this.setState({
[e.target.name]: e.target.value,
})
}
fileHandler = (e) => {
this.setState({
image: e.currentTarget.files[0],
})
}
addMenu = (e) => {
e.preventDefault()
const { name, price, category, image } = this.state
const data = new FormData()
data.append('name', name)
data.append('price', price)
data.append('category', category)
data.append('file', image)
axios
.post('/addMenu', data)
.then((response) => {
if (response.data.success) {
alert(response.data.menu)
} else {
alert('something went wrong')
}
})
.catch()
}
render() {
return (
<div className='col-lg-12 col-centered' style={{ height: '44rem' }}>
<Card
style={{
width: '20rem',
marginLeft: '420px',
marginTop: '80px',
float: 'left',
height: '34rem',
}}
>
<Card.Img
variant='top'
src='https://image.freepik.com/free-vector/food-delivery-service-fast-food-delivery-scooter-delivery-service-illustration_67394-869.jpg'
/>
<Card.Body>
<Card.Title>Add Menu</Card.Title>
<Card.Text>
Although a great restaurant experience must include great food, a bad restaurant experience can be achieved through bad service alone.
Ideally, service is invisible.
</Card.Text>
<Button as={Link} to='/' variant='info'>
Go to Home
</Button>
</Card.Body>
</Card>
<Card
style={{
width: '22rem',
marginTop: '78px',
float: 'left',
height: '34rem',
}}
>
<Form className='add-menu' onSubmit={this.addMenu}>
<h2>Add Menu</h2>
<Form.Group controlId='formBasicName'>
<Form.Label>Restaurant Name</Form.Label>
<Form.Control
type='text'
name='name'
placeholder='Enter Restaurant Name'
value={this.state.name}
onChange={(event) => this.inputHandler(event)}
/>
</Form.Group>
<Form.Group controlId='formBasicPrice'>
<Form.Label>Enter Price</Form.Label>
<Form.Control type='text' name='price' placeholder='Price' value={this.state.price} onChange={(event) => this.inputHandler(event)} />
</Form.Group>
<Form.Group controlId='formBasicCategory'>
<Form.Label>Enter Category</Form.Label>
<Form.Control
name='category'
type='text'
placeholder='Enter Menu Category'
value={this.state.category}
onChange={(event) => this.inputHandler(event)}
/>
</Form.Group>
<Form.Group controlId='formBasicImage'>
<Form.Label>Enter Category</Form.Label>
<Form.Control name='image' type='file' onChange={this.fileHandler} />
</Form.Group>
<Button className='btn-lg btn-block' variant='info' type='submit'>
Add Menu
</Button>
</Form>
</Card>
<br />
<br />
<br />
</div>
)
}
}
routes/menu implementation
const router = require('express').Router()
const { verifyAuth } = require('../middleware/auth')
const upload = require('../middleware/fileUpload')
const Menu = require('../models/Menu')
const { check, validationResult } = require('express-validator')
// add a menu item
router.post(
'/addMenu',
[
check('name', 'Menu name is required!').not().isEmpty(),
check('price', 'Price is required!').not().isEmpty(),
check('category', 'Category is required!').not().isEmpty(),
],
verifyAuth,
(req, res) => {
console.log(req.body)
if (req.authUser.userType === 'Restaurant') {
const validationErr = validationResult(req)
if (validationErr.isEmpty()) {
let image = null
const { name, price, category } = req.body
if (req.file) {
upload(req, res, (err) => {
if (err) {
response.status(500).json({ success: false, message: err })
} else {
image = req.file.filename
}
})
}
const newMenu = new Menu({ name, price, category, addedBy: req.authUser._id, image })
newMenu
.save()
.then((menu) => res.status(201).json({ success: true, message: 'Menu added', menu }))
.catch((error) => res.status(500).json({ success: false, message: error.message }))
} else {
res.status(400).json({ success: false, errors: validationErr.array() })
}
} else {
res.status(403).json({ success: true, message: 'Insufficient privileges' })
}
}
)
// get all menu items
router.get('/menus', (req, res) => {
Menu.find()
.populate('addedBy', '-_id name')
.then((menus) => res.status(200).json({ success: true, menus }))
.catch((error) => res.status(500).json({ success: false, message: error.message }))
})
module.exports = router
Even in Postman x-www-form-urlencoded sends the data but form-data does not
Form data will get empty object if there is no file given to it via routes like this.
import multer from 'multer';
router.post(
'/addMenu',
multer().single("keyNameForFile"),
[
check('name', 'Menu name is required!').not().isEmpty(),
check('price', 'Price is required!').not().isEmpty(),
check('category', 'Category is required!').not().isEmpty(),
],
verifyAuth,
(req, res) => {
console.log(req.body)
// body is empty here
})
Don't know what cause this behaviour but use form-data when you are sending some file like image doc etc.
You should set the Content-Type of your request header as Content-Type: application/x-www-form-urlencoded this will allow express to access you form data in the body
To set the header in axios you can perform it like this
const config = {
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
};
and you perform a request to you backend with the header set like this
axios.post('/addMenu', data, config)
.then({ /*...*/});
in your axios request you will need to specify the content type in the headers
of the request. What I usually do also, is specify my agrs as an object for just
for annotation purposes
like this:
axios({
method: 'post',
url: '/addMenu',
data: data,
headers: { 'Content-Type': 'application/json' },
})
.then((response) => {
if (response.data.success) {
alert(response.data.menu)
} else {
alert('something went wrong')
}
})
.catch((error) => {
//handle error
console.log(error);
});
EDIT:
I just noticed that you are trying to send a file as well...haha
to send a file through to express, you will need to get the package called multer to handle file uploads for you
npm i --save multer
then add it when configuring your server
const multer = require('multer');
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cors());
app.use(multer().any());
once you have that done, in your request on the axios side, do it like this:
axios({
method: 'post',
url: '/addMenu',
data: data,
headers: { 'Content-Type': 'multipart/form-data' },
})
.then((response) => {
if (response.data.success) {
alert(response.data.menu)
} else {
alert('something went wrong')
}
})
.catch((error) => {
//handle error
console.log(error);
});
and finally, to handle your files on your server they will show in the request
object like this:
request.files // which will be an array of file objects
please try this...i know its long but i had this issue once and used this solution
As per #ash.io answer BIG NOTICE for MERN stackers! : my case was as it used to return empty object , but when I added (mounted) app.use(express.json()) middleware all sorted out ! Currently MongoDB shows results just fine ! For anyone who interested into quick useForm snippet , here it goes React-useForm boilerplate
Attempting to make an AJAX request with axios and display the data in React component. Getting an error saying map is not a function, and 404 on the GET request. The POST request works great. Tested in Postman and the GET request works if http://localhost:8080/breakfast-tacos...can get the data to display in the console, but not in my CommentBox component. What am I doing wrong?
//COMMENTBOX COMPONENT
import React from 'react';
import Axios from 'axios';
import Rater from 'react-rater';
import './comment-styles.scss';
export class CommentBox extends React.Component {
constructor(props) {
super(props);
this.state = {
reviews: []
}
this.addReview = this.addReview.bind(this);
};
addReview() { /*Post Request*/
Axios({
method: 'POST',
url: 'http://localhost:8080/breakfast-tacos/reviews',
headers: {
'Content-Type': 'application/json'
}
}).then(response => {
this.setState({ reviews: response.data.reviews })
}).catch(error => console.log(error))
}
componentDidMount() {
Axios.get('http://localhost:8080/breakfast-tacos/reviews') /*Get Request*/
.then(reviews => {
this.setState({ reviews: reviews.data })
})
.catch(err => console.log(err))
};
render() {
return (
<div id="commentWrapper">
<div className="commentHeader">
<h5>Leave a Rating!</h5>
<Rater style={{fontSize: '35px'}} />
<button id="submitRatingBtn" type="submit">Submit</button>
<form action="/breakfast-tacos" method="POST">
<textarea className="reviewTextBox" maxLength="250" placeholder="Write a review..." name="reviews"></textarea>
<button id="submitReviewBtn" type="submit" onClick={this.addReview}>Submit</button>
</form>
</div>
<hr />
<div className="reviews">
<span className="user">
<h6>username:</h6>
</span>
<span className="text">
{this.state.reviews.map((review, text) => { /*Where I want to display the data*/
return (
<p key={text}>
{review}
</p>
)
})}
</span>
</div>
<hr />
</div>
)
}
};
//EXPRESS SERVER
require('dotenv').config();
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
const port = process.env.PORT || 8080;
const cors = require('cors');
const MongoClient = require('mongodb').MongoClient;
const dbUrl = process.env.DATABASE_URL;
MongoClient.connect(dbUrl, { useNewUrlParser: true, useUnifiedTopology: true }, (err, client) => {
// CHECK FOR CONNECTION TO DATABASE ERRORS, VERIFY DATABASE CONNECTION
if (err) throw err;
console.log(`Database connected successfully!`);
//GLOBAL DATABASE VARIABLES
const db = client.db('recipedb');
const dbCollection = db.collection('breakfast-tacos');
//MIDDLEWARES
app.use(cors());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true} ));
//POST OR CREATE ROUTES
app.post('/breakfast-tacos', (req, res) => {
dbCollection.insertOne(req.body)
.then(results => {
console.log('1 document inserted...');
})
.catch(error => console.error(error));
});
//GET OR READ ROUTES
app.get('/breakfast-tacos/', (req, res) => {
dbCollection.find().toArray()
.then(results => {
res.send({ reviews: results });
})
.catch(error => console.error(error))
});
});
//SERVER
app.listen(port, () => {
console.log(`Server is running on port ${port}...`);
});
// MAIN APP COMPONENT
import 'bootstrap/dist/css/bootstrap.css';
import React from 'react';
import ReactDOM from 'react-dom';
import Axios from 'axios';
import {
BrowserRouter as Router,
Switch,
Route,
} from 'react-router-dom';
import { Home } from './home.js';
import { Breakfast } from './breakfast.js';
import { LunchDinner } from './lunch-dinner.js';
import { Sides } from './sides.js';
import { Desserts } from './desserts.js';
import { Snacks } from './snacks.js';
import { Misc } from './misc.js';
import { About } from './about.js';
class App extends React.Component {
componentDidMount() {
Axios({ /*This GET request shows an array of data in the console*/
method: "GET",
url: "http://localhost:8080/breakfast-tacos",
headers: {
"Content-Type": "application/json"
}
}).then(res => {
console.log(res.data.reviews);
})
.catch(error => console.log(error))
}
render() {
return (
<Router>
<div>
<Switch>
<Route path="/" exact component={Home} />
<Route path="/breakfast" exact component={Breakfast} />
<Route path="/lunch-dinner" exact component={LunchDinner} />
<Route path="/sides" exact component={Sides} />
<Route path="/desserts" exact component={Desserts} />
<Route path="/snacks" exact component={Snacks} />
<Route path="/misc" exact component={Misc} />
<Route path="/about" exact component={About} />
</Switch>
</div>
</Router>
)
}
}
ReactDOM.render(<App />, document.getElementById('root'));
// ERRORS
/*Error which indicates something wrong with the url*/
/*UPDATE: I removed "reviews" after testing in Postman and no longer getting 404 error, now getting map is not a function error*/
xhr.js:177 GET http://localhost:8080/breakfast-tacos/reviews 404 (Not Found)
/*How the data is being displayed in the console*/
18) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]0: {_id: "600f6f2510e2f91da0a0b4da", reviews: "Testing 1"}1: {_id: "600f6fb410e2f91da0a0b4db", reviews: "Testing 1"}2: {_id: "6010e787ea6c5c1fb43f471d", reviews: "Testing 2"}3: {_id: "6010ee90ea6c5c1fb43f471e", reviews: "Test 3"}4: {_id: "6010fb2ec91e161344cacf39"}5: {_id: "6010fb33c91e161344cacf3a"}6: {_id: "6010fb42c91e161344cacf3b"}7: {_id: "6010fb51c91e161344cacf3c", reviews: "TESTING"}8: {_id: "6010fb5dc91e161344cacf3d"}9: {_id: "6010fb6bc91e161344cacf3e"}10: {_id: "6010fbe9c91e161344cacf3f"}11: {_id: "6010fc0cc91e161344cacf40"}12: {_id: "6010fc0dc91e161344cacf41"}13: {_id: "6010fc0dc91e161344cacf42"}14: {_id: "6010fc0ec91e161344cacf43"}15: {_id: "6010fc12c91e161344cacf44"}16: {_id: "6010fc785969750b0875580d", reviews: "fehafasdfasd"}17: {_id: "60120812fc750a0830ca1052", reviews: "does this work"}length: 18__proto__: Array(0)
Hello I'm developing a react-Node Js app and I'm migrating a component class to a functional component one, now I'm getting the issue: createError.js:16 Uncaught (in promise) Error: Request failed with status code 500 the same method worked well in the component class. The next is the code of my react component:
import React from "react";
import { makeStyles } from "#material-ui/core/styles";
import { useState } from "react";
import axios from "axios";
import TextField from "#material-ui/core/TextField";
import Button from "#material-ui/core/Button";
import Typography from "#material-ui/core/Typography";
const useStyles = makeStyles((theme) => ({
root: {
"& > *": {
margin: theme.spacing(1),
width: "25ch",
},
},
}));
export default function BasicTextFields(props) {
const classes = useStyles();
const [collection, setCollection] = useState("");
const [field, setField] = useState("");
const [integrationName, setIntegrationName] = useState("");
const [total, setTotal] = useState("");
function handleChange(evt, field) {
setField(evt.target.value);
console.log("new value", evt.target.value);
}
function handleSubmit(event) {
console.log("Event delete:" + event);
var params = new URLSearchParams();
params.append("collection", collection);
params.append("field", field);
params.append("integrationName", integrationName);
var request = {
params: params,
};
console.log("request: 127.0.0.1:" + request);
axios.delete(`http://127.0.0.1:8081/firestore/`, request).then((res) => {
console.log("react1: ", res);
console.log("react2: ", res.data);
this.setState({ total: res.data });
});
}
function handleSubmitCount(event) {
console.log("...count...");
var params = new URLSearchParams();
params.append("collection", collection);
params.append("field", field);
params.append("integrationName", integrationName);
var request = {
params: params,
};
console.log("request 127.0.0.1:" + request);
console.log("BACKEND_HOST:", process.env);
axios.get(`http://127.0.0.1:8081/firestore/`, request).then((res) => {
this.setState({ total: res.data });
});
}
return (
<span>
<form className={classes.root} noValidate autoComplete="off">
<TextField
name="collection"
onChange={(e) => setCollection(e.target.value)}
helperText="Collection"
variant="outlined"
required
margin="dense"
/>
<TextField
name="field"
onChange={(e) => setCollection(e.target.value)}
helperText="Field"
variant="outlined"
required
margin="dense"
/>
<TextField
name="value"
onChange={(e) => setCollection(e.target.value)}
helperText="Value"
variant="outlined"
required
margin="dense"
/>
<br />
<Button
variant="contained"
color="primary"
onClick={(e) => handleSubmit(e)}
disableElevation
type="button"
>
Delete Registers
</Button>
<Button
variant="contained"
color="primary"
onClick={(e) => handleSubmitCount(e)}
disableElevation
type="button"
>
Count Registers
</Button>
<br />
<br />
<Typography variant="h6" gutterBottom>
{total}
</Typography>
</form>
</span>
);
}
I'm getting the error, when I click in the button and use the handleSubmitCount method, for some reason it is not calling the axios request and it's throwing the issue mentioned before.
Any ideas?
Seems to have passed some months but here it goes... (I have also had the same issue.
You are, most likely, getting an HTTP error code and Axios is rejecting the promise.
You will need to catch it and get the message from the server (if any).
axios.get(`http://127.0.0.1:8081/firestore/`, request)
.then((res) => {
this.setState({ total: res.data });
})
.catch((error) => {
// here you will have access to error.response
console.log(error.response)
});
500 is a server error. try examining your error:
axios.get("http://127.0.0.1:8081/firestore/", request).then((res) => {
this.setState({ total: res.data });
}).catch(error => console.error(error));
Check the Axios documents, you'll find that delete method does not receive a body param which is what you're sendind after that colon. Request must only have a url parameter and an options/configuration param (optional).
https://github.com/axios/axios/blob/master/README.md#axiosdeleteurl-config
I suggest you to make the request like this:
axios.delete(`http://127.0.0.1:8081/firestore/${params.toString()}`).then(callback);
As request only contains your params, this object won't be required anymore.
Bear in mind that this params belong to a query string param type, and thats the purpose on URLSearchParams interface.
https://developer.mozilla.org/es/docs/Web/API/URLSearchParams
Good luck!
Try this way please
function requestObject(url,method, params) {
let configObject = {
"url": url,
"method": method,
"params": params
}
return configObject
}
function handleSubmit(event) {
console.log("Event delete:" + event);
let data= {
"collection": collection, "field" : field,
"integrationName":integrationName
};
let configObejct = requestObject("http://127.0.0.1:8081/firestore/", "delete", data);
axios.request(configObejct).then((res) => {
console.log("react1: ", res);
console.log("react2: ", res.data);
this.setState({ total: res.data });
});
}
Given,
axios.get('').catch(e => console.log(e.response)
In order to get axios actual response you need to do e.response.
Also, in the screenshot you can see e is throws a error text message.
I'm trying to build a web app that uses Spotify API now. I want it to send a search keyword that an user submits to the server and send back its search result to the front end. The problem is I get a 404 status code for the fetch call. The POST request works fine.
Main.js
import React, { Component } from "react";
import SingerCard from "./SingerCard";
import axios from "axios";
export class Main extends Component {
constructor(props) {
super(props);
this.state = {
keyword: "",
artists: [],
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(e) {
this.setState({ keyword: e.target.value });
}
handleSubmit(e) {
e.preventDefault();
axios
.post(
"http://localhost:4000/search_result",
{
keyword: this.state.keyword,
},
{
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
},
}
)
.then(function (res) {
console.log(res);
})
.catch(function (err) {
console.log(err);
});
}
componentDidMount() {
fetch("http://localhost:4000/api")
.then((res) => res.json)
.then((artists) => {
this.setState({ artists });
});
}
render() {
return (
<div className="main">
<form onSubmit={this.handleSubmit}>
<label htmlFor="search">Search an artist: </label>
<span>
<input
type="search"
value={this.state.keyword}
onChange={this.handleChange}
name="keyword"
/>
<button type="submit" value="Submit">
Search
</button>
</span>
</form>
<br />
<div className="container">
{this.state.artists.map((elem) => (
<SingerCard
images={elem.images}
name={elem.name}
artists={this.state.artists}
/>
))}
{console.log(this.state.artists)}
</div>
<br />
</div>
);
}
}
export default Main;
server.js
const express = require("express");
const SpotifyWebApi = require("spotify-web-api-node");
const bodyParser = require("body-parser");
const cors = require("cors");
const app = express();
const port = 4000 || process.env.PORT;
require("dotenv").config();
app.use(express.json());
app.use(cors());
app.use(bodyParser.urlencoded({ extended: true }));
// Create the api object with the credentials
var spotifyApi = new SpotifyWebApi({
clientId: process.env.CLIENT_ID,
clientSecret: process.env.CLIENT_SECRET,
});
// Retrieve an access token.
spotifyApi.clientCredentialsGrant().then(
function (data) {
console.log("The access token expires in " + data.body["expires_in"]);
console.log("The access token is " + data.body["access_token"]);
// Save the access token so that it's used in future calls
spotifyApi.setAccessToken(data.body["access_token"]);
},
function (err) {
console.log("Something went wrong when retrieving an access token", err);
}
);
app.post("/search_result", (req, res) => {
console.log(req.body.keyword);
spotifyApi.searchArtists(req.body.keyword).then(function (data) {
var search_res = data.body.artists.items;
res.json(search_res);
app.get("http://localhost:/api", (req, res) => {
res.json(search_res);
res.end();
});
res.end();
}),
function (err) {
console.log(err);
};
});
app.listen(port, () => console.log(`It's running on port ${port}`));
I think the app.get() in the app.post() causes the error but I can't figure out another way to send the search result back.
You're getting a 404 because the get method is not correctly defined.
Update your server code to define the get method to just keep the pathname, like this:
app.get("/api", (req, res) => {
// ...
}
Currently, you are defining this route inside the app.post. The get route definition should be outside of the post route.
Use Axios.get
import React, { Component } from "react";
// import SingerCard from "./SingerCard";
import axios from "axios";
export class Main extends Component {
constructor(props) {
super(props);
this.state = {
keyword: "",
artists: []
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(e) {
this.setState({ keyword: e.target.value });
}
handleSubmit(e) {
e.preventDefault();
const headers = {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*"
};
axios.post(
"https://jsonplaceholder.typicode.com/users",
{ keyword: this.state.keyword },
{ headers: headers }
)
.then(res => {
console.log(res.data);
})
.catch(err => {
console.log(err);
});
}
componentDidMount() {
axios.get("https://jsonplaceholder.typicode.com/users").then(res => {
this.setState({
artists: res.data
});
});
}
render() {
return (
<div className="main">
<form onSubmit={this.handleSubmit}>
<label htmlFor="search">Search an artist: </label>
<span>
<input
type="search"
value={this.state.keyword}
onChange={this.handleChange}
name="keyword"
/>
<button type="submit" value="Submit">
Search
</button>
</span>
</form>
<br />
<div className="container">
{this.state.artists.map(elem => (
<div key={elem.id}>
<ul>
<li>{elem.name}</li>
</ul>
</div>
))}
</div>
</div>
);
}
}
export default Main;
I've built an app that is running well when on the server generated from the npm start command, but when I set up a server with npm live-server, or a python simple HTTPserver, I'm getting this error when I navigate to the /login route.
Saying "Cannot GET /login". But at no point do I send a get request from what I can tell. When I navigate to the /login route, all that should appear is a form that takes in user info and sends a post request to get a token.
Here are all of my user Actions in my UserActions.js file. As you can see it's very minimal (I don't even have a /register, this is because I only have 1 admin user already in the database and have no need to register)
usrerActions.js
import {
SET_USER,
SET_ERRORS,
CLEAR_ERRORS,
LOADING_UI,
SET_UNAUTHENTICATED
} from "../types";
import axios from 'axios'
export const loginUser = (userData, history) => (dispatch) => {
dispatch({ type: LOADING_UI });
axios
.post("/login", userData)
.then((res) => {
const FBIdToken = `Bearer ${res.data.token}`;
localStorage.setItem("FBIdToken", `Bearer ${res.data.token}`);
axios.defaults.headers.common['Authorization'] = FBIdToken;
// dispatch(getUserData());
dispatch({ type: CLEAR_ERRORS })
history.push("/");
})
.catch(err => {
dispatch({
type: SET_ERRORS,
payload: err.response.data
})
});
}
export const logoutUser = () => (dispatch) => {
localStorage.removeItem('FBIdToken');
delete axios.defaults.headers.common['Authorization'];
dispatch({ type: SET_UNAUTHENTICATED })
}
export const getUserData = () => (dispatch) => {
axios.get('/user')
.then(res => {
dispatch({
type: SET_USER,
payload: res.data
})
})
.catch(err => console.log(err));
}
My app.js with routes
...
const token = localStorage.FBIdToken;
if (token) {
const decodedToken = jwtDecode(token);
if (decodedToken.exp * 1000 < Date.now()) {
store.dispatch(logoutUser());
window.location.href = "/login";
} else {
store.dispatch({ type: SET_AUTHENTICATED });
axios.defaults.headers.common["Authorization"] = token;
}
}
function App() {
document.documentElement.classList.remove("nav-open");
React.useEffect(() => {
document.body.classList.add("index");
return function cleanup() {
document.body.classList.remove("index");
};
});
return (
// <MuiThemeProvider theme={theme}>
<Provider store={store}>
<Router>
<div className="main">
<Switch>
<Route exact path="/" component={home} />
<Route exact path="/products" component={products} />
<Route exact path="/retreats" component={retreats} />
<Route exact path="/tarot" component={tarot} />
<Route
path="/artist"
render={props => <ProfilePage {...props} />}
/>
<Route exact path="/login" component={login} />
</Switch>
</div>
<Footer />
</Router>
</Provider>
// </MuiThemeProvider>
);
}
export default App;
And my login.jsx page component
import React, { Component } from "react";
...
export class login extends Component {
constructor(){
super();
this.state = {
email: '',
password: '',
errors: {}
}
}
componentWillReceiveProps(nextProps) {
if(nextProps.UI.errors) {
this.setState({ errors: nextProps.UI.errors })
}
}
handleSubmit = (event) => {
event.preventDefault();
const userData = {
email: this.state.email,
password: this.state.password
}
this.props.loginUser(userData, this.props.history);
}
handleChange = (event) => {
this.setState({
[event.target.name]: event.target.value
})
}
render() {
// loading was before: { classes, UI: { loading } }
const { classes, loading } = this.props;
const { errors } = this.state;
return (
<>
<IndexNavbar />
<ProfilePageHeader />
<Grid container className={classes.form}>
<Grid item sm />
<Grid item sm>
<ChangeHistoryIcon />
<Typography variant="h3" className={classes.pageTitle}>
Login
</Typography>
<form noValidate onSubmit={this.handleSubmit}>
<TextField
id="email"
name="email"
type="email"
label="Email"
className={classes.textField}
helperText={errors.email}
error={errors.email ? true : false}
value={this.state.email}
onChange={this.handleChange}
fullWidth
/>
<TextField
id="password"
name="password"
type="password"
label="Password"
className={classes.textField}
helperText={errors.password}
error={errors.password ? true : false}
value={this.state.password}
onChange={this.handleChange}
fullWidth
/>
{errors.general && (
<Typography variant="body2" className={classes.customError}>
{errors.general}
</Typography>
)}
<Button
type="submit"
variant="contained"
color="primary"
className={classes.button}
>
Login
{loading && (
<CircularProgress size={30} className={classes.progress} />
)}
</Button>
</form>
</Grid>
<Grid item sm />
</Grid>
</>
);
}
}
login.propTypes = {
classes: PropTypes.object.isRequired,
loginUser: PropTypes.func.isRequired,
user: PropTypes.object.isRequired,
UI: PropTypes.object.isRequired
}
const mapStateToProps = (state) => ({
user: state.user,
UI: state.UI
});
const mapActionsToProps = {
loginUser
}
export default connect(mapStateToProps, mapActionsToProps)(withStyles(styles)(login));
Does anybody know why I get this error when I'm obviously sending a post request?
any help is greatly appreciated!
ANDit was brought to my attention that it might be an issue with my backennd not rendering the index file? I'm not sure what to do here. this is my backend index file
const functions = require('firebase-functions');
const app = require('express')();
const FBAuth = require('./util/fbAuth')
const cors = require('cors');
app.use(cors());
const { getAllPosts, createOnePost, getThePost, deletePost, uploadImage } = require('./handlers/posts');
const { login } = require('./handlers/users');
// Posts Routes
app.get('/posts', getAllPosts);
app.get('/post/:postId', getThePost);
app.post("/post", FBAuth, createOnePost);
app.delete('/post/:postId', FBAuth, deletePost);
app.post('/post/:postId/image', FBAuth, uploadImage);
//TODO update post
// Login Route
app.post('/login', login)
exports.api = functions.https.onRequest(app)
So I assume you're using react router dom. Are you using < Link to='/login' >? or are you using another way that actually sends a get request such as an a tag?
React Router Dom needs you to use their components to navigate on the react side of things.