Switching from vue-resource to axios - javascript

With vue-resource, we could set the root url in main.js like so:
Vue.http.options.root = 'http://localhost:3000/api'
I tried replacing that with:
axios.defaults.baseURL = 'http://localhost:3000/api';
Vue.prototype.$http = axios
However, now my post calls don't work as expected, and Vue.http.post throws an error.
How is this achieved?

With axios, one can create another instance having a custom config
var my_axios = axios.create({
baseURL: 'http://localhost:3000/api',
});
From here one can use my_axios for operations. You could prototype the custom axios instance into Vue:
Vue.prototype.$http = my_axios

import axios from 'axios';
export const HTTP = axios.create({
baseURL: `http://localhost:3000/api/`,
headers: {
Authorization: 'Bearer {token}'
}
})
You could now use HTTP like so
<script>
import {HTTP} from './http-common';
export default {
data: () => ({
posts: [],
errors: []
}),
created() {
HTTP.get(`posts`)
.then(response => {
this.posts = response.data
})
.catch(e => {
this.errors.push(e)
})
}
}
</script>

Related

How can I use axios.defaults.baseURL conditionally? [duplicate]

I am having a config file . where i am setting the baseURL for the entire app and also saving the bearer token for the entire API requests. Here i am in situation to add another api . I dont know how to add another baseURL & use this on my API requests.Here i am sharing the code of what i have done.
BASE URL FILE:
import axios from 'axios';
axios.defaults.baseURL = http://localhost:3000/summary;
const setAuthToken = (token) => {
if (token) {
axios.defaults.headers.common.Authorization = `Bearer ${token}`;
} else {
delete axios.defaults.headers.common.Authorization;
}
};
export default setAuthToken;
API ACTION FILE:
export const login = ({ email, password }) => async (dispatch) => {
const userData = {
username: email,
password,
};
try {
const res = await axios.post('/license-api/auth/login', userData, config);
dispatch({
type: LOGIN_SUCCESS,
payload: res.data.token,
});
} catch (error) {
dispatch({
type: LOGIN_FAIL,
});
}
};
i need to add another url like this in BASE URL FILE
axios.defaults.baseURL = http://localhost:6000/profile
how to add this one and use this in API action file.
Please help me with this.
Thanks in advance
As said you could create two instances of axios and use them as needed:
In you BASE URL file:
import axios from 'axios';
const setAuthToken = (token) => {
if (token) {
axios.defaults.headers.common.Authorization = `Bearer ${token}`;
} else {
delete axios.defaults.headers.common.Authorization;
}
};
const mainAxios = axios.create({
baseURL: 'http://localhost:3000/summary'
});
const profileAxios = axios.create({
baseURL: 'http://localhost:6000/profile'
});
export default setAuthToken;
export { mainAxios, profileAxios };
Then in your API ACTION file:
import { profileAxios } from 'path/to/baseurl';
export const login = ({ email, password }) => async (dispatch) => {
const userData = {
username: email,
password,
};
try {
const res = await profileAxios.post('/license-api/auth/login', userData, config);
dispatch({
type: LOGIN_SUCCESS,
payload: res.data.token,
});
} catch (error) {
dispatch({
type: LOGIN_FAIL,
});
}
};
The above code works well. I don't see where setAuthToken is called so if you don't want to call setAuthToken manually then you might want to do this.
import axios from "axios";
import { config } from "./config";
const pythonAPI = axios.create({
baseURL: config.pythonServerUrl,
});
const nodeApi = axios.create({
baseURL: config.nodeServerUrl,
});
const setToken = () => {
const token = localStorage.getItem("auth_token");
if (token) {
pythonAPI.defaults.headers.common.Authorization = `Basic ${token}`;
} else {
delete pythonAPI.defaults.headers.common.Authorization;
}
};
const pythonApi = {};
pythonApi.get = async (url) => {
setToken();
return pythonAPI.get(url).catch((e) => e.response);
};
pythonApi.post = async (url, data) => {
setToken();
return pythonAPI.post(url, data).catch((e) => e.response);
};
export { pythonApi, nodeApi };

