Axios/Fetch not using next.config.js rewrite - reactjs

Looking up several examples online, it appears all one would need to do to redirect requests to the backend is to add rewrites to the next.config.js file, and it should work. However, I must be missing or misunderstanding something as this alone doesn't seem to do the trick. Redirecting seems to work if I type the url in the browser, but calls from axios/fetch continue to try to use a path relative to my client. Here are my snippets:
next.config.js
module.exports = {
async rewrites() {
return [
{
source: '/api',
destination: 'http://localhost:3001',
},
]
},
};
components/MyComponent.js
import React, { useEffect } from "react";
import axios from "axios";
function MyComponent({projectName}) {
...
useEffect(() => {
axios.get("/api/project/" + projectName)
.then((res) => {
console.log(res);
});
return;
}, []);
...
};
export default MyComponent;
To clarify, if I hit http://localhost:8001/api/project/Name_of_Project from the browser, I get properly redirected to my server (hosted on port 3001) and receive data I'd expect. However, when I hit my client (http://localhost:8001/Name_of_Project), axios doesn't redirect and tries http://localhost:8001/api/project/Name_of_Project which obviously fails. I also tried the fetch equivalent instead of axios and get the same result.
Is there another step that I need to take? Does the rewrite not work for axios/fetch? I have also seen mentions of the next-http-proxy-middleware package in my search, but I am not sure if this is something that I need to use in conjunction with the rewrite or not.
I appreciate any insight!
EDIT 1:
After doing some more searching, I ran into this post, and discovered that my issue is because I am using relative pathing in my axios call. If I change it to:
axios.get("http://localhost:3001/api/project/" + projectName)
.then((res) => {
console.log(res);
});
then I get my data properly. I suppose this leads me to my next question: is there a way to use relative path alongside the rewrite in the config? I personally think it's a little ugly to have the hostname and port exposed like that (I eventually plan on hosting this app on a FQDN). So if there's anything that can be done about that, I'd love to know!
EDIT 2: Of course the change in my first edit works because I am hitting my server directly! Which is not the desired effect. I want to use the redirect set in the config to go to my api.

Aha! I WAS misunderstanding something. I assumed that the path in the rewrite would reattached my path params for free. This is not the case. A link to the documentation.
The relevant excerpt:
Wildcard Path Matching
To match a wildcard path you can use * after a parameter, for example /blog/:slug* will match /blog/a/b/c/d/hello-world:
module.exports = {
async rewrites() {
return [
{
source: '/blog/:slug*',
destination: '/news/:slug*', // Matched parameters can be used in the destination
},
]
},
}
So my corrected next.config.js:
module.exports = {
async rewrites() {
return [
{
source: '/api/:slug*',
destination: 'http://localhost:3001/api/:slug*',
},
]
},
};

Related

Change the address without refreshing the page

I have a category list, which changes the address of the page by selecting each category, similar to dynamic adress, for example, when you select a game, the address goes to:
/s/game changes
Or you choose real estate
/s/estate
To transfer from the code:
router.push(address), null, {
shallow: true,
scroll: false
})
I use.
But the problem is that the things related to receiving the link only work the first time and the second time only the address changes and getStaticPaths and getStaticProps do not work at all!
The codes inside related to the /s/[category].js file (address recipient file):
export async function getStaticPaths() {
return {
paths: [
{ params: { category: "Search Category" } },
],
fallback: false,
};
}
export async function getStaticProps(context) {
const { params } = context;
return {
props: {
category: params.category,
},
};
}
It means that after compiling the component, the related items will no longer work!
where is the problem from ? Do you know the best method for this? Thank you for telling me
I have said all the things I used in the question
You may try to troubleshoot this issue with hlep of developer tools integrated with your browser Firefox or Chrome then in network tab look at http requests. You are looking for new http get to new uri

Redirect programatically using Regex in next.config.js

