Proxying requests in a create-react-app application - reactjs

I have been looking all over to try and figure out why this doesn't work. I have two applications, a client and a server. I'd like to proxy the client requests to the server. I have a route called /api/repositories. I can't have the proxy in the package.json, because it needs to work in production, also.
It is a Create React App project. Here are the important files.
setupProxy.js
const { createProxyMiddleware } = require("http-proxy-middleware");
module.exports = (app) => {
app.use(
createProxyMiddleware("/api", {
target: "http://my.server.com",
changeOrigin: true,
onProxyReq: (proxyReq) => {
console.log("logged");
if (proxyReq.getHeader("origin")) {
proxyReq.setHeader("origin", "http://my.server.com");
}
},
})
);
};
And I use it in a functional React component called Searchbar, as such:
Searchbar.js
import axios from "axios"
async function getRepos() {
const response = await axios({
method: "GET",
url: "/api/repositories",
});
return response.data;
}
function Searchbar() {
const [repos, setRepos] = useState([]);
// Get the repos on load
useEffect(async () => {
setRepos(await getRepos());
}, []);
return (
<div>
{repos.map((repo) => <p>{repo}<p>)}
</div>
);
}
However, when I run npm run start and run the development server, all of my API requests are going to http://localhost:3000/api/repositories, which obviously returns a 404 error. What am I doing wrong?

Related

Request URL from React (Vite) Front-End to Express.js Back-End includes page path and results 404 Not Found

I created an Express.js Back-End that runs on port 4000. Also React (Vite) app runs on port 5173. I try to make some axios requests to my Back-End. Eventhough the URL looks wrong on DevTools when I make any request from my home page, it is still able to hit the Back-End and fetch the data (I can log the request on the Back-End console). But when I try to make a request from another page such as "127.0.0.1:5173/quiz", the request URL also includes "quiz". That's why I get 404.
So it shows "http://127.0.0.1:5173/quiz/api/quiz/:quizId"
But it needs to be "http://127.0.0.1:4000/api/quiz/:quizId"
But like I said, it works when I make a request on home page:
"http://127.0.0.1:5173/api/quiz" - This works, and fetches the quiz list.
Btw, to solve CORS issues, I tried to add "proxy" on package.json, but it didn't work. Then I add some configurations on vite.config.ts, it worked, but like I said I kept seeing "http://127.0.0.1:5173" on Dev Tools Network tab instead of "http://127.0.0.1:4000".
Here's my vite.config.ts:
import { defineConfig } from "vite";
import react from "#vitejs/plugin-react";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
server: {
proxy: {
"/api": {
target: "http://localhost:4000",
changeOrigin: true,
secure: false,
},
},
},
});
Here's my request code
import { useState } from "react";
import { useAuthContext } from "./useAuthContext";
import { useQuizContext } from "./useQuizContext";
import { QuizType, Types as QuizActionTypes } from "../context/quiz/types";
import axios from "axios";
export const useQuiz = () => {
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const { state: authState } = useAuthContext();
const { dispatch } = useQuizContext();
const getQuiz = async (id: string) => {
setIsLoading(true);
setError(null);
const queryParams: string[] = [];
// If it's a logged in user
if (authState.user.token) {
queryParams.push(`userId=${authState.user._id}`);
}
// If it's a participant who's done with the quiz
if (localStorage.getItem("gifQuizUser")) {
queryParams.push("participantCompleted=true");
}
const uri =
queryParams.length > 0
? `api/quiz/${id}?${queryParams.join("&")}`
: `api/quiz/${id}`;
console.log(uri);
// Fetch & Dispatch
try {
const response = await axios.get(uri);
if (!response.data.error) {
dispatch({
type: QuizActionTypes.GetQuiz,
payload: response.data,
});
setIsLoading(false);
}
} catch (err: any) {
if (err.response.data.error) {
setIsLoading(false);
setError(err.response.data.error);
}
}
};
return { isLoading, error, getQuizzes, getQuiz };
};
Thank you for your time.

unexpected token in json at position 0 reactjs mongodb