Can axios request wait until the response is received?

I need to get IP address and port number details from an external source. These details are required to make some other requests. Following is the code I am trying on:
import axios from 'axios'
let ServerURL
axios.get('http://some/path')
.then((response) => {
ServerURL = 'http://' + response.data.server_ip_address + ':' + response.data.server_ip_port
})
.catch((error) => {
console.log(error)
})
const apiClient = axios.create({
baseURL: ServerURL,
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
}
})
export default {
getConfigInfo () {
return apiClient.get('/config')
}
}
My problem is that by the time the exported function getConfigInfo() is called, still, the ServerURL is undefined.
How can I handle this kind of problem? Any help is highly appreciated.
Yes you can:
import axios from 'axios'
let apiClient;
const getApiClient = async () => {
if (apiClient) {
return apiClient;
}
const {
data: {
server_ip_address: ipAdress,
server_ip_port: ipPort,
}
} = await axios.get('http://some/path');
const serverUrl = `http://${ipAddress}:${ipPort}`;
apiClient = axios.create({
baseURL: ServerURL,
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
}
});
}
export default {
async getConfigInfo() {
const apiClient = await getApiClient();
return apiClient.get('/config')
}
}
Pattern used: singleton

Make API handler wrapper to reduce repetition

Right now to call a private endpoint I need to copy this code to each component. Which is messy, unsustainable, and error-prone. How would I wrap this behavior in a function call and put it where I want utilities to go? So I could import { ApiUtil } from .. and ApiUtil.post('/user', user)
import axios from 'axios';
import { useAuth0 } from '../../../react-auth0-spa';
const authContext = useAuth0();
const {
getTokenSilently
} = authContext;
const token = await getTokenSilently();
await axios({
method: 'post',
headers: {
Authorization: `Bearer ${token}`,
},
url: '/user',
data: user,
});
You can create a instance of axios and can be reused in each component
import axios from 'axios';
//token code sample
const instance = axios.create({
baseURL: API_URL,
headers: { Authorization: `Bearer ${token}` }
});
export default instance;
You could create a new file and export an instance of axios
// ApiUtil.js
import axios from 'axios';
import { useAuth0 } from '../../../react-auth0-spa';
const authContext = useAuth0();
const { getTokenSilently } = authContext;
const token = await getTokenSilently();
export default axios.create({
headers: {
Authorization: `Bearer ${token}`,
},
});
Then, you could use it like this:
import ApiUtil from './ApiUtil';
// …
await ApiUtil.post('/user', { user });

Vuex store and access to Vue.prototype