My website is changing URL structure and I have 1000s of pages. For SEO I would like to set up a Regex redirect in my next.config.js file, but the official documentation doesn't really help my case because my pages have the following structure:
/product-name-price/
The new structure will be:
/price/product-name
UPDATE:
I've managed to get /product-name-price to redirect to /price/product-name-price with the following changes to next.config.js:
async redirects() {
return [
{
source: '/:product',
destination: '/price/:product',
permanent: true,
}
]
}
How do I manipulate the :product parameter within the next.config.js file to exclude the -price part of product-name-price so that my final url will be /price/product-name?
I resolved this using middleware since it doesn't seem to be possible to modify the parameter of the redirect destination in next.config.js.
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
if (request.nextUrl.pathname.endsWith('-price') || request.nextUrl.pathname.endsWith('-price/')) {
return NextResponse.redirect(new URL(`/price/${request.nextUrl.pathname.split("-price")[0]}`, request.url), 308)
}
if (request.nextUrl.pathname.includes('price.php')) {
return NextResponse.redirect(new URL(`/price/${request.url.split("price.php?brand=")[1].toLowerCase()}`, request.url), 308)
}
}
The first conditional checks if the request pathname ends with -price, and then redirects to the same path without -price by splitting the string, with status code 308.
The second conditional checks to see if the request pathname contains price.php, in which case it also has query parameter of 'brand'. It takes the value of this parameter and redirects to the /price/product-name structure, where 'product-name' is equal to the value of 'brand', again by splitting the string.
I have used 308 redirect for SEO purposes, to indicate it is a permanent redirect to Google.
You can do it using RegEx in your next.config: Regex Path Matching
It will be something like this:
module.exports = {
async redirects() {
return [
{
source: '/:product-name(.*)-:price(\\d)',
destination: '/:price/:product-name',
permanent: true,
},
]
},
}
#user3536141, I can try to help you with a more accurate example if you provide the use case and its variations (if there is some).

How to have dynamic redirect URLs in Next.js?

I'm working on a Next.js/Django project, which the user is able to add some redirect logic from the admin panel like:
[
{ source: "/about", destination: "google.com" },
{ source: "/about1", destination: "google1.com" },
{ source: "/about2", destination: "google2.com" },
]
and the web application should be able to handle these dynamic redirects.
As the Nextjs docs says, we can do this in next.config.js. The problem is that we can't have dynamic data in next.config.js. With every change in this file, server must be restarted.
Here we need a logic that gets the urls using an API on website load, loops through them and listens for every route calls to see if they match the redirect data or not.
I have tried some other ways too, like trying to use useEffect, but this way causes the website to render 404 page first and then it redirects to the desired url, which is not that nice for user experience viewpoints.
You can use Next.js Middleware to fetch the dynamic redirects array from the API, and add your own logic to handle the redirection.
Unlike redirects in the next.config.js that run at build time, Next.js Middleware runs on each incoming request to your pages and is able to dynamically fetch the redirects every time.
export async function middleware(req) {
// Fetch redirects array from API
const res = await fetch('https://example.com/api/redirects');
const redirects = await res.json();
/* Assuming the returned `redirects` array would have the following structure:
[
{ source: '/about-us', destination: '/about' },
{ source: '/google', destination: 'https://google.com' }
]
*/
// Find the matching redirect object
const redirect = redirects.find((redirect) => req.nextUrl.pathname === redirect.source);
if (redirect) {
if (redirect.destination.startsWith('http')) {
// Handle external URL redirects
return NextResponse.redirect(new URL(redirect.destination));
}
// Handle internal URL redirects
return NextResponse.redirect(new URL(redirect.destination, req.url));
}
// Continue if no matching redirect is found
return NextResponse.next();
}

How to get rid of this - message:{'You are not subscribed to this API.'}.?

