I cannot implement DJANGO REST API with REACT - reactjs

I want to integrate React with Django REST API for my ecom website but for some reason that does not work. I really do not know what I missed. Any input is welcomed.
Please see the code below.
REACT
Home.js (this is the code for products)
const loadAllProducts = () => {
getProducts()
.then((data) => {
if(data.error) {
setError(data.error); //box filled with data error
console.log(error); // message "error"
} else {
setProducts(data); // box filled with data product
}
});
loadAllProducts();
};
coreapicalls.js (here I want to fetch the data)
import { API } from "../../backend.js";
export const getProducts = () => {
return fetch(`${API}product`, { method: "GET" })
.then(response => response.json())
.catch((err) => console.log(err));
};
.env (I have both of my servers running, the url and symbol "/" are correct.)
REACT_APP_BACKEND = http://localhost:8000/api/
My compiler returns no specific error.
./src/core/Home.js
Line 16:11: 'loadAllProducts' is assigned a value but never used no-unused-vars
./src/core/Card.js
Line 26:11: 'getAredirect' is assigned a value but never used no-unused-vars
DJANGO (settings.py, Django does give me JSON data on the localhost:8000/api/product/)
'api',
'api.category',
'api.product',
Best,
Rok.

I went into chrome devtools and saw a "cors error" under network. I forgot to run "pip install django-cors-headers" . The configuration on the DJANGO REST API for corsheaders was correct.

Related

Axios API call returns a 404 on page render, but still returns api objects in terminal

I am using axios to make an api call to an api found on Apihub for a next JS app.
here is the code for the function to make the call to provide a list of property JSON objects.
export const baseUrl = "https://zillow56.p.rapidapi.com"
export const fetchApiListsingsCustom = async (url) => {
const { data } = await axios.get((url), {
method: 'GET',
headers: {
'X-RapidAPI-Key': '328713ab01msh862a3ad609011efp17e6b4jsn0e7112d5ee9a',
'X-RapidAPI-Host': 'zillow56.p.rapidapi.com'
}
});
data.then((res) => {
console.log(res);
})
.catch((error) => {
console.error(error);
});
return data.json();
}
When rendering the page I'm attempting to inject the response's data to dynamically create a list of apartment listings.
I'm trying to use getServerSideProps so that the data is already available by the time a user requests the page. After fetching the data, I want to also print them in the terminal to validate it's success.
export default function Home({ propertiesCustomdata })
export async function getServerSideProps() {
const propertiesCustom = await fetchApiListsingsCustom(`${baseUrl}`)
const propertiesCustomdata = propertiesCustom.json()
return {
props: {
propertiesCustomdata
}
}
}
The problem is, I seem to be getting a 404 error from the axios call, before the page gets a chance to load. When I access this I get a 404 error but I also manage to receive some contents of the call the API was to make.
My apologies if this is unclear, but this is all I know to report on this so far.
Studying async and await, fetch, and axios. Very confusing.

React repeatedly requests API data