I'm starting work with Vue. I tried find solution in another posts but without success. So:
I have 2 parts of code:
//main.js
...
const axiosInstance = axios.create({
mode: 'no-cors',
baseURL: process.env.VUE_APP_BASE_URL,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
})
Vue.prototype.$http = axiosInstance
Vue.config.productionTip = false
new Vue({
router,
store,
vuetify,
i18n,
render: h => h(App),
}).$mount('#app')
and
//store.js
export default new Vuex.Store({
...
actions: {
[AUTH_REQUEST]: ({commit, dispatch}, user) => {
return new Promise((resolve, reject) => {
commit(AUTH_REQUEST)
this.$http.post('/auth/login', user)
.then(resp => {...}
})
}
})
when I trigger this.$store.dispatch(AUTH_REQUEST, ...) in component method, I see error in console, like as Uncaught (in promise) TypeError: Cannot read property '$http' of undefined.
I tried by this.$http, by this._vm.$http - the same.
Problem is that attaching the axiosInstance to Vue.prototype makes it available only in subsequent child vue components and not the store.
To access axiosInstance from the store, you will need to import it.
A way could be to refactor the axios instance to its own file and include the file in main.js so it is executed.
Then in the newly created axios file, export axiosInstance so it can be imported by the store file.
HTH
You can reach this instance only in vue js components. You need wrap axios another js file after that you have to import to vuex file. Im using like that it's useful.
Thanks for answers. I made like this
//utils/axiosHelper.js
import Vue from 'vue';
import axios from 'axios';
import router from '#/router';
const axiosInstance = axios.create({
// withCredentials: true,
mode: 'no-cors',
baseURL: 'correctUrl',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
// 'Access-Control-Allow-Origin': '*',
},
})
axiosInstance.interceptors.request.use(
config => {
if (!config.url.includes('auth')) {
if (localStorage.getItem('user-token') !== null) {
config.headers['Authorization'] = localStorage.getItem('user-token')
}
}
return config;
})
axiosInstance.interceptors.response.use(
resp => {
return resp
}, error => {
if (error.response.status === 401) {
router.push('/auth/login');
localStorage.setItem('isAdmin', null);
localStorage.setItem('user-token', null);
} else if (error.response.status >= 400) {
console.log(error.response.data);
alert(error.response.data.error);
}
return Promise.reject(error);
})
Vue.prototype.$http = axiosInstance;
export default Vue.prototype.$http;
and then
//store.js
...
import $http from '#/utils/axiosHelper'
...
export default new Vuex.Store({
...
actions: {
[AUTH_REQUEST]: ({commit, dispatch}, user) => {
return new Promise((resolve, reject) => {
commit(AUTH_REQUEST)
this.$http.post('/auth/login', user)
.then(resp => {...})
})
},
...
})
and then
//main.js
...
import $http from "#/utils/axiosHelper"
...
Vue.use($http)
and still I see Cannot read property '$http' of undefined when I try trigger AUTH_REQUEST
As mentioned above, you should move your Axios instantiation code to its own file.
File: app/src/libs/axios.js
import Vue from 'vue'
// axios
import axios from 'axios'
import updateToken from '#/auth/middleware/updateToken'
const axiosIns = axios.create({
// You can add your headers here
// ================================
// baseURL: 'https://some-domain.com/api/',
// timeout: 1000,
// headers: { 'X-Custom-Header': 'foobar' },
})
// Or you can use an interceptor if adding tokens etc.
// ======================================
axiosIns.interceptors.request.use(async config => {
const token = await updateToken()
config.headers.common.Authorization = `Bearer ${token}`
return config
})
Vue.prototype.$http = axiosIns
export default axiosIns
File: app/src/store/index.js
...
import axiosIns from '#/libs/axios'
axiosIns.get('/some/url').then(data => { console.log(data) })
...

How to mock axios dependency using mocha in TypeScript?

Here is my sample src/main.ts file
import axios from 'axios';
export async function main() {
const URL = 'test url';
const secretKey = 'Test key'
const response = await axios.get(URL, {
headers: { 'Content-Type': 'application/json', 'KEY': secretKey },
});
I want to write my test case in spec/test.ts file using mocha. Can someone show me how to create a mock and stub for axios dependency.
For mock/stub axios in typestript I recommend axios-mock-adapter, for expect functions chai
Here is an example of how to do this
request.ts
import axios from 'axios';
const apiConfig = {
returnRejectedPromiseOnError: true,
timeout: 30000,
headers: {
common: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
},
};
const request = axios.create(apiConfig);
export default request;
main.ts
import request from './request';
export const URL = 'https://httpbin.org/get';
export const secretKey = 'secret_key';
export async function main() {
const response = await request.get(URL, {
headers: {
KEY: secretKey,
},
});
// response logic
return response;
}
main.spec.ts
import MockAdapter from 'axios-mock-adapter';
import { expect } from 'chai';
import request from './request';
import { main, URL, secretKey } from './main';
describe('Request test', () => {
let stub: MockAdapter;
const receivedData = { data: 'data' };
before(() => {
stub = new MockAdapter(request);
stub.onGet(URL, {
headers: {
KEY: secretKey,
},
}).replyOnce(200, receivedData);
// replyOnce if you assume that your code sends a single request
});
it('test', async () => {
const response = await main();
expect(response.status).to.be.equal(200);
expect(response.data).to.be.deep.equal(receivedData);
});
after(() => {
stub.restore();
});
});

Categories

Resources