import React from 'react';
import './App.css';
function App() {
fetch("https://spoonacular-recipe-food-nutrition-v1.p.rapidapi.com/recipes/quickAnswer?q=How%20much%20vitamin%20c%20is%20in%202%20apples%253F", {
"method": "GET",
"headers": {
"x-rapidapi-host": "[host]",
"x-rapidapi-key": "[key]"
}
})
.then(response => {
console.log(response);
})
.catch(err => {
console.log(err);
});
return ( <
div className = "App" >
<
form className = 'searchform' >
<
input className = 'search-bar'
type = "text" / >
<
button className = 'search-bar'
type = 'text' > Submit < /button> < /
form > <
/div >
);
}
export default App;
if you have everything set up correct on RapidAPI I would suggest passing the key without using variables because maybe you are passing undefined. For undefined we get exactly the same error.
You have to select a pricing plan, even if it's the free plan. Go to "Pricing" on the page for the API, and select a plan. This fixed the issue for me.
https://api.rakuten.net/Top-Rated/api/e-mail-check-invalid-or-disposable-domain/discussions/9487/keep-getting-this-response-%22You-are-not-subscribed-to-this-API.%22
Be sure that you actually subscribe tothe api on rapid api hub if you aren't subscribed to the api
you're going to get an error message that notifies you don't have an active subscription and your call will not
be successfulbe sure that you actually subscribe tothe api on rapid api hub if you aren't subscribed to the api
you're going to get an error message that notifies you don't have an active subscription and your call will not
be successful
message: you are not subscribed to this api rapidapi
video example
Make sure you select a plan whether it's a free plan or a premium plan.
https://rapidapi.com/tipsters/api/hotels-com-provider/pricing
If you are subscribed to the free plan and still getting this error "message:{'You are not subscribed to this API.'}"
The problem might be related to the .env location. Try placing it inside root of your folder, rather than src folder.
Maybe the problem is with GET, try this. And let me know, if it works or not.
state = {
url:
"<url>",
header: {
"x-rapidapi-host": "<host>",
"x-rapidapi-key": "<key>"
}
};
componentDidMount() {
axios
.post(this.state.url, this.state.header)
.then(res => {
console.log(res.data);
})
.catch(err => console.log("err" + err));
}
For anyone else encountering this issue: the oversight I made was adding 'Bearer ' in from of the RapidAPI key. It should just be the key, without anything in front of it.
This may be stale, but helpful to someone else:
The first thing you want to do is to avoid placing it within .env.
Ensure it works properly within the code snippet (unsafe method) before placing it within .env (current best practice).
For instance, you should first do this:
const options = {
'X-RapidAPI-Key': 'theVeryLenthyKey',
'X-RapidAPI-Host': 'theAPI.p.rapidapi.com'
}
};
Instead of this:
const options = {
'X-RapidAPI-Key': process.env.THE_VARIABLE_NAME_YOU_USED,
'X-RapidAPI-Host': 'theAPI.p.rapidapi.com'
}
};
I got the same response saying {message: you are not subscribed ... but I was, I made sure. So the problem was that it couldn't read from the .env file.
So I used the manual method of directly putting the key in the code while in the development phase, but when I deployed the project I added it in the environment variables of the hosting service and it was working just fine.
If you are passing your key as variables, make sure you place your .env file in root folder (environment variables)
I have fixed this issue by simple directly passing key, like this
export const exerciseOptions = {
method: "GET",
headers: {
"X-RapidAPI-Host": "exercisedb.p.rapidapi.com",
"X-RapidAPI-Key": "xxxxxxxxxxxxxxxxxx",
},
};
don't pass the key through the .env file

admin-on-rest Using PATCH method

I am a junior node developer and am trying out admin on rest to quickly run up an admin panel for my json api. However, all of my update requests use patch instead of put. I attempted revising the UPDATE method in my restClient but this seems wrong (the rest of the methods are removed for brevity)
export default (apiUrl, httpClient = fetchJson) => {
const convertRESTRequestToHTTP = (type, resource, params) => {
let url = ''
const options = {}
switch (type) {
case UPDATE:
url = `${apiUrl}/${resource}/${params.id}`
options.method = 'PATCH'
options.body = JSON.stringify(params.data)
break
return { url, options }
}
}
To me this makes sense but when I try to edit an object I get back HTTP/1.1 404 Not Found <pre>Cannot PUT </pre>
I know that that this wasn't possible with previous versions but I read this https://marmelab.com/blog/2017/03/10/admin-on-rest-0-9.html#http-patch but was a little confused on how it works? I guess I just don't know where to start with this.
if problem still is actual now, please check some places which are using by me to set my customRestClient.
// App.js
import customRestClient from './customRestClient';
in my case i'm using httpClient to add custom headers:
import httpClient from './httpClient';
below:
const restClient = customRestClient('my_api_url', httpClient);
and finally:
<Admin title="Admin Panel" restClient={restClient}>

Resources