axios interceptors how to use them with axios.create() - axios

I have the following code which I import and use in a VueJS application.
I want to be able to errors returned by the API centrally and it seems that interceptors would do the job for me but I don't understand where I set them up
import axios from 'axios'
import store from './store/index'
export default () => {
try{
var token = store.state.user.token.token
}catch(err){
var token = ""
}
return axios.create({
baseURL: "http://localhost:3333/api/v1",
headers: {
"Authorization": `Bearer ${token}`
}
})
}
I have tried this, but it does not work.
import axios from 'axios'
import store from './store/index'
axios.interceptors.request.use((config) => {
console.info("debug ", config);
return config;
}, (error) => {
console.error("debug ", error);
return Promise.reject(error);
});
export default () => {
try{
var token = store.state.user.token.token
}catch(err){
var token = ""
}
return axios.create({
baseURL: "http://localhost:3333/api/v1",
headers: {
"Authorization": `Bearer ${token}`
}
})
}

After some fiddling, I have worked it out.
You have to first create an axios object with axios.create(), then assign your intercepters to the object after which you can return the object. Here is the code I used that worked.
var axiosInstance = axios.create({
baseURL: "http://localhost:3333/api/v1",
headers: {
"Authorization": `Bearer ${token}`
},
})
//This allows you to intercept the request before it is sent and alter headers or anyting else that is passed to the axios config.
axiosInstance.interceptors.request.use((config)=>{
return config
}, (error) => {
console.log("Interceptor Request Error" + error)
})
//This allows you to intercept the response and check the status and error messages and if ncessary reject the promise.
axiosInstance.interceptors.response.use((response) => {
console.log(response.data)
return response
}, (error) => {
console.log("Interceptor Response Error" + error)
})
return axiosInstance
Now I know how to do this, I could move my Authorization code out of the create function and put it in the request interceptor axiosInstance.interceptors.request.use

Related

Axios interceptor not working anymore in last version (1.1.3)

I recently upgraded axios in one of my project (from 0.27 to 1.1.3) and the interceptor I created to refresh the user's access token doesn't work anymore, u can find in the screenshot bellow the error I'm having. I searched online but can't find anything working.
To precise, whenever the user's access token expires, my back end send the 401 error and so the interceptor is called. The returned token is good as well as the setting to the headers.
Thank you in advance for your time.
import axios from "axios";
import router from "#/router";
import store from "#/store/index";
const instance = axios.create({
baseURL: "http://localhost:3000",
});
instance.interceptors.response.use(
(response) => {
return response;
},
async (error) => {
const originalRequest = error.config;
console.log("error:", error);
if (
error.config.url != "users/refreshToken" &&
error.response.status === 401 &&
!originalRequest._retry
) {
originalRequest._retry = true;
await instance
.get("users/refreshToken", { withCredentials: true })
.then((response) => {
const token = response.data.accessToken;
console.log("token:", token);
store.state.token = token;
instance.defaults.headers.common["authorization"] = `Bearer ${token}`;
originalRequest.headers["authorization"] = `Bearer ${token}`;
localStorage.setItem("token", token);
})
.catch(() => {
store.commit("logout");
localStorage.removeItem("token");
router.push({ name: "login", params: { error: "refreshToken" } });
});
return instance(originalRequest);
}
return Promise.reject(error);
}
);
export default instance;
The error :

Router API cannot use res.end() or res.json() in catch/

