I have created a config file to create an Axios.
export const http = axios.create({
baseURL: process.env.REACT_APP_API_URI,
responseType: "json",
timeout: 30000,
timeoutErrorMessage: "Request Time out",
headers: {
withCredentials:true
}
})
In the other file, I have created helper functions to post, update, and get. Now I am trying to pass data from the body through the get function so far I have following code to get data without passing the body.
export const getRequest = (url, is_strict = false) => {
return new Promise((resolve, reject) => {
http.get(url, {
headers: getHeaders(is_strict)
}).then((response) => {
if(response.status === StatusCodes.OK || response.status === StatusCodes.CREATED){
resolve(response.data);
} else {
reject(response);
}
})
.catch((error) => {
reject(error);
})
})
}
How can I achieve that?
You cannot have a request body in GET method. You can use request params instead. Or you can use POST method.
Form the MDN docs for GET,
property
avaiability
Request has body
No
Request has body
Yes
Related
I'm trying to update the state of my component with the response data after Post request with axios but it returns an empty array when I log out the updated state with console.log(), but shows the response.data information received with .then in axois in the broswer console. Please help me out
Code starts here
const [offers, setOffers] = useState({});//THIS IS THE STATE
const search async (e) => {
e.preventDefault();
const options = {
url: "localhost:8080/api/search",
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json;charset=UTF-8",
},
data,
};
axios(options)
.then((response) => {
console.log(response.data.data);// THIS RETURNS OBJECT DATA GOTTEN FROM THE SERVER AFTER POST REQUEST
setOffers(response.data.data); //IT DOES NOT UPDATE WITH RESPONSE DATA
console.log(offers); = IT RETURNS AND EMPTY ARRAY
})
.catch(function (error) {
if (error.response) {
setValerr(error.response.data.errors);
console.log(error.response);
}
});
};
thanks in advance
In react, setState is asynchronous, so when you call "setOffers" it is an asyncronous action.
Therefore when you call console.log, offers might not be updated yet.
You can read more about it here:
https://reactjs.org/docs/faq-state.html#when-is-setstate-asynchronous
To listen to the value of "offers" you might need to use useEffect
An example
const [offers, setOffers] = useState({}) //THIS IS THE STATE
const search = async (e) => {
e.preventDefault()
const options = {
url: 'localhost:8080/api/search',
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json;charset=UTF-8',
},
data,
}
axios(options)
.then((response) => {
console.log(response.data.data) // THIS RETURNS OBJECT DATA GOTTEN FROM THE SERVER AFTER POST REQUEST
setOffers(response.data.data) //IT DOES NOT UPDATE WITH RESPONSE DATA
console.log(offers)
})
.catch(function (error) {
if (error.response) {
setValerr(error.response.data.errors)
console.log(error.response)
}
})
}
useEffect(() => {
// This should log offers to the console if it has been set
if(offers) {
console.log(offers)
}
}, [offers])
I am just trying my first reactJS app.
In that I am using axios.post() method for sending data.
submitHandler = event => {
event.preventDefault();
axios
.post("http://demo.com/api/v1/end-user/login", {
username: "",
password: "",
user_type: 1
})
.then(res => {
console.log(res);
console.log(res.data);
});
}
But when I check into my network tab, data which I am sending along with request is seems to be in payload.
I would like to send the data as form data instead. Am I am missing something?
If you want to send the data as form data instead of as JSON in the payload, you can create a FormData object and use that as second argument instead.
submitHandler = event => {
event.preventDefault();
const formData = new FormData();
formData.append("username", "");
formData.append("password", "");
formData.append("user_type", 1);
axios.post("http://demo.com/api/v1/end-user/login", formData).then(res => {
console.log(res);
console.log(res.data);
});
};
You can do this in axios by using FormData() like
var body = new FormData();
body.append('userName', 'test');
body.append('password', 'test');
body.append('user_type', 1);
And then you can use axios post method (You can amend it accordingly)
axios({
method: 'post',
url: 'http://demo.com/api/v1/end-user/login',
data: body,
config: { headers: {'Content-Type': 'multipart/form-data' }}
})
.then(function (response) {
//handle success
console.log(response);
})
.catch(function (response) {
//handle error
console.log(response);
});
What worked for me is to send the form trough params: instead of data:
That way it will be send as GET variables instead of Request Payload and is much easier to read with $_GET in PHP. No idea how to send as post
axios({
method: 'post',
params: data,
url: 'api.php',
})
.then((res) => {
//Perform Success Action
})
.catch((error) => {
// error.response.status Check status code
}).finally(() => {
//Perform action in always
});
I checked all the similar questions here but none has what I need.
I'm securing the routs in my App and sending the JWT with every request and everything is fine here.
The issue is when the JWT expires, instead of logging out the user, I need to know how to refresh that token and keep the user logged in.
Everyone is talking about creating a "Middleware" that handles that, but no one says how to create that middleware and what's in it?
So, what is the best practice in doing that? Should I check for JWT expiration date before sending any request? or should I wait for a "401" response then try to refresh the token (which I don't know how to do), or what exactly?
If anyone has a working example of such a middleware or a package or a project on Github that can help me with this it would be great.
I'm only interested in the front-end part of the process, what to send from react and what should I expect to receive and what to do with it.
If you are using Axios (which I highly recommend), you can declare your token refreshing behaviours in the response's interceptors. This will apply to all https requests made by Axios.
The process is something like
Checking if the error status is 401
If there is a valid refresh token: use it to get the access token
if there is no valid refresh token: log the user out and return
Redo the request again with the new token.
Here is an example:
axios.interceptors.response.use(
(response) => {
return response
},
(error) => {
return new Promise((resolve) => {
const originalRequest = error.config
const refreshToken = localStorage.get('refresh_token')
if (error.response && error.response.status === 401 && error.config && !error.config.__isRetryRequest && refreshToken) {
originalRequest._retry = true
const response = fetch(api.refreshToken, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
refresh: refreshToken,
}),
})
.then((res) => res.json())
.then((res) => {
localStorage.set(res.access, 'token')
return axios(originalRequest)
})
resolve(response)
}
return Promise.reject(error)
})
},
)
your middelware should look like this block of code (as example you can use whatever you want)
/* eslint-disable */
import request from 'superagent';
function call(meta, token) {
const method = meta.API_METHOD ? meta.API_METHOD : 'GET';
let req = request(method, 'http://localhost:8000/' + meta.API_CALL);
req = req.set({ Authorization: `JWT ${token}` });
req = meta.API_TYPE ? req.type('Content-Type', meta.API_TYPE) : req.set('Content-Type', 'application/json');
if (meta.API_PAYLOAD) {
req = req.send(meta.API_PAYLOAD);
}
if (meta.API_QUERY) {
req.query(meta.API_QUERY);
}
return req;
}
export default store => next => action => {
const state = store.getState();
const token = state.logged && state.logged.get('token') ?
state.logged.get('token') : 'eyJhbGciOiJIUzUxMiJ9';
if (action.meta && action.meta.API_CALL) {
call(action.meta, token)
.then((res) => {
store.dispatch({
type: action.meta.API_SUCCESS,
result: res.body,
});
})
.catch(({ status, response }) => {
if (action.meta.API_ERRORS && action.meta.API_ERRORS[status]) {
return store.dispatch({
type: action.meta.API_ERRORS[status],
result: response.body,
});
}
if (action.meta.API_ERRORS && action.meta.API_ERRORS[status] === '401') {
/*call the refresh token api*/
call(<Your Meta for refreshing>, <expiredtoken>)
.then((res) => {
store.dispatch({
type: action.meta.API_SUCCESS,
result: res.body,
});
})
.catch(({ status, response }) => {
if (action.meta.API_ERRORS && action.meta.API_ERRORS[status]) {
return store.dispatch({
type: action.meta.API_ERRORS[status],
result: response.body,
});
}
throw response;
});
}
throw response;
});
}
return next(action);
};
I have decided to put all my API calls in a seperate file and they are all stateless.
const get = endPoint => {
let token = "c8c17003468314909737ae7eccd83d4b6eecb792"; //I have put this token here manually
return fetch(endPoint, {
method: "GET",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
Authorization: "Token " + token
}
}).then(response => response.json());
};
and in the same file i have the actual API calls. Example is as follows.
export const loadGroups = () => {
const endPoint = "https://xxxx.com/api/groups/";
return get(endPoint);
};
This works perfectly when i call the API from various components as follows.
import { loadGroups } from "../../api";
componentDidMount() {
loadGroups()
.then(responseJson => {
this.setState({
groups: responseJson
});
})
.catch(error => {
console.error(error);
});
}
However, I want to use AsyncStorage to retrieve a stored token and the due nature of it is to return a promise. This works well when i write the functions of getting the token and storing it in SetState in every component that I do the calls. I really want to refactor the code and using redux is a pain for me.
so far, i have written a file to get the token and it returns a promise.
import { AsyncStorage, Text } from "react-native";
const MyToken = async () => {
try {
const retrievedItem = await AsyncStorage.getItem("userToken");
const item = JSON.parse(retrievedItem);
return item;
} catch (error) {
return null;
}
};
export default MyToken;
And in the API file, I have re-written the code above to
const get = endPoint => {
MyToken().then(token => {
console.log(token, "try 1"); //this works
const lookupOptions = {
method: "GET",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
Authorization: "Token " + token
}
};
return fetch(endPoint, lookupOptions).then(response => {
console.log(response.json(), "promise response,json");
response.json();
});
});
};
However, whenever i call loadGroups().then() (like in the first example) function in any component, I get an errors that loadGroups.then() can't be resolved
Is there any way to resolve this without state, redux, mobx keeping in mind i want my API code in stateless functions in seperate modules.
In V2 of get function, you are not returning any Promise. Either put a return statement in get function like
const get = endPoint => {
return MyToken().then(
...
);
}
Or return Promise explicitly from that function, consider following code snippets
const get = endPoint => {
return new Promise((resolve, reject) => {
MyToken().then(token => {
...
fetch(endPoint, lookupOptions)
.then(response => response.json())
.then(resolvedResponse => {
resolve(resolvedResponse);
}).catch(error => {
reject(error);
});
});
});
};
Hope this will help!
I almost finished creating React Native application, few days ago register action has stopped working.. I'm sending fetch request and it always returns network error altough there is 400 response and message that user exists, it stops there..
I'm destructuring the response and displays api response message instead of fetch network error but now it doesn't work. I'm doing the same for the login action and it works.
Could it be something with multipart/form-data ?
export const register = data => dispatch => {
dispatch(createUser());
const d = new FormData();
d.append("name", data.name);
d.append("email", data.email);
d.append("password", data.password);
d.append("avatar", data.avatar);
fetch(API_URL + "/register", {
method: "POST",
headers: {
"content-type": "multipart/form-data"
},
body:d
})
.then(response => response.json().then(user => ({ user, response })))
.then(({ user, response }) => {
if (!response.ok) {
console.log(response, user)
} else {
console.log(response, user)
}
})
.catch(err => {
throw err;
});
};
The api route works in Postman..
In this case, your using fetch which is Promise based incorrectly,
Try,
fetch(API_URL + "/register", {
method: "POST",
headers: { "content-type": "multipart/form-data" },
body:d
})
.then(response => {
console.log(response, response.json().user)
})
.catch(err => {
console.log(err)
});
Check the logs and see if it shows proper network response and debug from there.