I am trying to add a search query to the server-side endpoint, which calls swapi - the Star Wars API https://swapi.co/ and lists people by name.
Here's what the fetch call to the backend in App.js looks like (I am using reactJS framework for that):
import React, { Component } from 'react';
class App extends Component {
constructor() {
super();
this.state = {
searchResult: [],
}
}
searchPersonByName = (event) => {
fetch('/people/?search='+ event.target.value)
.then(response => response.json())
.then(response => {
//let searchResult = JSON.parse(responseBody).results;
console.log(response);
this.setState({ searchResult: response.results });
})
}
render() {
return (
<div className="pageStyle">
<div className="searchBar">
<input type="text"
placeholder="search for a person"
onChange={this.searchPersonByName}>
</input>
{Object.keys(this.state.searchResult).map((item, i) => (
<li key={i}>
<span>{this.state.searchResult[item].name}</span>
</li>
))}
</div>
</div>
);
}
}
export default App;
on the backend:
//Dependencies
const swapi = require('swapi-node');
const express = require('express'); //express server
const app = express();
app.use(express.static('public'))
//Search people endpoint
//format of the search string:
// https://swapi.co/api/people/?search=
app.get('/people', (req, res) => {
let query = req.query.search;
console.log(query);
swapi.get('https://swapi.co/api/people/?search=' + query).then((result) => {
console.log(result.results);
let results = result.results;
res.send({ results });
}).catch((err) => {
console.log(err);
});
});
//server listening on specified port
app.listen(4000, () => console.log('Listening on port 4000!'))
Right now the search query return the people from the first page only. What is missing?
You are not passing a search term to the backend with your fetch request.
If you really want to search for every change in the input field, you could use the event.target.value as search term.
searchPersonByName = event => {
fetch(`/people?search=${event.target.value}`)
.then(response => response.json())
.then(response => {
this.setState({ searchResult: response.results });
});
};
You also don't need to specify the query parameters in the backend route.
app.get('/people', (req, res) => { ... })
fetch call in App.js
import React, { Component } from 'react';
class App extends Component {
constructor() {
super();
this.state = {
searchResult: [],
}
}
searchPersonByName = (event) => {
fetch('/people/?search='+ event.target.value)
.then(response => response.json())
.then(response => {
//let searchResult = JSON.parse(responseBody).results;
console.log(response);
this.setState({ searchResult: response.results });
})
}
render() {
return (
<div className="pageStyle">
<div className="searchBar">
<input type="text"
placeholder="search for a person"
onChange={this.searchPersonByName}>
</input>
{Object.keys(this.state.searchResult).map((item, i) => (
<li key={i}>
<span>{this.state.searchResult[item].name}</span>
</li>
))}
</div>
</div>
);
}
}
export default App;
and backend:
//Dependencies
const swapi = require('swapi-node');
const express = require('express'); //express server
var bodyParser = require('body-parser');
const app = express();
app.use(express.static('public'));
app.use(bodyParser.json({ type: 'application/json' }));
var API_URL = 'http://swapi.co/api/';
//Search people endpoint
//format of the search string:
// https://swapi.co/api/people/?search=
app.get('/people', (req, res) => {
let query = req.query.search;
console.log(query);
swapi.get('http://swapi.co/api/people/?search=' + query).then((result) => {
console.log(result.results);
let results = result.results;
res.send({ results });
}).catch((err) => {
console.log(err);
});
});
//server listening on specified port
app.listen(4000, () => console.log('Listening on port 4000!'))
Related
I'm building a web app using Node, Express, Cors and Body Parser. The app uses the fetch api to fetch data from online apis. Now I have written all the code with a server.js file, an index.html and an app.js. My server.js file contains the express server functions and middleware. My app.js contains the main functionality. Here are my files:
Index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Weather Journal</title>
</head>
<body>
<div id="app">
<div class="holder headline">
Weather Journal App
</div>
<form id="userInfo">
<div class="holder zip">
<label for="zip">Enter City here</label>
<input type="text" id="city" placeholder="enter city here" required>
</div>
<div class="holder feel">
<label for="date">Enter departure date</label>
<input type="datetime-local" id="date" required>
<button id="submitBtn" type="submit"> Generate </button>
</div>
</form>
<div class="holder entry">
<div class="title">Most Recent Entry</div>
<div id="entryHolder">
<div id="lat"></div>
<div id="lng"></div>
<div id="countryName"></div>
<div id="temp"></div>
</div>
</div>
</div>
<script src="app.js" type="text/javascript"></script>
</body>
</html>
My app.js:
const geoURL = "http://api.geonames.org/searchJSON?";
const geoUsername = `rohanasif1990`;
const weatherURL = "https://api.weatherbit.io/v2.0/forecast/daily?"
const weatherKey = "20028a8267a24bba9a807362767bc4a7"
let d = new Date();
let newDate = d.getMonth() + 1 + "." + d.getDate() + "." + d.getFullYear();
const submitBtn = document.getElementById("submitBtn");
submitBtn.addEventListener("click", (e) => {
e.preventDefault();
const city = document.getElementById("city").value;
if (city !== "") {
getCity(geoURL, city, geoUsername)
.then(function (data) {
getWeather(weatherURL, weatherKey, data["geonames"][0]['lat'], data["geonames"][0]['lng'])
}).then(weatherData => {
postWeatherData("/addWeather", { temp: weatherData })
}).then(function () {
receiveWeatherData()
}).catch(function (error) {
console.log(error);
alert("Invalid city");
})
}
})
const getCity = async (geoURL, city, geoUsername) => {
const res = await fetch(`${geoURL}q=${city}&username=${geoUsername}`);
try {
const cityData = await res.json();
return cityData;
}
catch (error) {
console.log("error", error);
}
}
const postWeatherData = async (url = "", data = {}) => {
const response = await fetch(url, {
method: "POST",
credentials: "same-origin",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
temp: data.temp
})
});
try {
const newData = await response.json();
return newData;
}
catch (error) {
console.log(error);
}
}
const receiveWeatherData = async () => {
const request = await fetch("/allWeather");
try {
const allData = await request.json()
document.getElementById("temp").innerHTML = allData.temp;
}
catch (error) {
console.log("error", error)
}
}
const getWeather = async (weatherURL, weatherKey, lat, lon) => {
const res = await fetch(`${weatherURL}&lat=${lat}&lon=${lon}&key=${weatherKey}`);
try {
const weatherData = await res.json();
return weatherData;
}
catch (error) {
console.log("error", error);
}
}
My server.js:
// Setup empty JS object to act as endpoint for all routes
cityData = {};
weatherData = {};
picturesData = {};
// Require Express to run server and routes
const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
// Start up an instance of app
const app = express();
/* Middleware*/
//Here we are configuring express to use body-parser as middle-ware.
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
// Cors for cross origin allowance
app.use(cors())
// Initialize the main project folder
app.use(express.static('website'));
app.get("/all", function sendData(req, res) {
res.send(cityData);
})
app.get("/allWeather", function sendWeather(req, res) {
res.send(weatherData);
})
app.get("allPictures", function sendPictures(req, res) {
res.send(picturesData);
})
app.post("/add", (req, res) => {
projectData['lat'] = req.body.lat;
projectData['lng'] = req.body.lng;
projectData['countryName'] = req.body.countryName
res.send(cityData);
})
app.post("/addWeather", (req, res) => {
weatherData['temp'] = req.body.temp;
res.send(weatherData);
})
app.post("/addPicture", (req, res) => {
picturesData['pic'] = req.body.pic;
res.send(picturesData);
})
// Setup Server
app.listen(3000, () => {
console.log("App listening on port 3000")
console.log("Go to http://localhost:3000")
})
I am trying to get the geonames api to fetch the latitude and longitude of a city . Then I want to use the latitude and longitude to fetch the weather for that location. The pictures api is not implemented yet. I just want to use the data fetched from one api (geonames.org) as input to the other api (weatherbit.io). Right the app returns undefined when I console.log the final data.
You are breaking the Promise then chain. You do not return any promise so that it can be chained. Pasting modified example withe capital RETURN
statements
getCity(geoURL, city, geoUsername)
.then(function (data) {
RETURN getWeather(weatherURL, weatherKey, data["geonames"][0]['lat'], data["geonames"][0]['lng'])
}).then(weatherData => {
RETURN postWeatherData("/addWeather", { temp: weatherData })
}).then(function () {
RETURN receiveWeatherData()
}).catch(function (error) {
console.log(error);
alert("Invalid city");
})
A better would be to write the function as Async, I see you have done that already
So
submitBtn.addEventListener("click", async (e) => {
e.preventDefault();
const city = document.getElementById("city").value;
if (city !== "") {
try {
const city = await getCity(geoURL, city, geoUsername);
const weatherData = await getWeather(weatherURL, weatherKey, city["geonames"][0]['lat'], city["geonames"][0]['lng']);
//and so on
} catch (e) {
console.log(error);
alert("Invalid city");
}
}
})
The problem was here:
const receiveWeatherData = async () => {
const request = await fetch("/allWeather");
try {
const allData = await request.json()
document.getElementById("temp").innerHTML = allData['temp'];
}
catch (error) {
console.log("error", error)
}
}
I replaced allData['data'] with allData['temp']
I'm a beginner in using states in reactjs so im sorry if my question shouldn't be asked in the right spot.Using React js, Node js and mongodb
So i created a constructor and initialized a variable called val inside it and passed that variable in a value property in a textarea tag so the user would enter somthing and it would be saved in the val variable (im not sure if thats the right way of doing it, so thats why im asking!). Also, I created a function called handleSubmit that would get the variable val and save it in mongodb, and i called that function in the button the user supposed to click when he passes in somthing. But all that doesn't seem to be working with me.
Here is my ping.js file:
class Pingbutton extends React.Component {
constructor(props) {
super(props);
this.state = { val: "Ford" };
}
handleSubmit = () => {
// if we get state error then we need to put it in a claa and call the constructot and then call the function using this.state.the name of the function
console.log("its running 1");
let databody = {
message: this.state.val,
};
console.log(" the message is :" + databody.message);
console.log(" the message is :" + this.state.val);
return fetch("http://localhost:5000/stored", {
method: "POST",
body: JSON.stringify(databody),
headers: {
"Content-Type": "application/json",
},
})
.then((res) => res.json())
.then((data) => console.log(data));
};
render() {
return (
<div className="ok2">
<textarea
className="message"
type="text"
placeholder="Write me somthing!. Also, double click to ping:) "
value={this.setState.val}
></textarea>
<button
className="button"
onClick={() => {
this.magic();
this.handleSubmit(); //animation + //pinging the phone
// this.handleButtonClick(); //setVal(() => ""); //sets the value of the box to empty
}}
>
</button>
</div>
);
}
}
export default Pingbutton;
and this is the back-end (nodejs) index.js file:
const express = require("express");
const cors = require("cors"); // Importing cors
var request = require("request");
const dotenv = require("dotenv");
const port = 5000;
var request = require("request");
var util = require("util");
const connectDB = require("./config/db");
require("dotenv").config({ path: "./config/config.env" });
const app = express();
dotenv.config();
connectDB();
app.use(cors({ origin: "http://localhost:3000" }));
app.get("/", (req, res) => {
res.send("Hey there!");
});
app.use(cors({ origin: "http://localhost:3000" }));
app.get("/Pinged", function (req, res) {
find_my_iphone("omar.fsm98#gmail.com", "Faresomar123", "Omar");
res.send("Pinged!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
});
app.use(cors({ origin: "http://localhost:3000" }));
app.post("/stored", (req, res) => {
console.log("its running 2: " + req.body);
db.collection("quotes").insertOne(req.body, (err, data) => {
if (err) return console.log(err);
res.send("saved to db: " + data);
});
});
app.listen(port, () => console.log(`Example app listening on port ${port}!`));
I have been getting Ford in the two console in the front-end after typing somthing in the box and clicking the button (excuting the handleSubmit) function). I tried doing this.state.val but didnt work then i changed it to this.setState.val and didnt work either.
I would appreciate the help.
THANK YOU!
The answer for that would be to create a function that does all that as following:
class App extends React.Component {
constructor() {
super();
this.state = {header: 'yeaheheh'};
}
changeHeader = (e) => {
e.preventDefault();
let newHeader = this.textInput.value;
console.log('submitted');
this.setState({header : newHeader});
}
render() {
return (
<div>
<h1>{this.state.header}</h1>
<form onSubmit={this.changeHeader} className="change-header-form">
<input id="input" ref={(input) => { this.textInput = input; }} type="text" placeholder="Enter Text Here" />
<input type="submit" value="Submit" />
</form>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('test'));
The full answer for that can be found in that link: Change a state in react
I'm using react/express/SQL
I have a simple program where user can enter data, view data and update their data. inserting and getting data from my SQL database works fine, but when I try to update data from my database I get the following error.
Error when trying to update data
TypeError: Cannot read property 'userEvent' of undefined
index.js
const express = require('express'); // node js frontend/backend lib
const app = express()
const mysql = require('mysql'); // DB
const cors = require('cors') //By default requests from any other origins will be restricted by the browser. We have two differnet local hosts, so by default wont be able we req res data
//Setting up SQL, hide password properly
const db = mysql.createConnection({
host:'localhost',
user: 'root',
password: '*****',
database: 'calendardb',
});
app.use(cors());
app.use(express.json()); // turns data into json
// insert information in to DB
app.post('/send',(req,res) =>{
const userEvent = req.body.userEvent
db.query('INSERT INTO calevent (userEvent) VALUES (?)',
userEvent, (err,result) =>{
if(err){
console.log(err)
} else{
res.send("Data send to DB")
}
}
);
});
//Getting data from DB
app.get("/getData",(req, res) =>{
db.query("SELECT * FROM calevent", (err, result) => {
if(err){
console.log(err)
}else{
res.send(result)
}
});
});
//Update data
app.put('/update', (res,req) => {
//const newUserEvent = "test";
//const id = 325;
const newUserEvent = req.body.userEvent;
const id = req.body.id;
db.query("UPDATE calevent SET userEvent = ? WHERE id = ?", [newUserEvent, id],(err, result) => {
if(err){
console.log(err)
}else{
console.log(result)
}
});
});
app.listen(3001, () =>{
console.log('bonger');
});
The problem is that it is unable to get the variables from the front end and access it in the backend. if I uncomment the following: //const newUserEvent = "test"; //const id = 325; and use that as my hardcoded user input, everything works fine, I can update my database.
app.js
import React from 'react';
import { useState,useEffect } from "react";
import Calendar from 'react-calendar';
import 'react-calendar/dist/Calendar.css';
import Axios from 'axios';
const CalendarApp = () => {
var [selectedDate, newDate] = useState(new Date());
const [event, newEvent] = useState("")
const [userEvent, setUserEvent] = useState("")
const [items, setItem] = useState([])
const [userEventList, setUserEventList] = useState([])
const [newUserEvent, setNewUserEvent] = useState("")
//Add event to DB
const addUserEvent = () => {
Axios.post("http://localhost:3001/send", {userEvent: userEvent,
}).then(() => {
console.log("Data sent to DB")
setUserEventList([...userEventList,{userEvent: userEvent,}])
});
};
//Gets data from DB
const getUserEvent = () =>{
Axios.get("http://localhost:3001/getData").then((response) => {
setUserEventList(response.data)
});
};
//Updates data chosen by user
const updateUserEvent = (id) => {
console.log(newUserEvent, id)
Axios.put('http://localhost:3001/update', {newUserEvent:newUserEvent, id: id}).then(response => {
console.log(response);
})
.catch(err => {
console.log(err);
});
};
return(
<div id="eventList">
<h2>Event List</h2>
<div className="List">
{userEventList.map((val,key) => {
return (
<div>
Event: {val.userEvent}, Key: {val.id}
<div>
<input type="text" placeholder="Edit" onChange={(event) => {
setNewUserEvent(event.target.value)
}}/>
<button onClick={() => {updateUserEvent(val.id)}}>Update</button>
</div>
</div>
)
})}
</div>
</div>
)
the code console.log(newUserEvent, id) returns the correct updated user input and id number but for some reason when using axios.put it does not send it to the back end to be used there.
I am new to react, just but my first MERN stack - a simple to-do style app.
While both my post and delete functions are working fine, and the getData() function is firing so my dom gets updated with the new list of 'notes', this is not the case for my update function.
While the note is updating successfully on the database, the dom doesn't reload with the new updated data, even though I have placed the getData function there...
I think the problem is that the patch request is lagging, so the getData function fires before the updated data is actually in the database...
Any solutions out there? I've only posted my main app.js file, and my routes.
What is the correct way to deal with this problem? I realise i could try a delay but that seems a bit hacky
The Function in question:
//UPDATE NOTE
async updateNote(_id, newNoteContent) {
const updatedNote = {
content: newNoteContent
}
await axios.patch('http://localhost:5000/'+ _id, updatedNote)
.then(console.log('item ' + _id + ' has been updated'))
.then(this.loadData())
}
APP.js
import React, { Component } from 'react';
import './App.css';
import axios from 'axios';
import Note from './components/note.js';
import Form from './components/form.js';
import EditBox from './components/editBox.js';
class App extends Component {
state = {
notes: [],
dataLoaded: false,
toggleEditBox: false,
noteToEdit: null,
noteToEditContent: null,
}
//CDM which triggers first load
componentDidMount() {
this.loadData()
}
//function for loading our data from the db when required
async loadData() {
await axios.get('http://localhost:5000/notes')
.then(response => {
const notes = response.data.reverse();
console.log("fetched")
this.setState({ notes: notes, dataLoaded: true, toggleEditBox: false })
})
}
//ADD NOTE to the database
async addNote(noteContent) {
const newNote = {
content: noteContent
}
await axios.post('http://localhost:5000/', newNote)
.then(post => console.log('item ' + post.data._id + ' has been added'))
this.loadData()
}
//DELETE NOTE from the database
async deleteNote(_id) {
await axios.delete('http://localhost:5000/'+_id)
.then(post => console.log('item ' + _id + ' has been deleted'))
this.loadData()
}
//Function to open edit box
triggerEditBox(_id, content) {
this.setState({ toggleEditBox: true, noteToEdit: _id, noteToEditContent: content})
}
//UPDATE NOTE
async updateNote(_id, newNoteContent) {
const updatedNote = {
content: newNoteContent
}
await axios.patch('http://localhost:5000/'+ _id, updatedNote)
.then(console.log('item ' + _id + ' has been updated'))
.then(this.loadData())
}
render() {
let notes;
if (this.state.dataLoaded) {
notes =
<div className="note-container">
{this.state.notes.map(note =>
<Note
content={note.content}
deleteNote={() => this.deleteNote(note._id)}
triggerEditBox={() => this.triggerEditBox(note._id, note.content)}
/>)}
</div>
} else if (!this.state.dataLoaded) {
notes = <h3>Loading</h3>
}
//editbox
let editBox;
if (this.state.toggleEditBox) {
editBox =
<EditBox
content={this.state.noteToEditContent}
_id={this.state.noteToEdit}
updateNote={(_id, newNoteContent) => this.updateNote(_id, newNoteContent)}/>
}
return (
<div className="App">
{editBox}
<Form onSubmit={(noteContent) => this.addNote(noteContent)}/>
{notes}
</div>
);
}
}
export default App;
ROUTES
const express = require('express');
const router = express.Router();
const Note = require('../../models/Note') // Pull in our Note model
router.get('/', function (req, res) {
res.send('Hello, soon I will be a MERN stack app!')
});
// GET = RETRIEVE ALL NOTES
router.get('/notes', (req, res) => {
Note.find()
.then(notes => res.json(notes));
});
// POST = ADD A NOTE TO THE DB
// as the root of the route '/notes' is already defined in the server.js we dont need to have here
router.post('/', (req, res) => {
const newNote = new Note({
content: req.body.content
});
newNote.save().then(note => res.json(note));
});
// DELETE = DELETE A NOTE FROM THE DB
// we add the property param:id
router.delete('/:id', (req, res) => {
Note.findById(req.params.id)
.then(item => item.remove().then(() => res.json({ success: true })))
.catch(err => res.status(404).json({ success: false }));
});
// UPDATE = UPDATE A NOTE IN THE DB
router.patch('/:id', (req, res) => {
Note.findById(req.params.id)
.then(item => item.update({ content: req.body.content }));
});
// we cant use 'export default' in this particular file
module.exports = router;
Update 09/20/2019
its all working well. Thanks!!
Here are the updates I made:
// UPDATE = UPDATE A NOTE IN THE DB
router.patch('/:id', (req, res) => {
Note.findById(req.params.id)
.then(item => item.update({ content: req.body.content }).then(() => res.json({ success: true })))
});
and
async updateNote(_id, newNoteContent) {
const updatedNote = {
content: newNoteContent
}
await axios.patch('http://localhost:5000/'+ _id, updatedNote)
.then(console.log('item ' + _id + ' has been updated'))
this.loadData()
}
here I'm trying to have the sum of orders and the sum of their quantity in which I use Node JS for my backend. The problem is whenever I run my code -- my fetch functions seems not working properly or I'm missing something that I'm not aware.
But using postman, my API is working with the expected output. Buuut if I use it in my react-native code it show some errors.
Here's my code for backend:
OrderNo.js (models) //Backend
var Task = {
Sum:function(id,callback) {
return db.query("SELECT SUM(order_amount) AS TotalAmountOrdered FROM orders where order_no=?",[id],callback);
},
}
OrderNo.js (router) //Backend
var Task = require('../models/OrderNo');
router.get('/ForSum/:id?', (req, res, next) => {
Task.Sum(req.params.id,function(err,rows) {
if(err) {
res.json(err);
}
else {
res.json(rows);
}
});
});
NumOrder.js (models) //Backend
var Task = {
NumOrder:function(id,callback) {
return db.query("SELECT SUM(order_quantity) AS TotalItemsOrdered FROM orders where order_no=?",[id],callback);
},
}
NumOrder.js (router) //Backend
var Task = require('../models/NumOrder');
router.get('/num/:id?', (req, res, next) => {
Task.NumOrder(req.params.id,function(err,rows) {
if(err) {
res.json(err);
}
else {
res.json(rows);
}
});
});
And here's my code for React-Native
export default class Settlement extends Component {
constructor(props){
super(props)
this.state = {
orderDet: this.props.navigation.state.params.orderDet,
numOrder: [],
TotalSum: [],
};
}
fetchSum = async () => {
const response = await fetch("http://192.168.254.104:3308/OrderNo/ForSum/" + this.state.orderDet)
const json = await response.json()
this.setState({ TotalSum: json })
}
fetchNumOrders = async () => {
const response = await fetch("http://192.168.254.104:3308/NumOrder/num/" + this.state.orderDet )
const json = await response.json()
this.setState({ numOrder: json })
}
componentDidMount() {
this.fetchNumOrders();
this.fetchSum();
}
render() {
return (
<View>
<Text>Number of Orders: { this.state.numOrder }</Text>
<Text>Total Amount: ₱{ this.state.TotalSum }</Text>
</View>
)
}
}
And here is my DB
**PS: **I also tried " json[0].order_no " on each of my fetch function and there's no error, but my output is empty.
Based on your response object in the Postman, you need to do the following
this.state = {
orderDet: this.props.navigation.state.params.orderDet,
numOrder: null,
TotalSum: null,
};
fetchSum = async () => {
const response = await fetch("http://192.168.254.104:3308/OrderNo/ForSum/" + this.state.orderDet)
const json = await response.json()
this.setState({ TotalSum: json[0].TotalAmountOrdered })
}
fetchNumOrders = async () => {
const response = await fetch("http://192.168.254.104:3308/NumOrder/num/" + this.state.orderDet )
const json = await response.json()
this.setState({ numOrder: json[0].TotalItemsOrdered })
}
The error means that you cannot have object or array as the child the component i.e. <Text>. You can only have string or number displayed inside the component.
<Text>Number of Orders: { this.state.numOrder[0].TotalAmountOrdered }</Text>// Inside {} value of variable should be string or number not array or object
The error is that you are setting value of this.state.numOrder an array