I dont know why but if function not get error, it work perfectly , but when it get error, catch always display
res.end is not a function
it like i can't use res in catch, but in try res still work, Am i missing something?
import axios from "axios";
import { NextApiResponse } from "next";
const handler = async (res: NextApiResponse): Promise<void> => {
return new Promise((resolve, _) => {
axios({
method: "get",
headers: { "Content-type": "application/json" },
url:
process.env.NODE_ENV === "production"
? "https://.../refresh_token"
: "http://localhost:4000/refresh_token",
withCredentials: true,
})
.then((response) => {
res.statusCode = 200;
res.setHeader("Content-Type", "application/json");
res.setHeader("Cache-Control", "max-age=180000");
res.end(JSON.stringify(response.data));
resolve();
})
.catch((error) => {
res.statusCode = 500;
res.end(JSON.stringify((error as Error).message));
resolve();
});
});
};
export default handler;
The first parameter in your handler function should be a NextApiRequest object, not a NextApiResponse object:
const handler = async (req: NextApiRequest, res: NextApiResponse): Promise<void> => { //...
Since req is expected to be the first parameter, passing res there will mean calling end on the NextApiRequest object — an error because end doesn't exist there.

How to code Multipart-form POST REQUEST using apollo-datasource-rest

I want to code the multipart-form POST REQUEST below using apollo-datasource-rest
My attempt to code this leads to a BAD REQUEST error
const { RESTDataSource } = require('apollo-datasource-rest');
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
class SalesforceApi extends RESTDataSource {
constructor() {
super();
this.initialize({});
this.getAccessToken()
.then((accessToken) => {
this.headers = {
Authorization: `Bearer ${accessToken}`,
};
});
}
async getAccessToken() {
console.log('Getting Salesforce access token');
try {
const response = await this.post(
'https://test.salesforce.com/services/oauth2/token',
{
username: 'FILTERED#FILTERED',
password: `${'FILTERED'}`,
grant_type: 'password',
client_id: 'FILTERED',
client_secret: 'FILTERED',
},
{
headers: {
'Content-Type': 'multipart/form-data',
},
},
);
const { accessToken } = response;
console.log(`ChangeGear sessionId: ${accessToken}`);
return accessToken;
} catch (error) {
console.log(`${error}`);
}
return 'No access token!!!';
}
module.exports = SalesforceApi;
[server:salesforce:local] POST https://test.salesforce.com/services/oauth2/token (343ms)
[server:salesforce:local] Error: 400: Bad Request
If memory serves correctly, form data is serialized slightly differently hence why the FormData interface exists. And the apollo-datasource-rest's this.post method is just a wrapper around fetch, so something like the below should work.
Instead of passing the body as a JSON object, try something like this
const formData = new FormData();
formData.append('username', 'FILTERED#FILTERED');
// ... more append lines for your data
const response = await this.post(
'https://test.salesforce.com/services/oauth2/token',
formData
{
headers: {
'Content-Type': 'multipart/form-data',
},
},
);

axios post request fails with bad request

I try to do a simple post request with axios.
My code snippet:
const getOauthToken = async () => {
try {
const headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'X-ProxyPass' : '...',
}
const data = {
...
}
return await axios.post('/oauth2/token', data, {headers: headers});
} catch (error) {
throw new Error(`Unable to get an authentication token. Reason ${error}`);
}
};
This call fails with http 400. When I set the headers as default with
axios.defaults.headers.post['X-ProxyPass'] = '...';
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
then it works.
Found the solution in the documentation of axios.
If I use "application/x-www-form-urlencoded", I have to use querystring to serialize in the needed format.
return await axios.post('/oauth2/token', querystring.stringify(data), {headers: headers});
But why it works, when I set the headers as default headers i still mysterious.

Axios OPTIONS instead of POST Request. Express Rest API (CORS)

Im trying to use Axios (and VueJs) to make a Cross Origin POST Request to my Rest Api (running on localhost). Instead of doing a POST request, it actually does a OPTIONS request to my Rest Api. This circumvents a middleware function that checks for a token and return 403.
This is the login function
router.post('/login', (req, res) => {
User.authUser(req.body, (err, user) => {
var passwordIsValid = bcrypt.compareSync(req.body.password, user.password);
if (err) throw err;
if (!user) {
res.json({ success: false, message: 'User nicht gefunden' });
} else if (user) {
if (!passwordIsValid) {
res.json({ success: false, message: 'Falsches Passwort' });
} else {
const payload = {
admin: user.admin
};
var token = jwt.sign(payload, config.secret, {
expiresIn: 86400
});
res.json({success: true, message: 'Token!', token: token});
}
}
})
});
How can I get Axios to make a proper POST request? I tried this hack, because I first thought the OPTIONS Request was just a preflight, but there is no request after I return 200 (or 204)
CORS Middleware:
app.use(function(req, res, next) { //set Response Headers
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
if ('OPTIONS' == req.method) {
res.send(204);
}
else {
next();
}
});
Axios will sometimes send an OPTIONS request as part of a cors preflight if it doesn't know the Content-Type of a request.
You can get explicitly specify the Content-Type when you build the request, and then it should send your POST request as expected.
Instead of
axios.post(url, params), try:
axios.post(url, params, {
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
})