I'm requesting API data through axios using RapidAPI's Apis.
I followed all the documentations provided in RapidAPI with a relatively simple code. However, when I log the values, it keeps repeatedly requesting data over and over and this in turn hikes up my requests from RapidAPI and uses a lot of resources and money. I can't figure out how to only retrieve the values ONCE. Here are my codes.
My React .tsx file
const [sportsData, setSportsData] = useState()
const fetchSportsData = () => {
axios
.request(testApi)
.then((response) => {
setSportsData(response.data)
})
.catch((error) => {
console.log(error)
})
}
fetchSportsData()
console.log(sportsData)
My Api File
export const testApi = {
method: 'GET',
url: 'https://api-football-v1.p.rapidapi.com/v3/timezone',
headers: {
'X-RapidAPI-Key': '-------removed on purpose ---------',
'X-RapidAPI-Host': 'api-football-v1.p.rapidapi.com'
}
}
I am just setting the data using useState but it seems to repeatedly rerender whenever a value is stored. I've tried many roundabout ways but it seems to repeatedly request over and over again. Has anyone used API's from RapidAPI before?
While I don't know why useState will still repeatedly retrieve API data with axios, this is a workaround as commented by Sergey Sosunov.
On the React File
const [sportsData, setSportsData] = useState()
const fetchSportsData = () => {
axios.request(testApi).then((response) => {
setSportsData(response.data)
})
.catch((error) => {
console.log(error)
})
}
useEffect(()=> {
fetchSportsData()
},[])
On dev mode, the useEffect will run twice on load and depending on your API provider, this may mean calling the API twice on every load which may double your costs unnecessarily, this only happens in development mode as outlined in react documentation, what you can do is include a useRef variable.
const firstRender = useRef(false)
useEffect(()=>{
if (firstRender.current) {
fetchSportsData()
} else {
firstRender.current = true;
}
},[])
Remember that this code may not execute perfectly when in production as useEffect is only run once and the above code needs it to run twice in order to change the state of firstRender to true before retrieving the API call. This is just to help you lower your development costs.

How can I deal with CORS issue with create-react-app?

I'm trying to get data from images.google.com with axios.get on my create-react-app application and hosting by firebase.
This is the function of getting request results data from the URL.
const getImage = (transcript) => {
console.log("getImage executed,", transcript[transcript.length-1])
axios.get(`/images?&um=1&hl=en&nfpr=1&q=${transcript[transcript.length-1]}`)
.then((res)=> {
const search = document.querySelector(".search");
search.innerHTML = res.data;
search.querySelectorAll("img").forEach((element) => {
if(element.hasAttribute("data-src")){
const firstImage = element.getAttribute('data-src');
images.push(firstImage);
setSearchResult(images[images.length-1]);
}
});
console.log(res);
})
.catch((error) => {
console.log(error);
})
}
and on package.json I added
"proxy": "https://images.google.com"
but of course still blocked by CORS.
error
I know this is wrong and I think I don't understand the concept of middleware or backend server stuff enough.
So is there any idea to solve this problem in an easy way? Thanks.

Next.js - Error: only absolute urls are supported

