Unable to rewrite url in Next.js - reactjs

I am unable to rewrite the request url below is how my next.config looks
module.exports = withPlugins([
...
{
async rewrites() {
console.log("Rewrites called");
console.log(process.env.NEXT_PUBLIC_DOCS_URL)
return [
{
source: '/docs',
destination: process.env.NEXT_PUBLIC_DOCS_URL,
}
]
}
console logs are correctly printed with new urls but the component is not getting updated with correct links :
<Link href="/docs">
<Button className={NavbarClasses.button}>
<Box color={navWhite ? 'black' : 'white'}>Docs</Box>
</Button>
</Link>
The contents of .env file is as below:
NEXT_PUBLIC_DOCS_URL = http://localhost:4000/docs/intro
But the Link is rendered as localhost:3000 instead of localhost:4000.
Thanks.

According to the Next.js documentation:
Rewrites act as a URL proxy and mask the destination path, making it
appear the user hasn't changed their location on the site. In
contrast, redirects will reroute to a new page and show the URL
changes.
In the nutshell, when user opens your /docs page on localhost:3000 Next.js will send a request on his behalf to localhost:4000 and pass back response. From user's perspective, it looks like localhost:3000 is producing it.
If it's crucial for you to retain original URL, you should use redirects.
Redirects allow you to redirect an incoming request path to a
different destination path.

Related

Django / React - Production API URL routing issues

I have a backend Django REST API that also helps serve my React frontend. I currently have an issue with my API requests url paths to my Django API in production for every page except my home page...
API URL's that work:
I'm able to visit my home page, within my home page, I have a GET request to my API which works great and loads data as expected. This is the only working GET request of my website because the API URL path is correct to my urlpatterns syntax.
API URL's that DON'T work:
The issues arise when I visit a page OTHER than the home page of my React app. My API requests to Django on other pages are using the wrong URL path according to my network panel (they are also responding with index.html), which has me believe I set up my django URLs wrong.
Please checkout my configuration below:
main urls.py:
def render_react(request):
return render(request, "index.html") #<---- index.html from React
urlpatterns = [
path('auth/', include('drf_social_oauth2.urls', namespace='drf')),
path('admin/', admin.site.urls),
path('api/', include('bucket_api.urls', namespace='bucket_api')),
path('api/user/', include('users.urls', namespace='users')),
path('api-auth/', include('rest_framework.urls', namespace='rest_framework'))
]
urlpatterns += [
re_path('',render_react) #<---- Serving React index.html
]
Here is an example of the issue:
When I visit this subpage URL:
https://mywebsite.com/try-demo/ra4r7n7mdb
A GET request should be firing off too this URL:
https://mywebsite.com/api/demo/ra4r7n7mdb
However instead of sending the request to the correct URL above, it's sending to this url:
https://mywebsite.com/try-demo/api/demo/ra4r7n7mdb
This is the same problem for other parts of my website that are requesting data from my django api. So when I visit my login page (https://mywebsite.com/login), and enter my details to request an authentication token. The request for the token should be:
https://mywebsite.com/auth/token/
but instead its requesting the data through this:
https://mywebsite.com/login/auth/token/
How to fix this?
my url patterns has a catch all request, my react is then able to 404 pages that don't exist. The only problem I have is how my React app is requesting data to my API in production. (again the API request on my homepage works fine) Why are my other requests appending the first URL path of my React router URL's?
I don't want to clog this post with code, so please let me know what other information I should present here to help solve this problem?
UPDATE
I have solved the API request issues to my server. The paths are now correct according to the network panel. However, the issue still remains where I seem to be only getting my index.html as the response for these API requests (they should be data responses, not index.html)
Here is my catch all regex for Django
re_path(".*/", render_react),
re_path(r"^$", render_react)
NEW EDIT
I am now able to get one of my API data requests to respond with JSON data (as should be expected)
Here is the URL of the API request that works:
https://mywebiste.com/api/demo/idoyem1l4k/
These still don't work:
https://mywebsite.com/api/demo/tabledata/idoyem1l4k
https://mywebsite.com/api/demo/graphdata/idoyem1l4k
How I make requests:
import axios from 'axios';
const baseURL = `https://mywebsite.com/api`;
const axiosInstance = axios.create({
baseURL: baseURL,
timeout: 9000,
headers: {
Authorization: 'Bearer ' + localStorage.getItem('access_token'),
'Content-Type': 'application/json',
accept: 'application/json',
},
});
export const getData = async (dispatch, slug, cancelToken) =>
{
try
{
console.log('fired demo request')
const response = await axiosInstance.get("demo/graphdata/" + slug, { cancelToken });
dispatch({ type: 'FETCH_SUCCESS', payload: response.data });
} catch (err)
{
if ('isCancel' in err && err.isCancel())
{
return;
}
dispatch({ type: 'FETCH_ERROR' });
}
}
How can I return the actual data requested instead of my index?
It makes sense, that it always returns the index.html. Your catch all regex prevents your API calls to be called, so it always resolves to render_react. I think you have 3 options.
You try to put the catch-all patterns to the bottom of all urlpatterns - I'm not sure how reliable this is though
You do not catch all by deleting re_path(".*/", render_react), and explicitly name every react page you want to use
You change the catch-all regex to exclude your Django apps with something like re_path("(?!api).*/", render_react),
I would choose option 2, as it gives you most control of your urls

React and Nest.js google auth return CORS Error

I'm using in React of library "react-google-login": "^5.2.2" and in Nest.js: "passport-google-oauth20": "^2.0.0". In Nest.js google auth work correctly, but I have a problem on front-end site. When I click on button "Sign in with Google" and I loggin to google. Google auth return error cors:
Access to XMLHttpRequest at
'https://accounts.google.com/o/oauth2/v2/auth?response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A7000%2Fauth%2Flogin-google%2Fredirect&scope=email%20profile&client_id=XXXXX.apps.googleusercontent.com'
(redirected from 'http://localhost:7000/auth/login-google') from
origin 'http://localhost:3001' has been blocked by CORS policy: No
'Access-Control-Allow-Origin' header is present on the requested
resource.
I'm trying fix this problem by add proxy to React (docs):
File src/setupProxy.js:
const createProxyMiddleware = require('http-proxy-middleware')
module.exports = function (app) {
app.use(
'/auth/login-google',
createProxyMiddleware({
target: 'http://localhost:7000',
changeOrigin: true,
}),
)
}
But still I have this same CORS error.
React - http://localhost:3001
Nest.js - http://localhost:7000
How I can fix it?
EDIT:
I found this answer. I change action onClick on button "Sign in with Google" to:
window.location = 'http://localhost:7000/auth/login-google'
Now I don't get CORS error. Nest.js return me data about user (as I wanted, it's work correctly) but I don't know how I can listen in React when user is logged in. Because now when user click "Sign in with Google" (when the user logs in correctly) then the browser redirects to the address:
http://localhost:7000/auth/login-google/redirect?code=4%2F0AY0e-g7UsKrAyhmnc3xQBT3oE9ck9bCfuuO7lX9RJxh9JuRrZfdFPCaVZsRppapRfanGlw&scope=email+profile+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile+openid+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email&authuser=0&prompt=none
I'm trying using history.location but not work, because it's not address of React.

React request URL changes itself, depending on the location of the call. (Both axios and fetch)

I sent Axios Request in the React Component as always and succeeded.
server > routes > product.js
router.post("/removeImages", auth, (req, res) => {
req.body.images.map(imgPath => {
fs.unlink(imgPath, (err)=>{
if(err){
console.log(err);
}
console.log('Image removed successfully');
});
});
});
client > src > components > FileUpload.js
import Axios from 'axios';
function FileUpload(props) {
...
Axios.post('api/product/removeImages', { images: Images });
So, I copied the line(Axios.post('api/product/removeImages', { images: Images });) and used it in the child component. Then, the following error occurred:
POST http://localhost:3000/product/api/product/removeImages 404 (Not Found)
I thought it was an Axios bug, so I changed it to a fetch(), but I got the same result (404 Not Found). I do not know how hard-coded URL can change depending on the component. Maybe it was a React bug?
It looks like you're missing a starting / in the url. When not starting the url with /, it will be relative to whatever your path is currently.
Meaning if you're currently in localhost:3000/products, any requests to the relative path api/products/removeImages will resolve to localhost:3000/products/api/products/removeImages
A call to /api/products/removeImages, with the staring /, will only be relational to the base url, in this case localhost:3000, not the current path, thus result in locahost:3000/api/products/removeImages.
tl;dr: Add a prefixing / to your urls to resolve your relative path issue.
Additionally, as #ataravati mentioned in the comments, best practice is to also set a baseURL for axios.

Need help about nextjs dynamic url

I am having this problem that whenever i try to visit the page localhost:3000/blog/test directly it returns a 404 error. But whenever i try to visit it using <Link> component it works fine.
This is my code <Link href={{ pathname: '/blog', query: {slug: 'test'} }} as="/blog/test"><a className="nav__link">Blog</a></Link>
and i have a file blog.js in my pages folder.
What's happening is that on the client, with the Link component, you are creating a link to the blog.js page by setting "/blog" as the pathname.
When you go directly to the URL/blog/test, Next.js will try to render the page on the server and to do so will look for the file /pages/blog/test.js. That file doesn't exist, and Next.js doesn't know that you want to load the blog.js page and set query.slug to to the second part of the URL.
To do this, you need to map that route on the server to load the page you want, and pull the params you want out of the URL.
The Next.js docs cover this in Server Side Support for Clean URLs by using express to setup a custom server.
You can view the full code to get it working there, but your custom route will look something like this:
server.get('/blog/:slug', (req, res) => {
const actualPage = '/blog'
const queryParams = { slug: req.params.slug }
app.render(req, res, actualPage, queryParams)
})
You'll have to use now.json to set up your routes. Also it is important to note that it's now that builds the route so visiting it on the client side wont work if you are using localhost. Build your project with now and it should work.
Also the "as" parameter would be as={{ pathname:/user/manage/${variable}}}

Refreshing a react router page that has a dynamic url/params

I have several components displayed with react router that have dynamic url paths. An example path I have is
<Route path="/newproject/:id" onEnter={checkSesh} component= {ProjectDetails} />
When entering this component, I have a componentWillMount function that extract the id part of the url so that I can get the info for the correct project and render it on the ProjectDetails component.
componentWillMount() {
var id = this.props.router.params.id
this.props.teamDetails(id);
}
this.props.teamDetails(id) this calls a redux action creator that will make an axios request to an express route that will get the project info from the database.
export function teamDetails(id) {
return function(dispatch) {
axios.get('/getteaminfo/' + id)
.then(res => {
dispatch({ type: "SET_TEAM_DETAILS", payload: {
teamInfo: res.data.teamInfo,
admin: res.data.admin,
adminID: res.data.teamInfo.teamAdmin,
teamMembers: res.data.teamInfo.teamMembers
}
})
});
}
}
everything works fine upon visiting the page after already being logged in etc. But when I refresh the page /newproject/:id, i get an error Uncaught SyntaxError: Unexpected token <. An example url in my browser looks like http://localhost:3000/newproject/58df1ae6aabc4916206fdaae. When I refresh this page, I get that error. The error is complaining about my <!DOCTYPE html> tag at the very top of my index.html for some reason. This index.html is where all of React is being rendered.
When page is refreshed store state is not preserved. Make sure the state is not important to load the page, or at least initialized properly every time.
For e.g. login information if saved in store and not on browser with localStorage or cookies etc.. then on refresh, the error will come when trying to access /getteaminfo/ route through axios. The response will have error html and it can't be parsed by js.
Please check your web console on for more information. You can use chrome extension like https://github.com/zalmoxisus/redux-devtools-extension which will show your store and etc..
Make sure to check what /getteaminfo/ gives with id is not passed.
Also, make sure on your server side, did you route requests to react-router path through something like this?
e.g. express js,
app.get('*', function response(req, res) {
res.sendFile(path.join(__dirname, 'public', 'index.html'));
});
be sure to sendFile with the real location of index.html
I found the answer here: react-router dynamic segments crash when accessed I added <base href="/" /> into the <head>of my index.html. You can also read more info here: Unexpected token < error in react router component

Resources