I am trying to set localstorage in react, but get undefined in value.
Even if I am using JSON.stringify, it doesn't work.
I think, the value is not reaching there.
My code looks like this:
import fetch from "isomorphic-fetch";
import { API } from "../config";
import cookie from "js-cookie";
export const signup = (user) => {
return fetch(`${API}/signup`, {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify(user),
})
.then((response) => {
return response.json();
})
.catch((err) => console.log(err));
};
// login
export const login = (user) => {
return fetch(`${API}/login`, {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify(user),
})
.then((response) => {
console.log(user)
return response.json();
})
.catch((err) => console.log(err));
};
// logout
export const logout = (next) => {
removeCookie("token");
removeLocalStorage("user");
next();
return fetch(`$${API}/logout`, {
method: "GET",
})
.then((response) => {
console.log("Logged Out");
})
.catch((err) => console.log(err));
};
// set cookie
export const setCookie = (key, value) => {
if (process.browser) {
cookie.set(key, value, {
expires: 1,
});
}
};
// remove cookie
export const removeCookie = (key) => {
if (process.browser) {
cookie.remove(key, {
expires: 1,
});
}
};
// get cookie
export const getCookie = (key) => {
if (process.browser) {
return cookie.get(key);
}
};
// set localstorage
export const setLocalStorage = (key, value) => {
if (process.browser) {
localStorage.setItem(key, JSON.stringify(value));
}
};
// remove localstorage
export const removeLocalStorage = (key) => {
if (process.browser) {
localStorage.removeItem(key);
}
};
// authenticate user by passing data to cookie and localstorage
export const authenticate = (data, next) => {
setCookie("token", data.token);
setLocalStorage("user", data.user);
next();
};
export const isAuth = () => {
if (process.browser) {
const cookieChecked = getCookie("token");
if (cookieChecked) {
if (localStorage.getItem("user")) {
return JSON.parse(localStorage.getItem("user"));
} else {
return false;
}
}
}
};
Related
I've been working on this for hours, and I have no idea where did it go wrong.
I want to have an axios interceptor for my ReactJs
this is my interceptor axiosHandler.js
import axios from "axios";
const axiosHandler = axios.create({
baseURL: process.env.REACT_APP_BASE_URL,
headers: {
Accept: "application/json",
},
});
axiosHandler.interceptors.request.use(
(config) => {
const token = localStorage.getItem("token");
if (token) {
config.headers["Authorization"] = "Bearer " + token;
}
return config;
},
(error) => {
Promise.reject(error);
}
);
//axiosHandler.interceptors.response
export default axiosHandler;
And here is how I use the handler in my other component
import axiosHandler from "../services/axiosHandler";
const getData = async () => {
await axiosHandler
.get(`/path`)
.then((response) => {
//do something
})
};
And I get an error of below
services_axiosHandler__WEBPACK_IMPORTED_MODULE_0_.get is not a function
I've read many other solutions, but I can't find the difference as how it leads to the error of mine.
Where do I put it wrong?
Thank you
inside axios.index
import axios from "axios";
import { API_URL } from "../config/config";
const axiosHttp = axios.create({
baseURL: `${API_URL}`,
});
axiosHttp.interceptors.request.use(
(config) => {
const token = "Your Token here"
return {
...config,
headers: {
...(token !== null && { Authorization: `${token}` }),
...config.headers,
},
};
},
(error) => {
return Promise.reject(error);
}
);
axiosHttp.interceptors.response.use(
(response) => {
//const url = response.config.url;
//setLocalStorageToken(token);
return response;
},
(error) => {
if (error.response.status === 401) {
//(`unauthorized :)`);
//localStorage.removeItem("persist:root");
//removeLocalStorageToken
//window.location.href = "/login";
}
return Promise.reject(error);
}
);
export default axiosHttp;
Then inside your API function use it like below
import axiosHttp from "./utils/axios";
const getData = async ()=>{
try{
const response = await axiosHttp.get('/path')
return resposne;
}
catch(error){
//handle error here...
}
}
Last but not least, you shouldn't use await when using callback (then/catch)
Simple page given
import { fetchUtils, Admin, Resource, ListGuesser } from 'react-admin';
import * as React from "react";
import apiDataProvider from './apiDataProvider';
import apiAuthProvider from './apiAuthProvider';
const dataProvider = apiDataProvider('https://example.com/api/v1');
const App = () => (
<Admin dataProvider={dataProvider} authProvider={apiAuthProvider}>
<Resource name="campaign" list={ListGuesser} />
</Admin>
);
export default App;
apiDataProvider used for url customization, probably there's better solution
const endPoint = 'https://example.com/api/v1'
const apiAuthProvider = {
login: ({ username, password }) => {
console.log('login');
const request = new Request(endPoint+'/sign-in/', {
method: 'POST',
body: JSON.stringify({ username: username, password: password }),
headers: new Headers({ 'Content-Type': 'application/json' }),
});
return fetch(request)
.then(response => {
if (response.status < 200 || response.status >= 300) {
throw new Error(response.statusText);
}
return response.json();
})
.then(auth => {
localStorage.setItem('auth', JSON.stringify(auth));
})
.catch(() => {
throw new Error('Network error')
});
},
logout: () => {
console.log('logout');
localStorage.removeItem('username');
const request = new Request(endPoint+'/sign-out/', {
method: 'POST',
body: JSON.stringify({ }),
headers: new Headers({ 'Content-Type': 'application/json' }),
});
return fetch(request)
.then(response => {
if (response.status < 200 || response.status >= 300) {
throw new Error(response.statusText);
}
return response.json();
})
.then(auth => {
localStorage.setItem('auth', JSON.stringify(auth));
})
.catch(() => {
throw new Error('Network error')
});
},
checkAuth: () => {
console.log('checkAuth', localStorage.getItem('username'));
return localStorage.getItem('username') ? Promise.resolve() : Promise.reject();
},
checkError: (error) => {
console.log('checkError');
const status = error.status;
if (status === 401 || status === 403) {
localStorage.removeItem('username');
return Promise.reject();
}
// other error code (404, 500, etc): no need to log out
return Promise.resolve();
},
getIdentity: () => {
try {
const { id, fullName, avatar } = JSON.parse(localStorage.getItem('auth'));
return Promise.resolve({ id, fullName, avatar });
} catch (error) {
return Promise.reject(error);
}
},
getPermissions: () => Promise.resolve(''),
};
export default apiAuthProvider;
On load "/" it calls logout twice, queries for campaign list (custom url), gets 401 and calls logout url again.
On the page I can see "Please login to continue" message, but no login window. Login form is available on /login. Why RA doesn't redirect to login form?
When I navigate using Link (react router-dom) I don't have this problem, but if I refresh the browser I get a 403 error in console saying unauthorised and then I get the data in the next request with a 200 response. Why is this making what looks like 2 requests when refreshing the browser?
import { AuthContext } from "../../shared/context/auth-context";
const ContactEntries = () => {
const auth = useContext(AuthContext);
useEffect(() => {
const source = Axios.CancelToken.source();
setIsLoading(true);
const getContactEnquiries = async () => {
try {
const response = await Axios.get(
`${process.env.REACT_APP_BACKEND_URL}/v1/contact`,
{
cancelToken: source.token,
headers: { Authorization: "Bearer " + auth.token },
}
);
if (response.status === 200) {
setIsLoading(false);
setEnquiries(response.data.enquiries);
}
} catch (err) {
setIsLoading(false);
console.log(err.response);
}
};
getContactEnquiries();
return () => {
source.cancel();
};
}, [!!auth.token]);
}
Here is my authContext:
import { createContext } from "react";
export const AuthContext = createContext({
isLoggedIn: false,
userId: null,
token: null,
email: null,
firstName: null,
login: () => {},
logout: () => {},
});
This is because your useEffect is running twice on refresh. On first render it is not getting auth.token and may be it null. And on second render it is making call with 200 status code.
You have to check auth token it coming successfully.
You can check it this way
useEffect(() => {
const source = Axios.CancelToken.source();
setIsLoading(true);
const getContactEnquiries = async () => {
try {
const response = await Axios.get(
`${process.env.REACT_APP_BACKEND_URL}/v1/contact`,
{
cancelToken: source.token,
headers: { Authorization: "Bearer " + auth.token },
}
);
if (response.status === 200) {
setIsLoading(false);
setEnquiries(response.data.enquiries);
}
} catch (err) {
setIsLoading(false);
console.log(err.response);
}
};
if(auth.token) getContactEnquiries();
return () => {
source.cancel();
};
}, [!!auth.token]);
In our project we are using the MERN stack
I want to create a generic function whose input is the path to any api endpoint in our server and the JSON package to POST to the server. I want it to return the JSON sent back from the server.
That way when we are developing our mobile app and web app, we can simply use this function for all of our api endpoint POSTs.
I'm very new to using React/React-Native so I'm sure that I'm not understanding some sort of key concept.
Here is what I have so far:
import React from 'react';
// returns whatever the respective apiEndpoint is suppose to return
function postToAPI(route, package2send)
{
async() =>
{
try
{
const payload = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: package2send
}
const res = await fetch(route, payload);
console.log(res);
const data = await response.json();
console.log(data);
return data;
}
catch(error)
{
console.error(error);
}
}
}
export default postToAPI;
Whenever I call this function from my Login.js after I
import { postToAPI } from './postToAPI'
I get this error: 'TypeError: Object(...) is not a function'
I'm sure there are multiple things wrong with this code, so if someone could steer me in the right direction, it would be greatly appreciated.
If you export the function as default, you must import without bracket like that.
import postToAPI from './postToAPI';
If you would like to write a generic API call class, I advise you this class which I wrote before.
import { BASE_URL } from "../config";
import { Actions } from "react-native-router-flux";
import { deleteUserInfo } from "./SessionHelper";
const API_URL = BASE_URL;
class ApiHelper {
private accessToken?: string;
constructor() {
this.accessToken = undefined;
}
setAccessToken = (accessToken: string) => {
this.accessToken = accessToken;
};
getAccessToken = () => {
return this.accessToken;
};
getRequest = async (endpoint: string) => {
try {
const response = await fetch(`${API_URL}${endpoint}`, {
method: "GET",
headers: {
"x-access-token": `${this.accessToken}`
}
});
const responseJson = await response.json();
return responseJson;
} catch (error) {
console.error(error);
}
};
postRequest = async (endpoint: string, body: any) => {
try {
const response = await fetch(`${API_URL}${endpoint}`, {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
"x-access-token": `${this.accessToken}`
},
body: JSON.stringify(body)
});
const responseJson = await response.json();
const finalResponse = { data: responseJson, status: response.status };
if (response.status === 401) {
deleteUserInfo();
this.accessToken = undefined;
Actions.auth();
}
return finalResponse;
} catch (error) {
console.error(error);
return error;
}
};
patchRequest = async (endpoint: string, body: any) => {
try {
const response = await fetch(`${API_URL}/${endpoint}`, {
method: "PATCH",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
"x-access-token": `${this.accessToken}`
},
body: JSON.stringify(body)
});
const responseJson = await response.json();
const finalResponse = { data: responseJson, status: response.status };
if (response.status === 401) {
deleteUserInfo();
this.accessToken = undefined;
Actions.auth();
}
return finalResponse;
} catch (error) {
console.error(error);
}
};
deleteRequest = async (endpoint: string, body: any) => {
try {
const response = await fetch(`${API_URL}/${endpoint}`, {
method: "DELETE",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
"x-access-token": `${this.accessToken}`
},
body: JSON.stringify(body)
});
const responseJson = await response.json();
const finalResponse = { data: responseJson, status: response.status };
if (response.status === 401) {
deleteUserInfo();
this.accessToken = undefined;
Actions.auth();
}
return finalResponse;
} catch (error) {
console.error(error);
}
};
}
export const APIHelper = new ApiHelper();
I am trying to create a playlist on localhost and then have the list I created to be saved to Spotify. Can someone help why Save to Spotify button might not be working? Everything else seems fine, I have doubts about the fetching part I used but can't figure out what the issue might be.
Screenshot of the page:
And there is the Spotify.js code:
import { SearchBar } from '../components/SearchBar/SearchBar';
const clientId = 'I've put my client id';
const redirectUri = 'http://localhost:3000/callback/';
let accessToken;
const Spotify = {
getAccessToken() {
if (accessToken) {
return accessToken;
}
//check for access token match
const accessTokenMatch = window.location.href.match(/access_token=([^&]*)/);
const expiresInMatch = window.location.href.match(/expires_in=([^&]*)/);
if (accessTokenMatch && expiresInMatch) {
accessToken = accessTokenMatch[1];
let expiresIn = Number(expiresInMatch[1]);
//This clears the parameters, allowing to grab new access token then it expires
window.setTimeout(() => (accessToken = ''), expiresIn * 1000);
window.history.pushState('Access Token', null, '/');
return accessToken;
} else {
const accessUrl = `https://accounts.spotify.com/authorize?client_id=${clientId}&response_type=token&scope=playlist-modify-public&redirect_uri=${redirectUri}`;
window.location = accessUrl;
}
},
search(term) {
const accessToken = Spotify.getAccessToken();
return fetch(`https://api.spotify.com/v1/search?type=track&q=${term}`, {
headers: { Authorization: `Bearer ${accessToken}` },
})
.then((response) => {
return response.json();
})
.then((jsonResponse) => {
if (!jsonResponse.tracks) {
return [];
}
return jsonResponse.tracks.items.map((track) => ({
id: track.id,
name: track.name,
artists: track.artists[0].name,
album: track.album.name,
uri: track.uri,
}));
});
},
savePlaylist(name, trackUris) {
if (!name || !trackUris.length) {
return;
}
const accessToken = Spotify.getAccessToken();
const headers = { Authorization: `Bearer ${accessToken}` };
let userId;
return fetch(`https://api.spotify.com/v1/me`, { headers: headers })
.then((response) => response.json())
.then((jsonResponse) => (userId = jsonResponse.id))
.then((userId) => {
return fetch(`/v1/users/${userId}/playlists`, {
headers: headers,
method: 'POST',
body: JSON.stringify({ name: name }),
})
.then((response) => response.json())
.then((jsonResponse) => {
const playlistId = jsonResponse.id;
return fetch(`/v1/users/${userId}/playlists/${playlistId}/tracks`, {
headers: headers,
method: 'POST',
body: JSON.stringify({ uris: trackUris }),
});
});
});
},
};
export default Spotify;
Here is the screenshot of Element > Console:
I had an fetch error, updated as below and working now.
let accessToken;
const Spotify = {
getAccessToken() {
if (accessToken) {
return accessToken;
}
//check for access token match
const accessTokenMatch = window.location.href.match(/access_token=([^&]*)/);
const expiresInMatch = window.location.href.match(/expires_in=([^&]*)/);
if (accessTokenMatch && expiresInMatch) {
accessToken = accessTokenMatch[1];
let expiresIn = Number(expiresInMatch[1]);
//This clears the parameters, allowing to grab new access token then it expires
window.setTimeout(() => (accessToken = ''), expiresIn * 1000);
window.history.pushState('Access Token', null, '/');
return accessToken;
} else {
const accessUrl = `https://accounts.spotify.com/authorize?client_id=${clientId}&response_type=token&scope=playlist-modify-public&redirect_uri=${redirectUri}`;
window.location = accessUrl;
}
},
search(term) {
const accessToken = Spotify.getAccessToken();
return fetch(`https://api.spotify.com/v1/search?type=track&q=${term}`, {
headers: { Authorization: `Bearer ${accessToken}` },
})
.then((response) => {
return response.json();
})
.then((jsonResponse) => {
if (!jsonResponse.tracks) {
return [];
}
return jsonResponse.tracks.items.map((track) => ({
id: track.id,
name: track.name,
artists: track.artists[0].name,
album: track.album.name,
uri: track.uri,
}));
});
},
savePlaylist(name, trackUris) {
if (!name || !trackUris.length) {
return;
}
const accessToken = Spotify.getAccessToken();
const headers = { Authorization: `Bearer ${accessToken}` };
let userID;
return fetch('https://api.spotify.com/v1/me', { headers: headers })
.then((response) => response.json())
.then((jsonResponse) => {
userID = jsonResponse.id;
return fetch(`https://api.spotify.com/v1/users/${userID}/playlists`, {
method: 'POST',
headers: headers,
body: JSON.stringify({ name: name }),
})
.then((response) => response.json())
.then((jsonResponse) => {
const playlistID = jsonResponse.id;
return fetch(
`https://api.spotify.com/v1/users/${userID}/playlists/${playlistID}/tracks`,
{
method: 'POST',
headers: headers,
body: JSON.stringify({ uris: trackUris }),
}
);
});
});
}, // end of savePlaylist method
}; // end of Spotify object
export default Spotify;