Problems with react to translate words using google translate api - reactjs

I am trying to create a translation page where you type the word and it should translate to the language you chose in the dropdown. Using React and axios and the API from Rapid API.
I keep getting error like 401, 429 I know what the errors are but don't know how to fix it. Could it be from the website [Rapid API][1] that gives me a bad API?
import axios from "axios"
// de-structure language and text props
const Convert = ({ language, text }) => {
const [results, setResults] = useState("")
useEffect(() => {
const translate = async () => {
const translation = await axios.post(
"https://google-translate1.p.rapidapi.com/language/translate/v2",
{},
{
params: {
q: text,
target: language.value,
key: "cd4662825bmshfb23e36cc668d7fp111f42jsn736f6cc3a9aa",
},
}
)
setResults(translation.data.data.translations[0].translatedText)
}
translate()
}, [language, text])
console.log(results);
return (
<div>
<p>{results}</p>
</div>
)
}
export default Convert ```
[1]: https://rapidapi.com/googlecloud/api/google-translate1?endpoint=apiendpoint_a5764907-04b6-4d61-869b-79dc5325c739

I think there are 2 different APIs here... You are talking about the RapidAPI API but in the code you are using the MyMemory API.
So, regarding to your code and the MyMemory API specification, I see a couple errors in your code:
You are calling the /status endpoint, which checks the status of a TM import. I think this is not the endpoint you want to call. Instead, you have to make the request to the /get endpoint: https://api.mymemory.translated.net/get.
Also the request should be a get, not a post (just replace axios.post with axios.get).
The "q" and "key" params are correct, BUT in the documentation it says that you have to send a "langpair" param, not a "target".
With those changes the code should go fine. I've tried it and it works.

Try the next code:
import React, { useState, useEffect } from "react"
import axios from "axios"
import qs from "qs"
// de-structure language and text props
const Convert = ({ language, text }) => {
const [results, setResults] = useState("")
useEffect(() => {
const translate = async () => {
const translation = await axios.post(
"https://google-translate1.p.rapidapi.com/language/translate/v2",
qs.stringify({
q: text,
target: language.value
}),
{
headers: {
'x-rapidapi-key': 'cd4662825bmshfb23e36cc668d7fp111f42jsn736f6cc3a9aa',
'x-rapidapi-host': 'google-translate1.p.rapidapi.com'
}
}
)
setResults(translation.data.data.translations[0].translatedText)
}
translate()
}, [])
console.log(results);
return (
<div>
<p>{results}</p>
</div>
)
}
export default Convert
If you get a 403 Forbidden error then it's possibly because you're not subscribed to the API. To fix this, just go to https://rapidapi.com/googlecloud/api/google-translate1 and click on the "Subscribe to Test" button. Then select the free plan and you will be ready to go.

Here are some points that can definitely solve this issue.
If you're using RapidAPI then x-rapidapi-key is your API key. So instead of mentioning key in params, you can pass x-rapidapi-key inside the headers.
The possible reason for the 403 code is that you're not subscribed to that particular API. Make sure to double-check that.
429 status code indicates so many request in the give amount of time. I have checked, the rate limit is 5 request per second for Google Translate API.
You can use the code snippet that RapidAPI provides in order to avoid any kind of unwanted errors.

Related

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.

Invalid Hook Call when calling a custom hook

I've been trying to solve a problem for 4 days and I've searched and searched a lot! I'm not sure if I'm just searching for the wrong thing or seeing it and am just completely oblivious to it. My problem is that when I call the hook from the main function, it works, but when I call it via an onSubmit function, it fails for invalid hook call. I understand the concept of why the hook would be invalid, but am just completely unsure how to resolve it. I reformatted my hook so that I could initialize it earlier in my code and then call it via the onSubmit, but the problem is that the state token only gets updated on initialization and not whenever it's changed. Thus leading to some API calls with a bad token. Any Help Anyone can offer will be greatly appreciated!
The Setup:
NextJS, React-Form, Redux via Next-Redux-Wrapper, SWR
When ReactForm validates the form, I'd like for it to submit it's data to a custom hook. However, that custom hook fails with the Invalid Hook Call. It does it as soon as I defined a variable for useState.
-- Form Code ---
const { register, errors, handleSubmit, setValue, reset, control } = useForm()
<form onSubmit={ handleSubmit(onSubmit) }>
-- onSubmit Code ---
const onSubmit = (data) => {
const newData = useApiPost(`users/update/${ id }`, submitData)
}
-- Custom Hook --
function useApiPut(resource, params){
const [ data, setData ] = useState(null)
const [ error, setError ] = useState(null)
const { url, data : inData } = rest(resource, params)
//Post data
const { data : resData, error : resError, mutate } = useSWR(
state.user.token ? url : null,
url => axios.request({
url,
method : 'post',
data : inData,
headers : { Authorization : `Bearer ${ state.user.token }` }
})
.then(({ data }) => data),
{ revalidateOnFocus : false }
)
useEffect(() => {
if(resData) {
setData(resData)
}
if(resError) {
setError(resError)
}
}, [ resData, resError ])
return { data, error, mutate }
}
So the answer to this ended up being a few different things.
First, accessing my store value via store.getState() resolved one issue with hooks.
Secondly, moving away from SWR. It is an AWESOME wrapper and capable of a TON, no doubt. I just kept struggling with it and finally gave up. I moved to using Axios Interceptors and it has been amazing. Axios doesn't cache (out of the box) like SWR, but I was utilizing the caching for tokens, so I wasn't really using it to it's full potential. Please note, I'm in no way bashing SWR, it's a really great and extremely powerful library.
Lastly, wrapping the entire set of hooks into one function allowed me to initialize the function at the root of my page and then access the hooks I needed to use later.
So instead of just calling useApiPost() now my hook looks like this:
const useApi = async() => {
const post = async() => {
//Do work here
}
return { post }
}
export default useApi
Then it's called like this inside the main function:
const { post } = useApi()
And it's called like this in the onSubmit Function:
const options = await post(resource, params)

react-query: useQuery returns undefined and component does not rerender

I'm playing around with reactQuery in a little demo app you can see in this repo. The app calls this mock API.
I'm stuck on a an issue where I'm using the useQuery hook to call this function in a product API file:
export const getAllProducts = async (): Promise<Product[]> => {
const productEndPoint = 'http://localhost:5000/api/product';
const { data } = await axios.get(productEndPoint);
return data as Array<Product>;
};
In my ProductTable component I then call this function using:
const { data } = useQuery('products', getAllProducts);
I'm finding the call to the API does get made, and the data is returned. but the table in the grid is always empty.
If I debug I'm seeing the data object returned by useQuery is undefined.
The web request does successfully complete and I can see the data being returned in the network tab under requests in the browser.
I'm suspecting its the way the getAllProducts is structured perhaps or an async await issue but can't quite figure it out.
Can anyone suggest where IO may be going wrong please?
Simply use like this
At first data is undefined so mapping undefined data gives you a error so we have to use isLoading and if isLoading is true we wont render or map data till then and after isLoading becomes false then we can render or return data.
export const getAllProducts = async (): Promise<Product[]> => {
const productEndPoint = 'http://localhost:5000/api/product';
const res= await axios.get(productEndPoint);
return res.data as Array<Product>;
};
const { data:products , isLoading } = useQuery('products', getAllProducts);
if(isLoading){
return <FallBackView />
}
return (){
products.map(item => item)
}
I have managed to get this working. For the benefits of others ill share my learnings:
I made a few small changes starting with my api function. Changing the function to the following:
export const getAllProducts = async (): Promise<Product[]> => {
const response = await axios.get(`api/product`, {
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
});
return response.data as Product[];
};
I do not de-construct the response of the axios call but rather take the data object from it and return is as an Product[]
Then second thing I then changed was in my ProductTable component. Here I told useQuery which type of response to expect by changing the call to :
const { data } = useQuery<Product[], Error>('products', getAllProducts);
Lastly, a rookie mistake on my part: because I was using a mock api in a docker container running on localhost and calling it using http://localhost:5000/api/product I was getting the all to well known network error:
localhost has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present...
So to get around that for the purpose of this exercise I just added a property to the packages.json file: "proxy":"http://localhost:5000",
This has now successfully allowed fetching of the data as I would expect it.

why i'm not able to fetch data using axios call?

const [category, setCategory] = useState("general")
const news = await axios.get(`https://newsapi.org/v2/top-headlines?country=in&apiKey=64968be4903a4a979fe05c58a3355a73
&category=${category}`);
**As I am fetching API but its not fetching as is shows an empty array can anyone tell me where I am I going wrong **
You can not use the response of an async function directly in your React functional component. You have to use a state which holds your news. If you call setNews React automatically rerenders your component with the new news data.
export function News() {
const [category, setCategory] = useState("general");
const [news, setNews] = useState([]);
// fetch news everytime the category changes
useEffect(() => {
async function fetchNews() {
try {
const url = `https://newsapi.org/v2/top-headlines?country=in&apiKey=64968be4903a4a979fe05c58a3355a73&category=${category}`;
const response = await axios.get(url);
console.log(response);
setNews(response.data.articles);
} catch (errorWhileFetchingNews) {
console.log("error while fetching news", errorWhileFetchingNews);
}
}
fetchNews();
}, [category]);
// render the news
return (
<div>
{
news.map((article, i) => {
return <div key={i}>{article.title}</div>;
})
}
</div>
);
}
EDIT:
CAUTION: The CORS issues seem to appear only in my codesandbox example. If the example above runs on localhost:3000 in a normal React app (create-react-app) it works like it should. So you might ignore the following description.
Unfortunately the server newsapi.org doesn't send CORS headers. So you are not allowed to call this service directly via AJAX requests (axios, fetch, ...). You either find a way to enable CORS on this site (because you have an API key you may be able to administrate something?) or you find an other service that supports CORS or you have to send your request through a proxy. The proxy/backend then have to run on the same domain (host + port) like your frontend or the proxy must handle all the CORS header stuff. There are also questions on stackoverflow that have the same issue with newsapi.org but I am afraid that there is no easy solution/workaround for this.
I have setup a working example with jsonplaceholder.typicode.com (supports CORS) instead of newsapi.org.
See here: https://codesandbox.io/s/white-wildflower-su5vd?file=/src/News.js
Just in case the example is not reachable anymore, here is the code:
import { useState, useEffect } from "react";
import axios from "axios";
export function News(props) {
const [category, setCategory] = useState("general");
const [news, setNews] = useState([]);
// fetch news everytime the category changes
useEffect(() => {
async function fetchNews() {
try {
const url = "https://jsonplaceholder.typicode.com/comments";
const response = await axios.get(url);
console.log(response);
setNews(response.data);
} catch (errorWhileFetchingNews) {
console.log("error while fetching news", errorWhileFetchingNews);
}
}
fetchNews();
}, [category]);
// render the news
return (
<div>
{
news.map((article) => {
return <div key={article.id}>{article.name}</div>;
})
}
</div>
);
}

