I am trying something simple where I make a request from the front-end and fetch the JSON data on the back-end. I'm using ReactJS on the front-end and NodeJS and ExpressJS on the Back-end.
I am getting little confused with figure what the right way how I can access JSON data onto the front-end by make the name server file name from server.js or con.now.
I am getting in my console not it refused to connect the link to the server. I have been tried to name the file server.js to cors.now would that connect the server to the front-end but I was wrong.
Failed to load resource: net::ERR_CONNECTION_REFUSED
But when every do that getting an error message in my console that talks about cors.now.sh/https://us-central1-aaronklaser-1.cloudfunctions.net/medium?username=#aaron.klaser
Medium.js
import React from 'react';
import PageHeader from './PageHeader';
import PageContent from './PageContent';
import axios from 'axios';
export default class Medium extends React.Component {
state = {
posts: []
}
componentDidMount() {
this.fetchPosts().then(this.setPosts)
}
fetchPosts = () => axios.get(`https://cors.now.sh/https://us-central1-aaronklaser-1.cloudfunctions.net/medium?username=#aaron.klaser`)
setPosts = response => {
this.setState({
posts: response
})
}
render() {
return (
<div>
<PageHeader/>
<PageContent>
<pre>{JSON.stringify(this.state.posts, null, 2)}</pre>
</PageContent>
</div>
)
}
}
cors.now
const express = require('express');
const app = express();
const port = process.env.PORT || 5000;
const request = require('request');
app.get("/api/medium", (req, res) => {
if(!req.query.username){
return res.status(400).send('Error: You need to include query param ?username=#yourUsername');
} else {
return request(url,(error, response, body) => {
const url = `https://medium.com/${req.query.username}/latest?format=json`;
const prefix = `])}while(1);</x>`
const strip = payload => payload.replace(prefix, ``)
res.send(JSON.parse(strip(body)));
});
}
});
app.listen(port, () => console.log(`Listening on port ${port}`));
I see you're using the https://cors.now.sh site as a reverse proxy. I am not sure if that site is functioning at this time?
If you hit your API endpoint directly (https://us-central1-aaronklaser-1.cloudfunctions.net/medium?username=#aaron.klaser) - I see a valid JSON response returned to the browser.
I believe the issue is with the reverse proxy site not running or responding at this time.
Related
Backend code example: I am trying to get users here from my SQL Server database Account:
async function executeQuery() {
try {
const pool = await sql.connect(config);
const result = await pool
.request()
.query(`USE Account SELECT TOP 10 UserNo FROM UserTable`);
return result;
} catch (err) {
console.log(err);
}
}
app.get("/api/data", async (req, res) => {
const result = await executeQuery();
res.json(result);
});
React frontend code: I am getting an error when try to render data from SQL Server.
import React, { useState, useEffect } from "react";
function SqlTest() {
const [data, setData] = useState([]);
async function fetchData() {
const result = await fetch("/api/data").then((res) => res.json());
setData(result);
}
useEffect(() => {
fetchData();
}, []);
return (
<div>
{data.map((item) => (
<div key={item.UserNo}>{item.UserNo}</div>
))}
</div>
);
}
export default SqlTest;
I am trying to render data from SQL Server, but nothing helps..
Ok, your problem is a very common one that has a very common solution.
You have 2 separate projects (HTTP servers):
The HTTP server that CRA comes with, which is a NodeJS server.
Your API server, which happens to also be a NodeJS server.
Now you want to fetch data from React by querying your API server.
Look at your URL: api/data. This is a relative URL. Relative URL's are resolved by the browser by using the current page's domain. I don't know your exact setup, but the URL will end up being something like http://localhost:3000/api/data.
Do you see the problem already? Your API server is not listening on port 3000. It is probably listening on some other port number. After all, no 2 applications can listen on the same TCP port.
So you would then be tempted to change your fetch URL to a full URL that specifies the server API: http://localhost:3001/api/data. That probably works, but there's a chance it errors out due to CORS.
So long story short, do as the CRA help pages say you should do: Set a proxy up in your CRA server. Here it is: https://create-react-app.dev/docs/proxying-api-requests-in-development/
In a nutshell, create the file src/setupProxy.js with code similar to this:
const { createProxyMiddleware } = require('http-proxy-middleware');
module.exports = function(app) {
app.use(
'/api',
createProxyMiddleware({
target: 'http://localhost:5000', // <-- USE YOUR API PORT
changeOrigin: true,
})
);
};
The sample assumes you're running your API server in port 5000. Change it to fit your configuration.
I am trying to get function result from backend to frontend via axios but it returns 404 every time.
I managed to send request to backend and activate function but on geting result it started returning 404
route in app.ts
import cardRoute from './routes/test';
const app = express();
app.use('/test', cardRoute);
./routes/test.ts (backend)
function test_load() returns string
import express from 'express';
import { test_load } from '../cardpull';
const router = express.Router();
router.post('./test-bed',
async (req, res) => {
let cards = test_load()
res.send(cards);
},
);
export default router;
Frontend call
async function GetCard() {
var cards = await axios.post<string>('/test/test-bed');
return cards;
};
your route is not valid
router.post('./test-bed',
async (req, res) => {
let cards = test_load()
res.send(cards);
},
);
should be:
router.post('/test-bed',
async (req, res) => {
let cards = test_load()
res.send(cards);
},
);
and on your axios URL, maybe you need to include the host and port because if you define only the endpoint, it will hit your frontend host and port,
example if you open express on localhost:3000
then the axios will be
axios.post('http://localhost:3000/test/test-bed')
note: I didn't write the answer with typescript, but with javascript style should be clear enough.
I built my react app.
I have 2 main folders. The first folder contains my react-app and the second contains my nodejs server. In the first file i've created 2 pages and i want to fetch data from nodejs server to one of my page from react app.
//Here is my nodejs file
var express = require('express');
var app = express();
app.post('/', function (req, res) {
res.send('POST request to the homepage');
});
app.listen(4000, function () {
console.log('Example app listening on port 4000!');
});
//Here is my react page where i want to fetch data from nodejs
import React, { useState, useEffect } from 'react';
const Home = () => {
useEffect(async function () {
const url = 'http://localhost:4000/';
const response = await fetch(url);
const data = await response.json();
console.log(data)
});
return(
<div>
<h1>Home Page</h1>
<p>{data}</p>
</div>
)
}
export default Home;
In the future i want to get data also from a nosql database using nodejs, but now I can't pass data from one node js file into reactjs file. How to do this?
I'm just learning Express/React and I'm trying to get set up with routes and basic database connections. I suspect I'm missing something very simple. I've tried to boil it down to the following.
Backend
server.js:
require('dotenv').config({path: '../.env'});
const mysql = require('mysql');
const express = require('express');
const bodyParser = require('body-parser');
const port = process.env.PORT || 5000;
const app = express();
const router = express.Router();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
const users = require('./routes/api/users');
app.use('/api/users', users);
const events = require('./routes/api/events');
app.use('/api/events', events);
const db = mysql.createConnection({
host: process.env.DB_HOST,
database: process.env.DB_NAME,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD
});
db.connect(function(err) {
if (err) throw err;
console.log('MySQL Connected!');
})
app.listen(port, () => console.log(`Listening on port ${port}`));
/routes/api/events.js:
const express = require('express');
const router = express.Router();
// GET api/events
router.get('/', (req, res) => {
res.send({id: "1", name: "hi"});
});
module.exports = router;
Frontend
App.js:
import React, { Component } from 'react';
import EventList from './components/EventList';
class App extends Component {
render() {
return (
<div className="App">
<EventList/>
</div>)
}
}
export default App;
/components/EventList.js:
import React, { Component } from 'react';
import axios from 'axios';
class EventList extends Component {
constructor() {
super();
this.state = {
events: []
}
}
componentDidMount() {
axios.get('/api/events')
.then(events => {
this.setState({events: events.data})
})
.catch(err => console.log(err))
}
render() {
var events = this.state.events;
return (
<div>
<p>Events:</p>
<ul>
{ events.map(({ id, name }) => (
<li>{name}</li>
))}
</ul>
</div>
)
}
}
export default EventList;
The error I get is http://localhost:3000/api/events 500 (Internal Server Error). What am I missing? I have truly scoured all of the docs I can find, but I'm not quite getting it.
Edit
I haven't changed anything, but now I'm getting a 404 (Not Found) instead. I had been getting a 500 for awhile, so it wasn't a momentary fluke. I'm not sure what could have changed.
Update
It may help to know that the .env variables I'm pointing to are actually for a remote MySQL database (i.e., DB_HOST != localhost, but a remote URL). Eventually, I'd like to connect the GET call on the events route to that db, but since it doesn't work with what I have here I figured my first issue to solve was upstream. As noted in comments, the PORT var I'm loading in is 3306. When I start the server, it says it's listening on 3306 as expected.
I think you are running your server on port 5000 and front on port 3000. if you request events with http://localhost:5000/api/events instead of /api/events, you would get 200 status code with your json data.
// as is
axios.get('/api/events')
// to be
axios.get('http://localhost:5000/api/events')
You could try typing componentDidMount function like this.
componentDidMount = async () =>{
//like this
}
In addition, I would recommend making the GET ALL its own function so you could just invoke in the componentDidMount function. whenever you run another CRUD action it will automatically update your events for you and instead of setting state every time you can invoke the this.getEvents() again to update it that way.
componentDidMount = async () =>{
this.getEvents()
}
Also you need to add this package (npm install cors) its so you can connect your api to your frontend.
Import it like this in your server.js file
const cors = require('cors')
app.use(cors())
You should add a proxy inside package.json in frontend like this.
"proxy": "http://localhost:5000",
Basically to summarize my problem: I have some image to be displayed and it's displayed on localhost:5000 with status 200 where my Express server is running and when it comes to localhost:3000 i.e. my React Development Server, I made a request using Axios and it does give me gibberish and I don't know how to handle it at all.
React Code:
componentDidMount() {
axios.get('/filesuploaded/video_______82395d6a5af4e98fb8efca56f0ae3c1b_____.jpeg')
.then(Response => console.log(Response))
.catch(err => console.log(err));
}
Express Code:
route.get('/:filename' , (req , res) => {
GridFS.files.findOne({filename: req.params.filename} , (err , file) => {
const readstream = GridFS.createReadStream(file.filename);
readstream.pipe(res);
})
});
Random Gibberish:
{data: "����..."
SOLUTION:
So I played around more with the code and I had forgotten that this existed in my package.json of my client side and I have used it to full potential and rewrote my server side code without using multer anywhere.
Package.json:
"proxy": "http://localhost:5000" //This helps React communicate with ExpressJS through ports.
Server Side Config:
const route = require('express').Router();
const mongoose = require('mongoose');
const GridFS = require('gridfs-stream');
//Route for getting files
route.get('/file/:id' , (req , res) => {
//Setting Up GridFS-Stream
const db = mongoose.connection.db;
const MongoDriver = mongoose.mongo;
const gfs = new GridFS(db , MongoDriver);
const readstream = gfs.createReadStream({
_id: req.params.id,
});
//Reading to Response
readstream.pipe(res);
});
module.exports = route;
Front End Config:
import React, { Component } from 'react'
export default class Files extends Component {
//Render Method
render() {
return (
<div>
<img src = {window.location.pathname} alt = "something" />
</div>
)
}
}
Here the window.location.pathname will translate to /file/:id and send a GET request to ExpressJS, hence loading the image!