304 Error using Netlify Functions in create-react-app - reactjs

※Edited some code after posting the question. New Code below.
I am trying to use Netlify Functions to hide my API key to fetch data. However, it returns a 304 and seems to be not working.
The code below returns an error "SyntaxError: Unexpected token < in JSON at position 0" and the response code is 304.
Can anybody help me with how to improve this?
■functions/fetch-weather.js
const handler = async (event) => {
try {
const { city } = event.queryStringParameters;
const API = process.env.REACT_APP_API_KEY;
const response = await fetch(
`https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${API}`
);
const data = await response.json();
return {
statusCode: 200,
body: JSON.stringify(data),
};
} catch (error) {
console.log({ statusCode: 500, body: error.toString() });
return { statusCode: 500, body: error.toString() };
}
};
module.exports = { handler };
■getCurrentWeather.js
export const getCurrentWeather = async (
city,
setLocation,
setWeather,
setNotification
) => {
const fetchWeather = async () => {
setNotification({ status: 'pending', message: 'Loading...' });
const response = await fetch(
`/.netlify/functions/fetch-weather?city=${city}`
);
if (!response.ok) {
throw new Error('cannot get current weather data');
}
const data = await response.json();
return data;
};
try {
const data = await fetchWeather();
console.log(data);
setLocation(data.name);
const [array] = data.weather;
setWeather(array.main, array.description);
setNotification({ status: 'success', message: 'Success' });
} catch (error) {
console.log(error);
setNotification({ status: 'error', message: 'Cannot find result' });
}
};
■netlify.toml
[build]
functions = "functions"
publish = "src"
■package.json
(ran "npm i netlify-cli --save-dev")
"devDependencies": {
"netlify-cli": "^6.8.12"
}
■console images (after opening page with "netlify dev")
error
network

In your netlify function after making a request you need to use .json to get the json data
const response = await fetch(
`https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${API}`
);
const data = await response.json();

Related

How to use a value in a use state for API URL?

I am getting trouble with calling the API.
So in the first async await function i got the data of list_id.
Then i put the data inside a useState called listID.
After that i am trying to call an API again with async await function with the value of listID inside the URL. But i am getting an error here. Whats probably the issue?
const [listID, setlistID] = useState();
const formik = useFormik({
initialValues: {
name: "",
description: "",
},
onSubmit: (values) => {
if (localStorage.getItem("sessionID")) {
const createList = async () => {
try {
let response = await axios({
method: "post",
url: `https://api.themoviedb.org/3/list?api_key=${API_KEY}&session_id=${localStorage.getItem(
"sessionID"
)}`,
data: {
name: values.name,
description: values.description,
},
});
setlistID(response.data.list_id);
} catch (error) {
console.log(error);
}
};
createList();
}
const getList = async () => {
try {
const response = await axios.get(
`https://api.themoviedb.org/3/list/${listID}?api_key=${API_KEY}`
);
console.log(response);
} catch (error) {
console.error(error);
}
};
getList();
},
});

Getting status code 304 on a get request with axios using react and redux

I have a get request in my Redux Async Thunk. After calling get to my node.js express server it sends a 304 status code, for some reason I can't get my data.
const userTokenAxios = axios.create({
baseURL: '/api/shoes',
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
},
});
userTokenAxios.interceptors.response.use((response) => {
if (response.data.errorMessage === 'jwt expired') {
localStorage.removeItem('token');
localStorage.removeItem('user');
}
});
export const getShoesAsync = createAsyncThunk(
'shoes/getShoesAsync',
async (payload, { rejectWithValue }) => {
try {
const response = await userTokenAxios.get('/');
console.log(response);
return response.data;
} catch (error) {
return rejectWithValue(error.response.data);
}
}
);
Its being called from my homepage:
useEffect(() => {
dispatch(getShoesAsync());
}, [dispatch]);
But I can't get any data as every time the page loads the server sends a 304
my backend controller:
exports.getAllShoes = async (req, res, next) => {
try {
let query = Shoe.find({});
const shoes = await query.populate([
{
path: 'user',
select: 'username',
},
]);
return res.status(200).json(shoes);
} catch (err) {
return next(err);
}
};
app.js in my backend folder:
// ROUTES
app.use('/auth', authRouter);
app.use(
'/api',
expressJwt({ secret: process.env.JWT_SECRET, algorithms: ['HS256'] })
);
app.use('/api/shoes', shoeRouter);
package.json in my client folder
"proxy": "http://localhost:9000"
My network preview:
The problem is your interceptor. Response interceptors must return a value, a rejected promise or throw an error, otherwise the resulting promise will resolve with undefined.
It also seems odd that you're intercepting token errors in the successful response interceptor. I would have assumed you'd use the error interceptor.
userTokenAxios.interceptors.response.use(
res => res, // success response interceptor
err => {
// usually you'd look for a 401 status ¯\_(ツ)_/¯
if (err.response?.data?.errorMessage === "jwt expired") {
localStorage.removeItem('token');
localStorage.removeItem('user');
}
return Promise.reject(err);
}
);
If you are actually responding with a 200 status for token errors, you'd need to handle it in the success interceptor
userTokenAxios.interceptors.response.use(
res => {
if (res.data.errorMessage === "jwt expired") {
localStorage.removeItem('token');
localStorage.removeItem('user');
// Make this look like an Axios error
return Promise.reject({
message: "jwt expired",
response: res,
});
}
return res;
}
);
It also looks like you don't need the trailing forward-slash in your request so simply use
const response = await userTokenAxios.get("");