///component
function Home() {
const [show, setShow]= useState([{name:'', info:'', airingDate:'', poster:''}])
useEffect(()=>{
fetch("/home")
//.then(res=> res.json())
.then(res => res.text())
.then(text => console.log(text))
})
return (
<div>
{show.map(a=>
<div>
<h2>{a.title}</h2>
</div>
)}
</div>
)
/////index.js
const TvShows = require("./models/TvShows");
const express = require("express");
const app = express();
const mongoose= require("mongoose")
const dotenv= require("dotenv");
const authRoute = require("./routes/auth");
const { application } = require("express");
const userRoute = require("./routes/users");
const commentRoute = require("./routes/comments");
const tvshowsRoute = require("./routes/tvshows");
const cors = require("cors");
app.use(cors());
console.log(".");
dotenv.config();
app.use(express.json());
mongoose.connect(process.env.MONGO_URL,{
useCreateIndex: true,
useNewUrlParser: true,
useUnifiedTopology: true,
}).then(console.log("connected to mongoDB"));
app.use("/auth", authRoute);
app.use("/users", userRoute);
app.use("/comments", commentRoute);
app.post("/api/home", tvshowsRoute);
app.use("/api/home", tvshowsRoute);
/*
app.get('/api/home', (req,res)=>{
TvShows.find().then((result)=>{
res.send(result);
})
})
*/
/*
app.use("/",(req,res)=>{
console.log("main url")
})*/
app.listen("3001",()=>{
console.log("backend running");
})
//////route
const router = require("express").Router();
const TvShows = require("../models/TvShows");
router.post("/api/home", async (req, res) => {
console.log("here")
try{
const newTvShow = new TvShows({
title: req.body.title,
poster: req.body.poster,
info: req.body.info
});
const savedTvShows = await newTvShow.save();
res.status(200).json(savedTvShows);
}catch (err) {
res.status(500).json(err);
}
}
);
router.route("/api/home").get((req, res)=>{
TvShows.find()
.then(foundShows=> res.json(foundShows))
})
module.exports = router;
when I change res.json with res.text I see my index.html page on console not the data I want to fetch from mongodb. This error is probably because I didn't use /api/ on root url but I couldn't figure it out where I should write it. I tried but didn't work. It would be so good if someone could've helped. Thank you so much.
Indeed, you are fetching the /home page of your front-end app.
Assuming the api is on a different server, you would need to call the address of that server.
If you have a set up locally with a nodejs server and a react app running separately, you should have them run on two different ports.
If you have react app on http://localhost:3000 (default), then change your api to listen on 3001, then in your react code above, you can use the full uri
http://localhost:3001/api/home
in your fetch call.
I'm making a lot of assumptions about how you have this set up, based on my own experience of local development for similar problems.

NextJs - React component methods get called twice per request

I'm experimenting with NextJs Custom Server using Express. And i noticed that on every request, getInitialProps gets called twice. When trying to find out what the problem is i stumbled upon React.Strictmode being the reason for that since it calls certain class methods and constructor twice to help debug. When setting it to false, the getInitialProps method gets called three times. NextJs "pages" folder routing is disabled.
To be mentioned that render() gets called twice or three times too.
My server.js :
require('dotenv').config();
const express = require('express');
const next = require('next');
const dev = process.env.NODE_ENV !== 'production';
const mongoose = require('mongoose');
const app = next({ dev });
mongoose.connect(process.env.DB_URI)
.then(()=>{
console.log('>Succesfully connected to the database');
app.prepare()
.then(() => {
const server = express();
server.listen(3000, (req, res) =>{
console.log('>Listening on port 3000');
});
server.get('*', (req, res)=>{
app.render(req, res, '/index', {something:true});
})
})
.catch((ex) => {
console.error(ex.stack);
process.exit(1);
})
})
.catch(e=>{
console.log('<!>Error connecting to database: \n' + e);
});
and my GetInitialProps:
static async getInitialProps(ctx){
console.log({...ctx.query});
console.log('once');
return {props:{...ctx.query}};
}
Console when Strictmode on:
{ something: true }
once
{ something: true }
once
Console when Strictmode off:
{ something: true }
once
{ something: true }
once
{ something: true }
once

setupProxy.js in Create React App not working

Hello I am trying to get a dynamic proxy going in react and express. I do not want to configure the proxy in the package.json because I need it to be dynamic. I have tried the following using setupProxy.js by the CRA documentation. Here is my code
TypeError: Cannot read property 'split' of null
[1] at required (/Users/chadlew/Desktop/SC.CRM.React/client/node_modules/requires-port/index.js:13:23)
[1] at Object.common.setupOutgoing (/Users/chadlew/Desktop/SC.CRM.React/client/node_modules/http-proxy/lib/http-proxy/common.js:101:7)
[1] at Array.stream (/Users/chadlew/Desktop/SC.CRM.React/client/node_modules/http-proxy/lib/http-proxy/passes/web-incoming.js:127:14)
[1] at ProxyServer.<anonymous> (/Users/chadlew/Desktop/SC.CRM.React/client/node_modules/http-proxy/lib/http-proxy/index.js:81:21)
[1] at HttpProxyMiddleware.middleware (/Users/chadlew/Desktop/SC.CRM.React/client/node_modules/http-proxy-middleware/dist/http-proxy-middleware.js:22:32)
This is the error I'm getting everytime.
And here is my code: setupProxy.js
const { createProxyMiddleware } = require('http-proxy-middleware');
module.exports = function(app) {
app.use(
'/api', // You can pass in an array too eg. ['/api', '/another/path']
createProxyMiddleware({
target: process.env.REACT_APP_PROXY_HOST,
changeOrigin: true,
})
);
};
Here is the React:
import React, { useState, useEffect } from 'react'
import GoogleLogin from 'react-google-login';
const Login = ({history}) => {
const [authData, setAuthData] = useState({});
useEffect(() => {
if(Object.keys(authData).length > 0) {
(async () => {
const res = await fetch("/api/auth/login", {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(authData)
});
// This data would be set into app level state (react-context api) and be accessible everywhere
const { message, isAuth, userData } = await res.json();
})();
}
}, [authData, history])
const successHandler = data => {
setAuthData(data);
history.push("/home");
}
const failureHandler = (data) => setAuthData(data);
return (
<div className = "login-page">
<h1 style = {{marginBottom: '1rem'}}>Welcome</h1>
<GoogleLogin
clientId = {process.env.REACT_APP_GOOGLE_CLIENT_ID}
buttonText = "Login with Google"
onSuccess = {successHandler}
onFailure = {failureHandler}
cookiePolicy = {'single_host_origin'}
/>
</div>
)
}
export default Login;
Whenever I login with google I get the error message and the proxy ultimately does not work. Any suggestions would be highly appreciated

http-proxy-middleware does't catch request from react app to API

Into my component
axios.post('/api/' + 'create', {
name: 'new name'
},
{
headers:
{
'Content-Type': 'application/json'
}
}
)
into setupProxy.js , created from third part official instruction https://facebook.github.io/create-react-app/docs/proxying-api-requests-in-development
const proxy = require('http-proxy-middleware');
module.exports = function (app) {
app.use(proxy('/api/', {
target: 'http://my-api.com/',
changeOrigin: true
}));
};
When i call method with axios from my app
into browser console write
POST http://localhost:3000/api/create 404 (Not Found)
I tryed to write /api/* and /api/** into configuration http-proxy-middleware , but it did't help me.
What it does't work?
Please try using below code, with http-proxy-middleware version 1.0.0 onwards, you cannot use proxy as the name.
const { createProxyMiddleware } = require('http-proxy-middleware');
module.exports = (app) => {
app.use(createProxyMiddleware('/api',
{ target: 'http://localhost:3001/'
}));
}
Note: found this from one of the PR discussions here: https://github.com/facebook/create-react-app/issues/8550
I know its late and I came across the same issue. Keeping what worked for me so that others can give it a try.
I proxied this endpoint - https://services.odata.org/V2/Northwind/Northwind.svc/Customers?$format=json
setupProxy.js
const { createProxyMiddleware } = require('http-proxy-middleware');
module.exports = (app) => {
app.use(createProxyMiddleware('/api2', {
target: 'https://services.odata.org/V2/Northwind/Northwind.svc/',
changeOrigin: true,
pathRewrite: { '^/api2': '' }
})
);
}
Your .js file
triggerCORSCall() {
axios.get(`/api2/Customers?$format=json`)
.then(response => {
alert('Success');
}).catch(error => {
alert('Failure');
console.log(error);
})
}

Resources