I have a react app.
I have an axios component I want to reuse:
import axios from 'axios'
import dynamic from 'next/dynamic'
const baseUrl = 'http://127.0.0.1:8000/'
const axiosInstance = axios.create({
baseURL: baseUrl,
timeout: 5000,
headers: {
Authorization: localStorage.getItem('access_token')
? 'Bearer ' + localStorage.getItem('access_token')
: null,
'Content-Type': 'application/json',
accept: 'application/json',
}
})
export default axiosInstance
Now, I try and import this into my registration page as follows:
import axiosInstance from "axiosInstance"
The file itself looks like this:
const handleFormSubmit = async (values: any) => {
axiosInstance.post(`account/register/`, {
username: values.username,
email: values.email,
password: values.password,
confirm_password: values.confirm_password,
}).then((response) => {
console.log(response);
});
// router.push('/profile')
console.log(values);
};
However, this throws an error:
Can some please help me with this issue? I am new to Nextjs and looked at
https://nextjs.org/docs/advanced-features/dynamic-import#with-no-ssr
but not sure how to use it in this context.
localStorage is a propert on window object, and since next.js is a server side rendering framework, when next renders the component on server, window.localStorage will be undefined.
In order to import it, set the axios instance like this:
const axiosInstance = axios.create({
baseURL: baseUrl,
timeout: 5000,
headers: {
// if localStorage is not defined, it wont throw error
Authorization:localStorage && localStorage.getItem('access_token')
? 'Bearer ' + localStorage.getItem('access_token')
: null,
'Content-Type': 'application/json',
accept: 'application/json',
}
})
and then inside
localStorage is part of the browser's storage and not the server's. You could use an environment variable and use process.env.ACCESS_TOKEN
More can be read here
Basically you create a file called .env.local
There is built in support in NextJS for this file.
Here you defined your variables as follows
ACCESS_TOKEN=myAccessTokenIsAwesome
SOMETHING_ELSE=myOtherKeyINeed
In your code you can then use the process.env.ACCESS_TOKEN to use this defined environment variable
Related
When I try to login to my react app it returns as success and saves it in sessionStorage but when I try to access the page which requires Bearer token to fetch data via axios it returns http 401 error.
But when I reload the page, then the result is as required.
import axios from "axios";
let token = JSON.parse(window.sessionStorage.getItem("token"));
let AxiosInstance= axios.create({
baseURL: "https://myurl.com/backend/api/",
timeout: 5000,
headers: { Authorization: "Bearer " + token },
});
export default AxiosInstance;
Your token is being initialized onload so you have to call token in config.headers["Authorization"] on every request through interceptor so you don't need to reload page.
Interceptor:
Axios interceptors are functions that are called before a request is sent and after a response is received
import axios from "axios";
let AxiosInstance = axios.create({
baseURL: "https://myurl.com/backend/api/",
timeout: 5000,
});
AxiosInstance.interceptors.request.use(function (config) {
let token = JSON.parse(window.sessionStorage.getItem("sessionData"));
config.headers["Authorization"] = "Bearer " + token;
return config;
});
export default AxiosInstance;
UPDATE: You can learn more here about Axios interceptors
I'll guess it is because you're creating the axios instance outside any of React's lifecycle
when you run your app and enter your login screen, it makes a Axios instance
import axios from "axios";
let token = JSON.parse(window.sessionStorage.getItem("token"));
let AxiosInstance = axios.create({
baseURL: "https://myurl.com/backend/api/",
timeout: 5000,
headers: { Authorization: "Bearer " + token }, // on the first go token is null
});
export default AxiosInstance;
After you login, your axios instance still has a nulll token, you see, this code is executed once and never more, that's why when you refresh the page, it works, because when this piece of code is executed once again, there's a token in localstorage.
There's a couple things you can do but the easiest i guess it's to use Axios interceptors
AxiosInstace.interceptors.request.use(function (config) {
const token = localStorage.getItem('token');
config.headers.Authorization = token ? `Bearer ${token}` : '';
return config;
});
That way every time you do a request your headers will be updated (not sure if this is the best approach but it works)
I want to add an authorization to header, I've already assign to header before like in the code below
const axiosIns = axios.create({
baseURL: 'http:$$$$$$$$$$/api/app',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
})
Then I added interceptor and assigned token to authorization header
axiosIns.interceptors.request.use(async config => {
const accessToken = await authService.getAccessToken()
config.headers.Authorization = `Bearer ${accessToken}`
return config
})
but typescript put red line below config.headers says Object is possibly 'undefined'
The error message "Object is possibly 'undefined'" is indicating that the TypeScript compiler is not sure if the "config.headers" object is defined or not. This can happen if the "config" object passed to the request interceptor does not have a "headers" property. To fix this, you can add a check for the "headers" property before trying to access it.
You can add a check to ensure the headers object is defined before trying to add the Authorization header.
axiosIns.interceptors.request.use(async config => {
const accessToken = await authService.getAccessToken()
if (config.headers) {
config.headers.Authorization = `Bearer ${accessToken}`
}
return config
});
This way, if the headers property is undefined, you will skip the assignment and not get the error.
axiosInstance.interceptors.request.use((config: AxiosRequestConfig) => {
config.headers['Authorization'] = auth;
return config
})
you can red more there
I am trying to create and axios instance so that I don't have to write Authorization header on every request. I am storing access token on localStorage.
I tried creating a file axiosInstance.ts
import axios, { AxiosInstance } from "axios"
const service = axios.create({
baseURL: "http://localhost:5000/",
headers: {
Authorization: localStorage && localStorage.getItem("token")
? `Bearer ${localStorage.getItem("token")}`
: "",
},
})
export default service
But it throws localStorage is not defined error.
So I tried to make this a custom hook like this
useAxios.ts
function useAxios() {
const [axiosInstance, setAxiosInstance] = useState<null | AxiosInstance>(null)
useEffect(() => {
const service = axios.create({
baseURL: "http://localhost:5000/",
headers: {
Authorization: localStorage.getItem("token")
? `Bearer ${localStorage.getItem("token")}`
: "",
},
})
setAxiosInstance(service)
}, [])
return axiosInstance
}
export default useAxios
And when i tried to use it like this it threw an error which says service.post is not a function
So when i log the service/axiosInstance it logs a get request promise to baseURL. I am not sure what i am doing wrong.
I send a request to the API for creating an account(I use axios) then API send me a response involve a token. I save this token in local storage.But I don't know how to send it in axios header.
if (this.sendRequest) {
axios.post(url, data)
.then((res) => {
if (res.data.type === "success") {
localStorage.setItem("token",res.data.data);
}
})
.catch((err) => this.msg.push("error" + err.response.status));
}
To do this, follow the steps below:
1- create a folder in your project called Services. Then create another directory in that folder called Config. Inside that folder create a .js file called auth-axios.js as follows:
In this file, you use the following code. By doing this, you inform the application that every time you want to call the API, you must go through this port and you must set the base URL and header in the API automatically:
import axios from "axios";
import authService from "../modules/authService";
import Vue from "vue";
const headers = {
"content-type": "application/json",
Accept: "application/json",
"Accept-Language": "fa",
version: "1000"
};
const API_V1 = axios.create({
baseURL: process.env.VUE_APP_BASE_URL_V1,
headers: headers
});
const API_DEV = axios.create({
baseURL: process.env.VUE_APP_BASE_URL_DEV,
headers: headers
});
API_DEV.interceptors.request.use(
config => {
const token = authService.getAccessToken();
if (token) {
config.headers["Authorization"] = "Bearer " + token;
}
return config;
},
error => {
Promise.reject(error);
}
);
export { API_V1, API_V4, API_DEV };
Now for the services that you have in the application, you have to create a separate file in the same services directory and use the API_1 variable in that file.
for example, create accountServices.js and on this file call API by this way:
import { API_V1 } from "../config/auth-axios";
class employerServices {
createAccount(body) {
return API_V1.post("test-API-URL", body);
}
}
export default new employerServices();
I am building an Vue.js app that relies heavily on api calls. I am using axios to make call.
I am using a pattern similar this. Basically I have created a service that will be shared by all the components.
Following is the service:
//api-client.js
import axios from 'axios'
import store from '../src/store'
let authKey = store.getters.getAuthKey
export default axios.create({
withCredentials: false, // This is the default
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
authorization: "Basic "+authKey
}
})
Now notice I am using a getter to get auth token for the vuex store and seting it in the service.
I will use this service like:
//App.vue
<template>
<div>
<!-- some code -->
</div>
</template>
<script>
import apiClient from "../api-client.js"
export default {
mounted(){
apiClient.get("#url").then(()={
// Do Something
})
}
}
</script>
<style lang="scss">
</style>
The situation is, auth key changes every now and then, so I have a setting that will update the auth key in the store.
The setting updates the auth key in store successfully, but the key in api-client.js is not updated. It is loaded only once and the update in the store is not cascaded to this api-client.js.
Is there any pattern to solve this? Please suggest.
Since your token is dynamic, you can't define it in your axios instance factory headers setup. Best way to handle this globally is to use request interceptors
//api-client.js
import axios from 'axios'
import store from '../src/store'
const apiClient = axios.create({
withCredentials: false, // This is the default
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
}
});
apiClient.interceptors.request.use(function (config) {
// Do something before request is sent
let authKey = store.getters.getAuthKey
config.headers["Authorization"] = "Basic " + authKey;
return config;
});
export default apiClient;
This way interceptor function would occur on each request and would pickup latest version of your authKey;