Why is fetching data in next.js with hardcoded api-key working but not with environment variable?

I followed the documentation of Next.js, so I created a file called .env.local and stored my API key inside.
When console.logging that key it gets shown in the server-console and not in the browser console. So far I understand this.
Problem: I want to fetch some data from the given URL. How can I get this done, without giving my API_KEY to the browser?
I think that topic is quite confusing for beginners (as me) and I an many other (so I think) would be overjoyed if anyone could get the confusion out of that.
Here is my code: (If I hardcode my API_KEY inside the URL it works fine)
import Haversine from '../components/Haversine'
import LangLat from '../components/LangLat'
import axios from 'axios'
import { useEffect } from 'react'
const key = process.env.API_KEY
const index = () => {
console.log(key)
const getLangLat = async () => {
try {
const response = await axios.get(
`https://geocode.search.hereapi.com/v1/geocode?q=wimpfener str 40 backnang&apiKey=${key}`
)
console.log(response.data)
} catch (err) {
console.error(err.message)
}
}
useEffect(() => {
getLangLat()
})
return (
<div>
<Haversine />
<LangLat />
</div>
)
}
export default index
You need to add NEXT_PUBLIC_ to the beginning of your environmental variable so you have access to it on the client side.
So inside of your .env.local change
API_KEY to NEXT_PUBLIC_API_KEY and do the same inside of your code.
https://nextjs.org/docs/basic-features/environment-variables#loading-environment-variables

Resources