I'm using express as my custom server for next.js. Everything is fine, when I click the products to the list of products
Step 1: I click the product Link
Step 2: It will show the products in the database.
However if I refresh the /products page, I will get this Error
Server code (Look at /products endpoint)
app.prepare()
.then(() => {
const server = express()
// This is the endpoints for products
server.get('/api/products', (req, res, next) => {
// Im using Mongoose to return the data from the database
Product.find({}, (err, products) => {
res.send(products)
})
})
server.get('*', (req, res) => {
return handle(req, res)
})
server.listen(3000, (err) => {
if (err) throw err
console.log('> Ready on http://localhost:3000')
})
})
.catch((ex) => {
console.error(ex.stack)
process.exit(1)
})
Pages - products.js (Simple layout that will loop the products json data)
import Layout from '../components/MyLayout.js'
import Link from 'next/link'
import fetch from 'isomorphic-unfetch'
const Products = (props) => (
<Layout>
<h1>List of Products</h1>
<ul>
{ props.products.map((product) => (
<li key={product._id}>{ product.title }</li>
))}
</ul>
</Layout>
)
Products.getInitialProps = async function() {
const res = await fetch('/api/products')
const data = await res.json()
console.log(data)
console.log(`Showed data fetched. Count ${data.length}`)
return {
products: data
}
}
export default Products
As the error states, you will have to use an absolute URL for the fetch you're making. I'm assuming it has something to do with the different environments (client & server) on which your code can be executed. Relative URLs are just not explicit & reliable enough in this case.
One way to solve this would be to just hardcode the server address into your fetch request, another to set up a config module that reacts to your environment:
/config/index.js
const dev = process.env.NODE_ENV !== 'production';
export const server = dev ? 'http://localhost:3000' : 'https://your_deployment.server.com';
products.js
import { server } from '../config';
// ...
Products.getInitialProps = async function() {
const res = await fetch(`${server}/api/products`)
const data = await res.json()
console.log(data)
console.log(`Showed data fetched. Count ${data.length}`)
return {
products: data
}
}
Similar to the #Shanker's answer, but if you prefer not to install the additional package for this, here is how to do it.
async getInitialProps({ req }) {
const protocol = req.headers['x-forwarded-proto'] || 'http'
const baseUrl = req ? `${protocol}://${req.headers.host}` : ''
const res = await fetch(baseUrl + '/api/products')
}
It sounds silly but worth mentioning. If you're using SSR in your webapp the fetch call will work with a relative link on the client but will fail on the server. Only the server needs an absolute link!
If you want to prevent the server from making the request just wrap it in logic
if(global.window){
const req = fetch('/api/test');
...
}
You could utilize environment variables if your project is hosted on a provider that supports it.
env.local
// Local
URL="http://localhost:3000"
// Production
URL="https://prod.com"
Then you can use the following.
const { URL } = process.env;
const data = await fetcher(URL + '/api');
This simple solution worked for me without having to add an additional config file,
Install
npm install --save next-absolute-url
Usage
import absoluteUrl from "next-absolute-url";
async getInitialProps({ req }){
const { origin } = absoluteUrl(req, req.headers.host);
console.log('Requested URL ->',origin);
// (or) other way
const host = absoluteUrl(req, req.headers.host);
console.log('Requested URL ->',host.origin);
}
Case 1. It's not an error. The isomorphic-unfetch is running by SSR mode, so Node.js needs to know the absolute url to fetch from it, because the back-end doesn't know your browser settings.
Case 2. Another scenario is to prevent the http host poisoning headers attack.
append secret keys and tokens to links containing it:
<a href="http://_SERVER['HOST']?token=topsecret"> (Django, Gallery, others)
....and even directly import scripts from it:
<script src="http://_SERVER['HOST']/misc/jquery.js?v=1.4.4">
Case 3. The isomorphic-unfetch it's the library we are going to use to fetch data. It's a simple implementation of the browser fetch API, but works both in client and server environments.
Read more about it:
Isomorphic unfetch - Switches between unfetch & node-fetch for client & server
Prevent http host headers attack
Fetching Data for Pages
In the NextJS 9.5, we can also use process.cwd().
process.cwd() will give you the directory where Next.js is being executed.
import path from 'path'
import fs from "fs";
export const getStaticProps: GetStaticProps = async () => {
const dataFilePath = path.join(process.cwd(), "jsonFiles", "data.json");
console.log(dataFilePath); // will be YourProject/jsonFiles/data.json
const fileContents = fs.readFileSync(dataFilePath, "utf8");
const data: TypeOfData[] = JSON.parse(fileContents);
return { props: { data } };
};
Ref: https://nextjs.org/docs/basic-features/data-fetching#reading-files-use-processcwd
Putting this out there because this showed up in google results for my problem, even though the question itself isn't really related (outside of the fact that the same dependency is throwing the same error message, albeit in a different context for a different reason).
I got this issue from using hardhat while attempting to verify (verify:verify) my contract on etherscan. The problem was that in the hardhat config, I didn't have a full url under rinkeby (since I was verifying on rinkeby, would be mainnet, etc.). Copy/pasting some config stuff quickly into a project I cloned from someone else, they had a full URL in their .env, while I had the url in the config and stored only my api key in my .env.
To figure this out, though, was straightforward--go into node_modules, then find the node-fetch folder, then lib, (this is from memory--just find the line that is vomitting in your stack trace) then the line number, and put a console log there to see what the "bad" url you're seeing is. Usually that's enough of a clue; in my case, it was an API key, obviously not a URL, and that made it straightforward to solve.
If you have an absolute path issues. Try to use swr to access data.
Notice: This is a React hooks so you must call inside the component.
import useSWR from 'swr';
// optionally you can use unfetch package from npm or built yours to handle promise.
const fetcher = (...args) => fetch(...args).then(res => res.json())
export const AllProducts = () => {
const { data, error } = useSWR('/api/products', fetcher)
if (error) return <div>failed to load</div>
if (!data) return <div>loading...</div>
return (
<div>{data}</div>
);
};
Export or deploying in production
Whenever you are trying to deploy on Vercel you might encounter an error. For instance `
warn - Statically exporting a Next.js application via `next export` disables API routes`.
It means you are trying to export data and NextJS does not support fetching data from pages/api/* directory. To avoid errors, its better to separate build and export command.
// package.json
{
"scripts": {
"dev": "next",
"build": "next build", // No next export command
"start": "next start"
},
}
Thanks folks for great contribution and I hope the answer shared will help somebody too.
Make sure what the value of your API url is
In my case, I was using POST but my url was somewhat undefined.
Use console.log to see where is your request going.
this is a way to get the base hostname to fetch data from external endpoint
without getting that error
function return_url(context) {
if (process.env.NODE_ENV === "production") {
return `https://${context.req.rawHeaders[1]}`;
} else if (process.env.NODE_ENV !== "production") {
return "http://localhost:3000";
}
}
and on the getServerSideProps or getStaticProps functions you use
export async function getServerSideProps(context) {
let url = return_url(context);
const data = await fetch(`${url}/yourEndPoint`).then((res) => res.json());
return {
props: {
data: data,
},
};
}
If you are using next environment config prefix your variables with NEXT_PUBLIC_ as mentioned here Exposing Environment Variables to the Browser.
USE: NEXT_PUBLIC_STRAPI_URL="http://localhost:1337" instead of
NEXT_PUBLIC_STRAPI_URL=http://localhost:1337
use .log(console.log) after nock , so you will get exact unmatched and expected url .
Example:
nock("http://localhost")
.log(console.log)
.persist()
.get("/api/config")
.reply(200, { data: 1234 })

Data fetching with React Native + Redux not working

I am building my first React Native app and use Redux for the data flow inside my app.
I want to load some data from my Parse backend and display it on a ListView. My only issues at the moment is that for some reason, the request that I create using fetch() for some reason isn't actually fired. I went through the documentation and examples in the Redux docs and also read this really nice blog post. They essentially do what I am trying to achieve, but I don't know where my implementation differs from their code samples.
Here is what I have setup at the moment (shortened to show only relevant parts):
OverviewRootComponent.js
class OverviewRootComponent extends Component {
componentDidMount() {
const { dispatch } = this.props
dispatch( fetchOrganizations() )
}
}
Actions.js
export const fetchOrganizations = () => {
console.log('Actions - fetchOrganizations');
return (dispatch) => {
console.log('Actions - return promise');
return
fetch('https://api.parse.com/1/classes/Organization', {
method: 'GET',
headers: {
'X-Parse-Application-Id': 'xxx',
'X-Parse-REST-API-Key': 'xxx',
}
})
.then( (response) => {
console.log('fetchOrganizations - did receive response: ', response)
response.text()
})
.then( (responseText) => {
console.log('fetchOrganizations - received response, now dispatch: ', responseText);
dispatch( receiveOrganizations(responseText) )
})
.catch( (error) => {
console.warn(error)
})
}
}
When I am calling dispatch( fetchOrganizations() ) like this, I do see the logs until Actions - return promise, but it doesn't seem to actually to fire off the request. I'm not really sure how how I can further debug this or what resources to consult that help me solve this issue.
I'm assuming that Redux is expecting a Promise rather than a function.. Is that true?
If so, I think your return function may not be working.
You have a new line after your return, and it's possible JavaScript is (helpfully) inserting a semicolon there.
See here: Why doesn't a Javascript return statement work when the return value is on a new line?

Resources