I'm trying to successfully connect my backend Express app to my frontend React app but I'm having difficulty with the actual connection process and I think it's to do with the "proxy" pathway I'm using in my package.json file in my react app.
Express
const express = require('express')
const app = express()
let name = "Justin"
app.get('/', (req, res) => {
res.send(name)
})
app.listen(40000, () => {
console.log("Im Listening on port 40000")
})
React
import './App.css';
function GetData() {
fetch('/')
.then((response) => response.text())
.then(function (data) {
console.log(data)
}
)};
function App() {
return (
<div className="App">
<button onClick={GetData}>Get Data</button>
</div>
);
}
export default App;
I've made sure to add the proxy route to the express server within my package.json file
"proxy": "http://localhost:40000",
The only thing that happens when I click the button is a text representation of the react app html page source.
What I want to see is the name "justin" displayed in the console when I click the button.
Would love a quick solve
Related
I created a Google Cloud Platform account, and made a simple hello_world type Python "Cloud Function" that just spits out some simple text. I made this function "HTTP" accessible and only able to be called/authenticated by a "Service Account" that I made for the purpose of calling this very function. I generated a key for this "Service Account" and downloaded the json file for the key.
The problem is that I can't find any documentation on how to call this function with my service account in a next.js app. I tried this:
import React from 'react';
import { Button } from 'react-bootstrap';
import { GoogleAuth } from 'google-auth-library';
const projectId = 'gtwitone';
const keyFilename = '/Users/<myusername>/path/to/cloudfunction/credentials.json';
class Middle extends React.Component {
handleClick() {
console.log('this is:', this);
}
// This syntax ensures `this` is bound within handleClick. // Warning: this is *experimental* syntax. handleClick = () => { console.log('this is:', this); }
/* async listFunctions() {
const [functions] = await client.listFunctions();
console.info(functions);
} */
async runGoogleCloudFunctionTest() {
// Define your URL, here with Cloud Run but the security is exactly the same with Cloud Functions (same underlying infrastructure)
const url = "https://us-central1-<projectname>.cloudfunctions.net/<functionname>"
//Example with the key file, not recommended on GCP environment.
const auth = new GoogleAuth({keyFilename: keyFilename})
//Create your client with an Identity token.
const client = await auth.getIdTokenClient(url);
const res = await client.request({url});
console.log(res.data);
}
render() {
return (
<div className="col-md-12 text-center">
<Button variant='primary' onClick={this.runGoogleCloudFunctionTest}>
Click me
</Button>
</div>
);
}
}
export default Middle;
But I got this error in my terminal:
<myusername>#<mycomputername> <thisnextjsappdirectory> % yarn dev
yarn run v1.22.17
$ next dev
ready - started server on 0.0.0.0:3000, url: http://localhost:3000
wait - compiling...
event - compiled client and server successfully in 267 ms (124 modules)
wait - compiling / (client and server)...
wait - compiling...
error - ./node_modules/google-auth-library/build/src/auth/googleauth.js:17:0
Module not found: Can't resolve 'child_process'
Import trace for requested module:
./node_modules/google-auth-library/build/src/index.js
./components/Middle.tsx
./pages/index.tsx
https://nextjs.org/docs/messages/module-not-found
Native Node.js APIs are not supported in the Edge Runtime. Found `child_process` imported.
Could not find files for / in .next/build-manifest.json
Could not find files for / in .next/build-manifest.json
^C
<myusername>#<mycomputername> <thisnextjsappdirectory> %
I know that this is problem with server side rendering in my Next.js app and people recommend using a client side package like this https://github.com/google/google-api-javascript-client. But google-api-javascript-client doesn't have any documentation on authenticating with a .json credentials file instead of an API KEY which I do not have.
In short how do I get my app to work and run the Google Cloud function with a .json credentials file for am authenticated service account?
I fixed it by simply moving the GoogleAuth api call to the pages/api route.
pages/api/google.ts
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import type { NextApiRequest, NextApiResponse } from "next"
import { GoogleAuth } from "google-auth-library"
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
const url = process.env.FUNCTION_URL as string
//Example with the key file, not recommended on GCP environment.
const auth = new GoogleAuth({ keyFilename: process.env.KEYSTORE_PATH })
//Create your client with an Identity token.
const client = await auth.getIdTokenClient(url)
const result = await client.request({ url })
console.log(result.data)
res.json({ data: result.data })
}
components/Middle.tsx
import React from "react"
import { Button } from "react-bootstrap"
class Middle extends React.Component {
handleClick() {
console.log("this is:", this)
}
// this talks with /pages/api/google
async imCallingAnAPI() {
const result = await fetch("/api/google")
console.log({ result })
}
render() {
return (
<div className="col-md-12 text-center">
<Button variant="primary" onClick={this.imCallingAnAPI}>
Click me
</Button>
</div>
)
}
}
export default Middle
pages/index.tsx
import type { NextPage } from 'next'
import Header from '../components/Header';
import Footer from '../components/Footer';
import Middle from '../components/Middle';
const Home: NextPage = () => {
return (
<><main className='d-flex flex-column min-vh-100'>
<Header />
<br></br>
<br></br>
<Middle />
</main>
<footer>
<Footer />
</footer>
</>
)
}
export default Home
I think that next.js has trouble loading GoogleAuth in a component. I'm not 100% sure why, but I think it has to do with next.js not knowing exactly how to handle GoogleAuth with server-side rendering.
Hey i have a express app with a api route
app.get("/api", (req, res) => {
res.json({ message: "Its work !! !! !" });
});
And i have a reactjs app with that in package.json
"proxy": "http://localhost:3001",
When i want to go on api route of express app (http://localhost:3001/api) its work but its not work with my reactjs app when i go on (http://localhost:4000/api)
i start my webserver with
yarn run clean && cross-env NODE_ENV=development webpack-dev-server --host localhost --hot --https
The problem can be a problem from react router dom?
Resolved Solution:
In webpack config add proxy to devserver
As you are proxying requests, you can access the API endpoints from within react application (proxy parses requests to API), but nevertheless your API is still on its server (or another port on localhost f.e.)
Your React app just proxies the request
Example how to query your data with proxy configured:
import { useState, useEffect } from "react";
import axios from "axios";
const App = () => {
const [data, setData] = useState();
useEffect(() => {
const getData = async () => {
// you can use /api here as you proxi it to your API url
// f.e. localhost:5000/api
const response = await axios.get("/api");
setData(response.data);
};
getData();
}, []);
// stringify your data in json
return <pre>{JSON.stringify(data, undefined, 2)}</pre>;
};
export default App;
I am having similar problem.I stored the path in database named Cast and the images on the server. The database has two fields name and image. In the react app,i want to display the image.I am not getting the image.
I am running express on localhost:5000 and reactjs on localhost:3000.
Ex: image in the db has the value "Anushka.jpg". On the server side it is stored as follows:
public
└─ cast_images
└─ Anushka.jpg
app.js file(server side)
app.use('/login', express.static(path.join(__dirname, '/public')));
app.get('/login',(req,res)=>{
Cast.find()
.then(
cast=>res.json(cast))
.catch(err => res.status(400).json('Error: ' + err));
});
App.js(frontend react file):
function App() {
return (
<Router>
<Navbar />
<br/>
<Route path="/login" component={Login}/>
</Router>
);
}
export default App;
Login.js
import React, { Component } from 'react';
import axios from 'axios';
export default class Login extends Component {
state={
casts:[]
};
componentDidMount() {
axios.get('http://localhost:5000/admin/')
.then(response => {
this.setState({casts:response.data});
console.log(response.data);
})
.catch((error) => {
console.log(error);
})
}
render() {
const actor =this.state.casts.map(actor => {
return (
<p>
<img src="/cast_images/{actor.image}" alt="hello"/>
<h3>{actor.name}</h3>
</p>
);
});
return(<p>{actor}</p>);
}
}
I did not not mention here imports in React code.This is a part of code.Can u please tell me how to get the image.Thanks in advance.
With this code you are mounting your public folder to the /login url path, I don't think that is what you want
app.use('/login', express.static(path.join(__dirname, '/public')));
So it should be changed to
app.use('/', express.static(path.join(__dirname, '/public')));
And in React, you can use JavaScript template string literal to insert a variable inside a string.
const serverBaseURI = 'http://localhost:5000' // set this to the value of your express server, should be different value for production server
/* .... */
<img src={`${serverBaseURI}/cast_images/${actor.image}`} alt="hello"/>
I've been told that Axios is how you get React to talk to an api (external or internal). So far, I have specifically only received 404 errors whenever I try to implement Axios calls.
Here is the axios call in client/src/App.js:
import React, {Component} from 'react';
import './App.css';
import API from "./utils/API";
class App extends Component {
state = {
recipes: []
}
componentDidMount = () => {
API.getRecipes("milk") /* This is supposed to call the getRecipes
function in API.js with "milk" as the only
parameter (ie - Search the api for "milk"
related recipes). */
.then(res => this.setState({recipes: res.data}))
.catch(err => console.log(err));
}
render(){
return (
<div>
{
this.state.recipes.map(recipe => {
return(
<p>
{recipe.title} // All recipe names are then set to a p tag
</p>
)
})
}
</div>
);
}
}
export default App;
Now, this calls API.js in the "utils" folder:
import axios from "axios";
// Function that takes the parameter and is supposed to send it to the
/api/recipes route
export default {
getRecipes: function(query) {
return axios.get("/api/recipes", { params: { q: query } });
}
};
The relevant api route (/api/recipes) is located in a folder named "routes" outside of the "src" folder. This file is the only item inside the folder.
const axios = require("axios");
const router = require("express").Router();
/* As you can see, this sends the request to "recipepuppy.com" with the
relevant query ("milk").*/
router.get("/recipes", (req, res) => {
axios.get("http://www.recipepuppy.com/api/", {params: req.query})
.then(({data: {results}}) => {res.json(results)})
.catch(err => res.status(422).json(err));
});
module.exports = router;
Going even further out, here is the server.js file (outside of the "client" folder) that determines the routes:
const express = require("express");
const path = require("path");
const PORT = process.env.PORT || 3001;
const app = express();
const apiRoutes = require("./routes/apiRoutes"); // *********
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
if (process.env.NODE_ENV === "production") {
app.use(express.static("client/build"));
}
app.use("/api", apiRoutes); // *********
app.get("*", function(req, res) {
res.sendFile(path.join(__dirname, "./client/build/index.html"));
});
app.listen(PORT, function() {
console.log(`API server now listening on port ${PORT}.`);
});
As far as I can tell, everything is set up perfectly. However, every single time I boot up the server, the browser console error pops up and says:
GET http://localhost:3000/api/recipes?q=milk 404 (Not Found)
Even though server.js directly ties to the apiRoutes folder, and the axios call within API.js calls the exact same route that would result from going to the /api route, then the /recipes route within /api (resulting in /api/recipes).
If anybody here can tell me what is going on and how to fix it, I would appreciate it.
I didn't have "proxy" set in my dependencies (package.json) in the client folder.
Once I set "proxy" to "localhost:3001" (the same as my initial server.js port value) and restarted the server, it worked immediately.
I have almost googled my fingers off trying to figure this out. It seems a lot of the existing info on connecting socket.io with React Native is outdated, or maybe I'm just interpreting things wrong?
I've managed to get the client-side connected (I'm getting the client console logs when I connect to my app). It seems to be the server-side that's giving me issues. Why is the data being emitted from the client not showing up as a log in my terminal? None of the related console.logs in my server.js are logging but the App.js console.logs are registering.
Edit: Here is my full App.js file:
import Expo from 'expo';
import React from 'react';
import { Dimensions, StyleSheet, Text, View } from 'react-native';
import store from './src/store';
import { Provider } from 'react-redux';
// window.navigator.useragent = 'react-native'; -> not necessary anymore?
const ROOT_URL = 'https://myherokudomain.herokuapp.com';
const io = require('socket.io-client/dist/socket.io');
const socket = io.connect(ROOT_URL);
socket.on('connect', () => {
console.log('Connected to server');
});
socket.on('example', (data) => {
console.log(data);
socket.emit('my other event', { my: 'data' });
});
socket.on('disconnect', () => {
console.log('Disconnected from server');
});
export default class App extends React.Component {
render() {
// const MainNavigator = my react-navigation system
return (
<Provider store={store}>
<View style={styles.container}>
<MainNavigator />
</View>
</Provider>
);
}
}
Edit: Here is my full server.js file:
const config = require('./config/config');
const { mongoose } = require('./db/mongoose');
const express = require('express');
const cors = require('cors');
const app = express();
const port = process.env.PORT;
// ************ Include and use separate routes file
app.use(require('./routes/routes'));
// ************
//Cross-Origin resource sharing. cors library solves CORS problems.
app.use(cors());
//***********
/* Chat server code*/
// enabled heroku session affinity:
// see https://devcenter.heroku.com/articles/session-affinity
// to enable: heroku features:enable http-session-affinity
// to diable: heroku features:disable http-session-affinity
const socketIO = require('socket.io');
const http = require('http');
const server = http.createServer(app);
const io = socketIO(server, { origin: "*:*" });
//********** */
io.on('connection', (socket) => {
console.log('A client just joined', socket.id);
socket.emit('example', { hello: 'world' });
socket.on('my other event', (data) => {
console.log(data);
});
socket.on('disconnect', () => {
console.log('User was disconnected');
});
});
server.listen(port, (err) => {
console.log(`started on port ${port}`);
});
module.exports = { app };
I am getting the console logs on the client side just fine (for instance, the "connected to server" and "hello: world" stuff is showing up when I open my app on expo. But I am not getting the server-side console logs.
What am I doing wrong - how do I get socket.io fully working with a deployed React-Native app?
I would really appreciate any help at all! I've been stuck on this forever.
I'm assuming all the code works, just not the logging since that's all you're asking about. The problem is Node doesn't output to your browser's console.
If it's deployed on heroku then you should see everything being logged there, otherwise you can use libraries like https://github.com/node-inspector/node-inspector to output to your browser.
You're not getting the server-side console logs because 1.) They're only logging on the server, and 2.) You're not emitting them, if you do actually want to send the data back.