Created
September 16, 2022 02:53
-
-
Save ashwanth1109/ca13e58b121afb3c4e75f8b74d323f45 to your computer and use it in GitHub Desktop.
useAPI proposal
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { useState, useEffect, useCallback } from 'react'; | |
import axios, { AxiosInstance } from 'axios'; | |
import camelcaseKeys from 'camelcase-keys'; | |
import { ok, err, Result } from 'neverthrow'; | |
interface APIError { | |
message: string; | |
} | |
interface useApiProps { | |
apiBaseUrl: string; | |
tokenFetcher: () => Promise<string | null>; | |
} | |
interface Account { | |
id: number; | |
name: string; | |
smbName: string; | |
} | |
interface IUseAccountServices { | |
getAccount: () => Promise<Result<Account, APIError>>; | |
} | |
interface Instance { | |
id: number; | |
account: Account; | |
name: string; | |
} | |
interface IUseInstanceServices { | |
getInstance: (id: number) => Promise<Result<Instance, APIError>>; | |
getInstances: () => Promise<Result<Instance[], APIError>>; | |
} | |
interface APIServices { | |
accountService: ReturnType<typeof useAccountServices>; | |
instanceService: ReturnType<typeof useInstanceServices>; | |
} | |
const useAccountServices = ({ | |
api, | |
}: { | |
api: AxiosInstance | null; | |
}): IUseAccountServices => { | |
const getAccount = useCallback(async () => { | |
try { | |
const res = await api?.get('/account'); | |
return ok(res?.data); | |
} catch (e) { | |
return err({ message: e.message }); | |
} | |
}, [api]); | |
return { | |
getAccount, | |
}; | |
}; | |
const useInstanceServices = ({ | |
api, | |
}: { | |
api: AxiosInstance | null; | |
}): IUseInstanceServices => { | |
const getInstance = useCallback( | |
async (id: number) => { | |
try { | |
const res = await api?.get(`/instances/${id}`); | |
return ok(res?.data); | |
} catch (e) { | |
return err({ message: e.message }); | |
} | |
}, | |
[api] | |
); | |
const getInstances = useCallback(async () => { | |
try { | |
const res = await api?.get('/instances'); | |
return ok(res?.data); | |
} catch (e) { | |
return err({ message: e.message }); | |
} | |
}, [api]); | |
return { | |
getInstance, | |
getInstances, | |
}; | |
}; | |
const useApi = ({ apiBaseUrl, tokenFetcher }: useApiProps): APIServices => { | |
const [token, setToken] = useState<string | null>(null); | |
const [api, setApi] = useState<AxiosInstance | null>(null); | |
const [err, setErr] = useState<Error | null>(null); | |
const accountService = useAccountServices({ api }); | |
const instanceService = useInstanceServices({ api }); | |
// | |
const services = { | |
accountService, | |
instanceService, | |
}; | |
// Effect to fetch the token | |
useEffect(() => { | |
const fetchToken = async () => { | |
const token = await tokenFetcher(); | |
setToken(token); | |
}; | |
fetchToken().catch((e) => setErr(e)); | |
}, [tokenFetcher]); | |
// Effect to create API endpoint instance once token is available | |
useEffect(() => { | |
if (!token) { | |
return; | |
} | |
try { | |
const api = axios.create({ | |
baseURL: apiBaseUrl, | |
headers: { | |
Authorization: token, | |
}, | |
}); | |
// https://stackoverflow.com/questions/43051291/attach-authorization-header-for-all-axios-requests | |
// Attach authorization token to all requests | |
api.interceptors.request.use((cfg) => { | |
cfg.headers.Authorization = token; | |
return cfg; | |
}); | |
// Convert snake case to camel case for all responses | |
api.interceptors.response.use((res) => { | |
res.data = camelcaseKeys(res.data, { deep: true }); | |
return res; | |
}); | |
setApi(api); | |
} catch (e) { | |
setErr(e); | |
} | |
}, [apiBaseUrl, token]); | |
return services; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment