How to use axios with React to make AJAX requests - node.js

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)

Related

request body is empty on post request when using FormData()

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

How do I use data from POST request for the next GET request

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;

Create script for adding question in React.js

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

Connecting to multiple collections in MongoDB

I am trying to access two collections of my MongoDB for my React app. I have constructed two API_URLs:
const API_URL = window.location.hostname === 'localhost' ? 'http://localhost:5000/api/v1/Sessions' : 'production-url-here'
const API_URL1 = window.location.hostname === 'localhost' ? 'http://localhost:5000/api/v1/members' : 'production-url-here'
The sessions collection is returned with raw data when I put the url into my browser but the members URL returns a "not found" message.
I have mirrored my server and client side code of the sessions collection for my members collection and Im unsure as to what the issue is.
Here is the code for members.js:
const express = require('express');
const Joi = require("joi");
const db = require('../db');
const members = db.get('members');
//Defining the schema for the backend.
const schema1 = Joi.object().keys({
name: Joi.string().min(1).max(100).required(),
bio: Joi.string().min(1).max(500).required(),
latitude: Joi.number().required(),
longitude: Joi.number().required()
});
const router = express.Router();
//Gets all sessions that are found within the DB.
router.get('/', (req, res) => {
members
.find()
.then(allmembers =>{
res.json(allmembers);
});
});
module.exports = router;
Here is the code for Sessions.js :
const express = require('express');
const Joi = require("joi");
const db = require('../db');
const Sessions = db.get('Sessions');
//Defining the schema for the backend.
const schema = Joi.object().keys({
event: Joi.string().min(1).max(100).required(),
venue: Joi.string().min(1).max(500).required(),
address: Joi.string().min(1).max(100).required(),
dtstart: Joi.string().required(),
dtend: Joi.string().required(),
latitude: Joi.number().required(),
longitude: Joi.number().required()
});
const router = express.Router();
//Gets all sessions that are found within the DB.
router.get('/', (req, res) => {
Sessions
.find()
.then(allSessions =>{
res.json(allSessions);
});
});
//POST for when no errors are produced.
router.post('/', (req, res, next) => {
const result = Joi.validate(req.body, schema);
if (result.error == null) {
//Removes the need to write eg) req.body.name below.
const { event, venue, address, latitude, longitude, dtstart, dtend,} = req.body;
const Session = {
event,
venue,
address,
dtstart,
dtend,
latitude,
longitude,
date: new Date()
};
Sessions.insert(Session).then(insertedMessage => {
res.json(insertedMessage);
});
}
else {
next(result.error);
}
});
module.exports = router;
Frontend code:
import React, { Component } from 'react';
import './App.css';
import L from 'leaflet';
import Joi from 'joi';
//import only modules needed or error.
import { Map, TileLayer, Marker, Popup } from 'react-leaflet';
import { Card, CardTitle, CardText } from 'reactstrap';
import {Form, FormGroup, Label, Input } from 'reactstrap';
import { Button } from 'reactstrap';
import Chart from './components/Chart';
var myIcon = L.icon({
iconUrl: 'https://purepng.com/public/uploads/large/purepng.com-harpharpstringedsoundboardfingersmodern-1421526538276nepuu.png',
iconSize: [25, 51],
iconAnchor: [12.5, 51],
popupAnchor: [0, -51],
draggable: true,
});
//Joi creates the schema for validation
const schema = Joi.object().keys({
event: Joi.string().min(1).max(100).required(),
venue: Joi.string().min(1).max(500).required(),
address: Joi.string().min(1).max(100).required(),
dtstart: Joi.string().required(),
dtend: Joi.string().required()
});
const schema1 = Joi.object().keys({
name: Joi.string().min(1).max(100).required(),
bio: Joi.string().min(1).max(500).required(),
latitude: Joi.number().required(),
longitude: Joi.number().required()
});
//URL declaration, if hostname is localhost, request backend. otherwise URL.
const API_URL = window.location.hostname === 'localhost' ? 'http://localhost:5000/api/v1/Sessions' : 'production-url-here'
const API_URL1 = window.location.hostname === 'localhost' ? 'http://localhost:5000/api/v1/members' : 'production-url-here'
class App extends Component {
state = {
location: {
lat: 51.505,
lng: -0.09,
},
UserslocationFound: false,
zoom: 12,
/* Monitors the state of the users inputs (detects changes). */
UsersSession: {
event: '',
venue: '',
address: '',
dtstart: '',
dtend: ''
},
Sessions: [],
members: []
}
componentDidMount() {
//Grabs the markers from the Thesession API to be displayed.
fetch(API_URL)
.then(res => res.json())
.then(Sessions => {
this.setState({
Sessions
});
});
fetch(API_URL1)
.then(res => res.json())
.then(members => {
this.setState({
members
});
});
/*Asks user for location via google alert. */
navigator.geolocation.getCurrentPosition((position) => {
this.setState({
location: {
lat: position.coords.latitude,
lng: position.coords.longitude
},
UserslocationFound: true,
zoom: 15,
draggable: true
});
}, () => {
console.log("Location not given 😞");
fetch('https://ipapi.co/json')
.then(res => res.json())
.then(location => {
console.log(location);
this.setState({
location: {
lat: location.latitude,
lng: location.longitude
},
UserslocationFound: true,
zoom: 15
});
});
});
}
formSubmitted = (event) => {
/* prevents the page from refreshing on submit. */
event.preventDefault();
console.log(this.state.UsersSession);
const UsersSession = {
event: this.state.UsersSession.event,
venue: this.state.UsersSession.venue,
address: this.state.UsersSession.address,
dtstart: this.state.UsersSession.dtstart,
dtend: this.state.UsersSession.dtend
};
//importing Joi to get the result through validation of the inputs with the schema.
const result = Joi.validate(UsersSession, schema);
if(!result.error) {
//fetching against API_URL
fetch(API_URL, {
method: 'POST',
headers: {
'content-type': 'application/json',
},
body: JSON.stringify({
...UsersSession,
latitude: this.state.location.lat,
longitude: this.state.location.lng,
})
}).then(res => res.json())
.then(Sessions => {
console.log(Sessions)
});
}
}
/*Updates the state on UsersSession */
valueChanged = (event) => {
/*declaring event.target as it throws errors in chrome */
const { name,value } = event.target;
/*Sets usersSession to be the value defined in inputs */
this.setState((prevState) => ({
UsersSession: {
...prevState.UsersSession,
[name]: value
}
}))
}
//Sharing of code between React components
render() {
const position = [this.state.location.lat, this.state.location.lng]
return (
<div className ="map">
<Map className ="map" center={position} zoom={this.state.zoom}>
/* tile imported to use over leafletjs*/
<TileLayer
attribution='&copy OpenStreetMap contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
/* displays marker for when users location is given/found */
{ this.state.UserslocationFound ?
<Marker
position={position}
icon={myIcon}>
</Marker> : ''
}
{this.state.Sessions.map(UsersSession => (
<Marker
position={[UsersSession.latitude, UsersSession.longitude]}
icon={myIcon} >
<Popup>
<em>{UsersSession.event}, </em>
{UsersSession.venue} {'\n'}
<Button color="primary" size="sm">More info</Button>
<Chart/>
</Popup>
</Marker>
))}
{this.state.members.map(Users => (
<Marker
position={[Users.latitude, Users.longitude]}
icon={myIcon} >
<Popup>
<em>{Users.name}, </em>
{Users.bio} {'\n'}
<Button color="primary" size="sm">More info</Button>
<Chart/>
</Popup>
</Marker>
))}
</Map>
<Card body className="message-form">
<CardTitle>Welcome to TradMap!</CardTitle>
<CardText>Please input the details of your Session below.</CardText>
<Form onSubmit={this.formSubmitted}>
<FormGroup>
<Label for="name">Session Title</Label>
<Input
/*when the state changes */
onChange={this.valueChanged}
type="text"
name="event"
id="event"
placeholder="..." />
<Label for="startDate">Start Date</Label>
<Input
onChange={this.valueChanged}
type="date"
name="dtstart"
id="dtstart" />
<Label for="EndDate"> End Date </Label>
<Input
onChange={this.valueChanged}
type="date"
name="dtend"
id="dtend" />
<Label for="venue">Session Venue</Label>
<Input
onChange={this.valueChanged}
type="textarea"
name="venue"
id="venue"
placeholder="..." />
<Label for="Address">Session Address</Label>
<Input
onChange={this.valueChanged}
type="textarea"
name="address"
id="address"
placeholder="..." />
</FormGroup>
<Button type ="submit" color="info" disabled={!this.state.UserslocationFound}>submit</Button>
</Form>
</Card>
</div>
);
}
}
export default App;
The issue was referencing the Members collection on the server side. I had not referenced it within the index.js file of the api directory:
const Members = require('./Members');
router.use('/Members', Members);
This then allowed for my collection to be referenced in my front-end and to be accessed through localhost.

ReactNative : variable for FormData() being logged as undefined in ReactNative application when i make an http request with a file

i have been trying to make a post request from my react native app on an android emulator but the object that i am sending in the body of the request is being vvalued as undefined,been trying alot to solve this issue but no success. Please help me
here is the code to my form in the app known as "API.js" its named so just for testing the API endpoints
import React, { Component } from "react";
import {
Text,
TextInput,
View,
TouchableHighlight,
StyleSheet,
Button,
FormData
} from "react-native";
import Permissions from "react-native-permissions";
import ImagePicker from "react-native-image-crop-picker";
import axios from "axios";
var styles = StyleSheet.create({});
var msg = "Select Image";
var data;
export default class API extends Component {
constructor(props) {
super(props);
this.state = {
name: "",
price: "",
size: "",
description: "",
image: "",
popularity: ""
};
}
FormDataFunc() {
let form = new FormData();
form.append("name", this.state.name);
form.append("price", this.state.price);
form.append("size", this.state.size);
form.append("description", this.state.description);
form.append("image", this.state.image);
form.append("popularity", this.state.popularity);
return form;
return form;
}
onChange(e) {
this.setState({ [e.target.name]: e.target.value });
}
Submit() {
axios({
method: "post",
url: "http://192.168.0.102:3000/products",
data: this.FormDataFunc,
headers: {
Accept: "application/json",
"Content-Type": "application/x-www-form-urlencoded"
},
body: this.FormDataFunc
})
.then(() => {
console.log("DONE!");
this.props.navigation.navigate("offersScreen");
})
.catch(err => {
console.log(err);
console.log(this.FormDataFunc);
});
}
componentDidMount() {
Permissions.check("photo").then(response => {
// Response is one of: 'authorized', 'denied', 'restricted', or 'undetermined'
console.log(response);
});
}
render() {
const image = () => {
ImagePicker.openPicker({
multiple: false,
includeBase64: true
}).then(images => {
console.log(images);
this.setState({
images: { data: `\`${images.mime}\`;base64,\`${images.data}\`` }
});
console.log(this.state.images);
msg = "Selected";
});
};
return (
<View>
<TextInput placeholder="Name" name="name" />
<TextInput placeholder="Price" name="price" />
<TextInput placeholder="Size" name="size" />
<TextInput placeholder="Description" name="description" />
<TouchableHighlight onPress={image} name="image">
<Text>{msg}</Text>
</TouchableHighlight>
<TextInput placeholder="Popularity" name="popularity" />
<TouchableHighlight title="Submit" onPress={this.Submit}>
<Text>Send</Text>
</TouchableHighlight>
</View>
);
}
}
here is the code to my backend route "product.js" which recieves the request(node.js and express)
const express = require("express");
const router = express.Router();
const bodyParser = require("body-parser");
const path = require("path");
const cloudinary = require("cloudinary");
const mongoose = require("mongoose");
//Product Model
const product = require("../models/product").product;
router.use(bodyParser.json());
//GET route
router.get("/", (req, res) => {
product.find().then(product => res.json(product));
});
// POST route
cloudinary.config({
cloud_name: "cloud222",
api_key: "783935981748815",
api_secret: "uY47vBS1rI2x5jvFtnXQIjMMqU0"
});
router.post("/", (req, res) => {
//MISC//
let imageUrl;
console.log("starting");
//MISC//
//CLOUDINARY UPLOAD
cloudinary.v2.uploader.upload(req.body.image, (error, result) => {
if (error) {
console.log(error);
console.log(`${req.body.image}`);
} else {
imageUrl = result.secure_url;
//MONGO UPLOAD
var productv = {
name: req.body.name,
price: req.body.price,
size: req.body.size,
description: req.body.description,
image: imageUrl,
popularity: req.body.popularity
};
const productvar = new product(productv);
productvar
.save()
.then(product => console.log(product))
.then(product => res.json(product))
.catch(err => console.log(err));
}
});
//END//
});
module.exports = router;
the data is being logged as undefined and therefore the request doesnt get a response
I think the problem is that you have created a FormData and wanted to post it, but the headers you added is "application/json". You should change it:
headers: {
'content-type': 'multipart/form-data',
'Accept':'multipart/form-data',
},
Hope it works for you.
Problem solved
Had to use onChangeText = instead of onChange as onChange does not return a string

Resources