I have the following useEffect call back function :-
import { initDB, useIndexedDB } from "react-indexed-db";
initDB(DBConfig);
const db = useIndexedDB("reads");
useEffect(() => {
db.getByIndex("hash", props.match.params.id).then((data) => {
setToken(data.token);
});
handleTextColorSelection(backgroundColor);
axios
.post(`${process.env.REACT_APP_API_URL}khatma/read`, {
khatma: props.match.params.id,
part: props.match.params.part,
section: props.match.params.section,
token: token,
})
.then((res) => {
if (res.data.token) {
db.add({
hash: props.match.params.id,
token: res.data.token,
}).then(
(event) => {},
(error) => {
console.log(error);
}
);
}
})
In axios post body i am sending token , if "token" state receive a value stored before in browser indexed db, if there is not object store data found , then a post token will be sent as null.
The problem here, that i noticed that before the db.getByIndex("hash", ... command get a result, an axios request run, and sending a token as null, even-though later on token state will get a value.
How can i run the db.getByIndex("hash", then if it finish , run axios post request ?
You could use .then
const axiosRequest = () => { /* your axios logic */ };
db.getByIndex(...).then(axiosRequest).catch(axiosRequest)
Anything you do inside the then and catch callbacks will be run after the getByIndex call
Related
In the code below, I will call LoginAPI for authorization and writes token as a state(Login.e2e.ts ).By the way using axios interceptors.request in my axios.ts file.
My question is;
If I use below code logic, when I send request with customAxios in my project,everytime await LoginAPI.API.Signin.run() will run for every API request. Soon,I can have 100 API call. I don t want run every time await LoginAPI.API.Signin.run(),because I can take 429 error.
The new logic should be like this;
I want to take a token first and then use it until it expires. If the token expired then send a new request and get a new token. How can do this using JavaScript or TypeScript?
This is my Login.e2e.ts file
import api from "api/core"
import { expect } from "#playwright/test";
export const LoginAPI = {
States: {
token: {} as string
},
API: {
Signin: {
notes: "user login",
run: async () => {
let res: any = await api.test.LoginPost(process.env.NAME, process.env.PASS)
LoginAPI.States.token = res.data.token
expect(res.status).toBe(200)
},
},
},
};
This is my axios.ts file
import axios from "axios";
import { LoginAPI } from "../playwright/tests/login/login.api";
const customAxios = axios.create({
baseURL: process.env.ENV === '1' ? "https://test1" : process.env.ENV === '2' ? "https://test2" : "https://test3",
});
customAxios.interceptors.request.use(
async (config) => {
await LoginAPI.API.Signin.run()
if (config.headers) {
config.headers['Authorization'] = `Bearer ${LoginAPI.States.token}`;
return config;
}
return config;
},
(error) => {
Promise.reject(error);
}
);
export default customAxios
take a token first and then use it until it expires. If the token expired then send a new request and get a new token.The above code should be changed the this logic
I would suggest you to log in once and get cookies from the browser.context() and save them as JSON file then use this cookie state/session for the rest of the test. That way you won't have to log in every time for new tests or test suites.
More information using storageState(options) here in official docs.
Example of using storageState(options) in your global setup and teardown here in official docs.
I am using Laravel API as a backend for my react-native application. I want to get all the logged in user's data from the users table when he logs in.
I've tried several things but nothing has worked so far.
Here is my code:
Laravel api.php:
Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
return $request->user();
});// i also tried this code.
Route::get('/user', function (Request $request) {
return $request->user();
});
ProfileScreen.js
const [user, setUser] = useState({});
const getUser = async () => {
try {
const token = await AsyncStorage.getItem('auth_token');
axios.get("/api/user").then(res => {
console.log(res.data)//this is logging nothing.
}).catch(e => console.log(e));
} catch (e) {
console.log('error' + e);
}
};
useEffect(() => {
getUser();
});
auth()->user() is a global helper, Auth::user() is a support facade,
and $request->user() uses http.
You can use any of them. For a quick test, try
Route::get('/test', function() {
return auth()->user();
})->middleware('auth:sanctum');
Be sure to send your token in a header like so:
Authorization: Bearer UserTokenHere
I'm using NextJS 12.0.10 with next-redux-wrapper 7.0.5
And Axios custom instance to hold user JWT token saved in local storage and inject it with every request also to interceptors incoming error's in each response
The problem with this is that I simply cannot use the Axios instance inside the Next data fetching methods
Because there is no way to bring user JWT Token from local storage when invoking the request inside the server
Also, I cannot track the request in case of failure and send the refresh token quickly
I tried to use cookies but getStaticProps don't provide the req or resp obj
Should I use getServerSideProps always
axios.js
const axiosInstance = axios.create({
baseURL: baseURL,
timeout: 20000,
headers: {
common: {
Authorization: !isServer()
? localStorage.getItem("access_token")
? "JWT " + localStorage.getItem("access_token")
: null
: null,
accept: "application/json",
},
},
});
login-slice.js
export const getCurrentUser = createAsyncThunk(
"auth/getCurrentUser",
async (_, thunkApi) => {
try {
const response = await axiosInstance.get("api/auth/user/");
await thunkApi.dispatch(setCurrentUser(response.data));
return response.data;
} catch (error) {
if (error.response.data) {
return thunkApi.rejectWithValue(error.response.data);
}
toast.error(error.message);
return thunkApi.rejectWithValue(error.message);
}
}
);
Page.jsx
export const getStaticProps = wrapper.getStaticProps((store) => async (ctx) => {
try {
await store.dispatch(getCurrentUser());
} catch (e) {
console.log("here", e);
}
return {
props: {},
};
});
Server side rendered technology is a one-way street if you follow the standard practise. You won't get any local details - being it cookies, local store or local states back to the server.
I would let the server build the DOM as much as it makes sense (ie with empty user data) and let the client fetch the data via useEffect.
I am sending axios get request whose end-point sends the user associated with the token stored in localStorage and then the redux state is updated with the user. When I don't have a token the end-point return a res with status 401 with message "Unauthorized" and then I handle it in the catch statement and set the "error" redux state. But even after doing this the error is displayed on the console like this:
Failed to load resource: the server responded with a status of 401 (Unauthorized) /users/auth:1
This is the function which makes api call and authorizes the user:
export function loadUser(){
return function (dispatch,getState){
dispatch(userLoading());
const token = getState().auth.token;
const config = {
headers:{
'Content-Type':'application/json'
}
}
if(token) config.headers['auth-token']=token;
axios.get('http://localhost:80/users/auth',config)
.then(user => {
dispatch(clearError())
dispatch(userLoaded(user.data))
})
.catch(error => {
dispatch(setError(error.response.status,error.response.data.msg));
dispatch(authError());
})
}
}
This is the middleware which handles the token before hitting the endpoint (In my case response is returned from here itself since there is no token sent):
function auth(req,res,next){
const token = req.header('auth-token');
if(!token) res.status(401).json({msg:"Unauthorized"})
else{
try{
const decoded = jwt.verify(token,jwt_secret);
req.user = decoded;
next();
}
catch(e){
res.status(400).json({msg:"Invalid token"})
}
}
}
I'm not able to figure out why am I getting error on console (State is getting updated as desired)
It is actually impossible to do with JavaScript. because of security concerns and a potential for a script to hide its activity from the user.
The best you can do is clearing them from your console.
console.clear();
I think it is because you are not getting the token when consulting your API.
If this is the case I recommend you use defaults.headers.common in this way
const axiosApi = axios.create({ baseURL: "http://localhost:80" });
const headerAuth = () => {
const token = getMyToken();
if (token) {
axiosApi.defaults.headers.common["Authorization"] = `Bearer ${token}`;
} else {
delete axiosApi.defaults.headers.common.Authorization;
}
};
export function loadUser(){
headerAuth(); // <-----
return function (dispatch,getState){
dispatch(userLoading());
axiosApi.get('/users/auth',config)
.then(user => {
dispatch(clearError())
dispatch(userLoaded(user.data))
})
.catch(error => {
dispatch(setError(error.response.status,error.response.data.msg));
dispatch(authError());
})
}
I recommend that you do not store the token in the REDUX but in sessionStorage
Project Issues
I'm having a problem using the state that was set, instead of the initial state where the values are empty.
Description
Im making an axios request and using the response to set the state.
Im making another axios request that uses a parameter that I can only get after making the first request.
When I try to reference the state that was set in the second request, it instead of using the set state it points back to the initial state.
Therefore making the request fail
from react dev tools
State accountId: 47228906 name: "Senpai My Guy" summonerLevel: 127
Code Snippet
initial state
class App extends Component {
constructor (props) {
super(props)
this.state = {
name: '',
summonerLevel: '',
accountId: 0
}
}
first request
componentDidMount () {
var api_key = '';
axios
.get(
`https://na1.api.riotgames.com/lol/summoner/v3/summoners/by-name/Senpai%20My%20Guy?api_key=${api_key}`
)
.then(response => {
console.log(response.data)
console.log(response.data.name)
console.log(response.data.accountId)
console.log(response.data.summonerLevel)
this.setState({
name: response.data.name,
summonerLevel: response.data.summonerLevel,
accountId: response.data.accountId
})
console.log(this.state.accountId)
})
var account_Id = this.state.accountId
add in the second one request
componentDidMount () {
var api_key = '';
axios
.get(
`https://na1.api.riotgames.com/lol/summoner/v3/summoners/by-name/Senpai%20My%20Guy?api_key=${api_key}`
)
.then(response => {
console.log(response.data)
console.log(response.data.name)
console.log(response.data.accountId)
console.log(response.data.summonerLevel)
this.setState({
name: response.data.name,
summonerLevel: response.data.summonerLevel,
accountId: response.data.accountId
})
console.log(this.state.accountId)
})
var account_Id = this.state.accountId
axios
.get(
`https://na1.api.riotgames.com/lol/match/v3/matchlists/by-account/${account_Id}?api_key=${api_key}`
)
.then(response => {
console.log(response.data.matches)
})
.catch(err => {
console.log(err)
})
}
Error
GET https://na1.api.riotgames.com/lol/match/v3/matchlists/by-account/0?api_key= 404 (Not Found)
Error: Request failed with status code 404
at createError (createError.js:16)
at settle (settle.js:18)
at XMLHttpRequest.handleLoad (xhr.js:77)
setState is asynchronous, so the state will not have been updated if you try to access it directly after using it. Your axios requests are also asynchronous, so you need to make sure the first request has finished before starting the second one.
You could instead use the accountId variable from the response in your second request.
Example
componentDidMount() {
var api_key = "...";
axios
.get(
`https://na1.api.riotgames.com/lol/summoner/v3/summoners/by-name/Senpai%20My%20Guy?api_key=${api_key}`
)
.then(response => {
var { name, summonerLevel, accountId } = response.data;
this.setState({ name, summonerLevel, accountId });
axios
.get(
`https://na1.api.riotgames.com/lol/match/v3/matchlists/by-account/${accountId}?api_key=${api_key}`
)
.then(response => {
console.log(response.data.matches);
})
.catch(err => {
console.log(err);
});
});
}