I'm just learning how hooks work in larger applications. I'm trying to figure out what the correct pattern is here. I typically wrap my api calls in their own files. For instance, I might call out to get a list of customers in a file Customers.Api.js:
import axios from 'axios';
const client = await getApiClient();
const reply = await client.get(`${baseUrl}/customers`);
return reply;
The job of getApiClient() is to get an axios instance that already has the Authorization header added. I am getting this from Auth0, but that part doesn't matter as I am really looking for the pattern here and not specifics to Auth0, could be any hook:
// Engine.Api.js
// Inside an axios interceptor called from getApiClient()
const { getAccessTokenSilently } = useAuth0(); // <-- this is not allowed in a plain js func
const token = await getAccessTokenSilently({});
request.headers.Authorization = `Bearer ${token}`;
...
return request
Since my token comes from a hook, how should I be setting this up?
I don't want to do this every time:
const { getAccessTokenSilently } = useAuth0();
const token = await getAccessTokenSilently({});
const client = await getApiClient();
const reply = await client.get(`${baseUrl}/customers`,{
headers: `Authorization: Bearer ${token}`,
})
I would prefer some way to do this (or something similar):
const customers = await getCustomers();
getCustomers() would live in Customers.Api.js and would have something like:
const client = await getApiClient(); // <-- this would use interceptor to add bearer
return await client.get(`${baseUrl}/customers`);
Final Solution
After looking at what Andrey had to say, I finally got to where I needed to be. Here is what I ended up doing:
const axiosClient = axios.create();
export function useApiClient() {
const { getAccessTokenSilently, isLoading } = useAuth0();
const [state, setState] = useState({
loading: true,
authHeader: null,
token: '',
client: null,
});
useEffect(() => {
(async () => {
if (!isLoading) {
if (state.token === '') {
const apiToken = await getAccessTokenSilently({
audience: 'https://example.com/',
scope: 'read:current_user',
});
setState({ ...state, authHeader: { Authorization: `Bearer ${apiToken}` }, token: apiToken });
}
if (state.token && !state.client && state.loading) {
setState({ loading: false, client: axiosClient });
}
}
})();
}, [getAccessTokenSilently, state, isLoading]);
return { ...state };
}
I also modified it a lot after that as this was not really my true use case, but it identified what I was not understanding. Thanks Andrey!!!!