Unable to fetch Data in Netlify Dev Proxy (React)

I've been having CORS error when deploying my app so I decided to try out Netlify Dev.
I followed all steps of the written tutorials but I keep getting errors without being able to identify whats wrong. I haven't even deployed it yet and right now I am having the 403 error, before this was the 500 internal server error.
Please let me know if you notice any obvious mistake on my part.
Here's the node-fetch code:
const fetch = require("node-fetch");
exports.handler = async function () {
const headers = {
"x-api-key": process.env.REACT_APP_MY_API_KEY,
"content-type": "application/json",
};
try {
const response = await fetch("https://api.crimeometer.com", { headers });
if (!response.ok) {
return { statusCode: response.status, body: response.statusText };
}
const data = await response.json();
return {
statusCode: 200,
body: JSON.stringify(data),
};
} catch (err) {
console.log(err);
return {
statusCode: 500,
body: JSON.stringify({ msg: err.message }),
};
}
};
Here's the frontend of my app (with the relevant code):
const initializeApp = useCallback(() => {
async function fetchData() {
try {
let req = new Request(
`./.netlify/functions/node-fetch?lat=${lat}&lon=${lon}&distance=10km&datetime_ini=${newdateyear}&datetime_end=${newdatenow}&page=1`);
const res = await fetch(req);
const info = await res.json();
setCrimes(info.incidents);
} catch (err) {
console.log(err);
}
}
}, [submit, lat, lon]);
useEffect(() => {
initializeApp();
}, [initializeApp]);
This is the error in my console:
This is where i am trying to fetch data from:
https://api.crimeometer.com/v1/incidents/raw-data?lat=${lat}&lon=${lon}&distance=10km&datetime_ini=${newdateyear}&datetime_end=${newdatenow}&page=1
It requires two headers to be set on frontend, which I have done in the netlify function
The API key is currently being added to the React side, where it sets a header and makes a call to the netlify function. But the API key is actually required at the netlify function to request the third party API.
So you have to move the request header from React to Netlify function with something like:
const headers = {
'x-api-key': API_KEY,
'content-type': 'application/json',
}
const response = await fetch(
"https://api.crimeometer.com/v1/incidents/raw-data",
{ headers }
);

Generic function to request api with Axios

I am trying to build a generic function for my endpoints, using Axios and React. Generic because I have always the same header and I do not want to repeat a lot of code for each of my components.
To do that, I built this function (sorry, a lot of comments that I will remove after of course) :
export const getRequest = ( endpoint ) => axios
.get( env._URL_SERVER_ + endpoint, { headers: getHeaders() } )
.then((res) => {
// Success
console.log(res);
return {error: false, response: res.data};
})
.catch((error) => {
// Error
if (error.response) {
/*
* The request was made and the server responded with a
* status code that falls out of the range of 2xx
*/
console.log(error.response.data);
console.log(error.response.status);
return {error: true, status: error.response.status, data: error.response.data};
} else if (error.request) {
/*
* The request was made but no response was received, `error.request`
* is an instance of XMLHttpRequest in the browser and an instance
* of http.ClientRequest in Node.js
*/
console.log(error.request);
return {error: true, data: error.request };
} else {
// Something happened in setting up the request and triggered an Error
console.log('Error', error.message);
return {error: true, data: error.message}
}
});
Ant then in my components I do that :
getSchools = () => {
this.setState({
loadingSchools: true
}, () => {
getRequest(`/schools?name=${this.state.filterByName}&city=${this.state.filterByCity}&school_type_id=${this.state.filterBySchoolTypeId}&page=${this.state.selectedPage}`)
.then((response) => {
// there is an error
if (!response.error) {
this.setState({
schools: response.response.data,
meta: response.response.meta,
links: response.response.links
})
} else {
this.setState({
error: true,
errorMessage: response.data,
})
}
})
.then(() => {
this.setState({loadingSchools : false});
})
})
}
It works fine. I tested it in several situation (all is OK - 200, not found - 404, no response). But is it a good practice ? I feel that there is a lot of codes in the parent component. Maybe I complicate my life?
Here is how I've done it:
var URL_BACKEND = "http://localhost:5000/";
// Create Function to handle requests from the backend
callToBackend = async (ENDPOINT, METHOD) => {
const options = {
url: `${URL_BACKEND}${ENDPOINT}`,
method: METHOD,
headers: {
Accept: "application/json",
"Content-Type": "application/json;charset=UTF-8",
},
};
const response = await axios(options);
return response.data;
}
// Then you make a call with the exact endpoint and method:
const response = await this.callToBackend('createSetupIntent', 'POST');
console.log(JSON.stringify(response));
create one common file for base URL let's say api.js
// api.js file code
export const apiUrl = axios.create({
baseURL: 'http://localhost:5000',
});
Register file
// register.js file code
import { apiUrl } from './api';
try {
const resp = await apiUrl.post('/api/register', {
username,
email,
password,
});
const { data, status } = resp;
if (Object.keys(data).length && status === 200) {
// received api data successfully
console.log('API response', data);
}
} catch (err) {
console.log(err);
}
// For auth request
try {
const token = localstorage.getItem('token');
const res = await apiUrl.post(
'/authroute',
{
name: fullName,
originCountry: country,
career: careerStatus,
},
{
headers: { Authorization: `Bearer ${token}` },
}
);
const { data, status } = strapiRes;
if (Object.keys(data).length && status === 200) {
return res.status(status).json(data);
}
} catch (error) {
throw new Error(error);
}
// same for all request
apiUrl.get(endpoint);
apiUrl.post(endpoint, body);
apiUrl.put(endpoint, body);
apiUrl.delete(endpoint, body);

Fetch Post Request not returning payload but return status code (200)

So I am trying to create a user using redux-form. I have an express post route on the backend. NOTE: using redux-thunk for middleware, whatwg-fetch with webpack and babel-polyfill.
routes.post('/signup', async (req, res) => {
try {
const createdUser = await userController.createUser(req.body);
const JSONCreatedUser = JSON.stringify(createdUser);
res.json({
confirmation: 'success',
result: createdUser,
});
return JSONCreatedUser;
} catch (error) {
res.statusMessage = error.toString();
res.status(409).json({
confirmation: 'failure',
error: error.toString(),
});
}
});
So the problem I am having is that when I use postman. I will get the entire user object back.
But when I submit it using form I only get
Apimanager.js
export const signUserUpApi = async (url, params) => {
try {
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(params),
});
const { status, statusText } = response;
if (status === 409) {
throw new Error(statusText);
}
return response;
} catch (error) {
throw new Error(error.toString());
}
};
action.js
import constants from '../constants';
import { signUserUpApi } from '../utils/APIManager';
const signUserUpUrl = process.env.SIGN_USER_UP_URL || 'http://localhost:3000/user/signup';
export const signUserUp = (user) => {
return async (dispatch) => {
try {
const createdUser = await signUserUpApi(signUserUpUrl, user);
dispatch({
type: constants.SIGN_USER_UP,
user: createdUser,
});
return createdUser;
} catch (error) {
throw new Error(error);
}
};
};
export const signUserIn = (user) => {
return {
type: constants.SIGN_USER_UP,
user,
};
};
What I am trying to do is to get the User Object I created when I submit the form and redirect back to the page.
This is what I get back and it did create the user.
First thing, I need is why am I getting the https status code back and not the user object?
Second thing, what are the ways to redirect to the home page when a user successfully signed up logged in.

Resources