This is a package to abstract all boilerplate configurations for a production http client library. Axios is used as base provider
import { HttpClient } from '.';
export const Http = HttpClient.getOrCreateInstance<'LEGACY_API' | 'ANOTHER_API' | 'PUBLIC'>();
Http.register('LEGACY_API', {
baseURL: 'http://legacy.company.com/api/v1',
getToken: () return localStorage.getItem('token') ?? "",
beforeRedirect(options, responseDetails) {
console.log(options, responseDetails);
},
onSessionExpired(error) {
console.log(error);
},
onUnauthorized(error) {
console.log(error);
},
});
Http.register('ANOTHER_API', {
baseURL: 'http://another.company.com/api/v1',
getToken: () return process.env.ACCESS_TOKEN ?? "",
beforeRedirect(options, responseDetails) {
console.log(options, responseDetails);
},
onSessionExpired(error) {
console.log(error);
},
onUnauthorized(error) {
console.log(error);
},
});
Http.getInstance('ANOTHER_API')
.get('/customers')
.then(console.log)
.catch((err) => console.log(HttpClient.parseError(err)));
Method | Description |
---|---|
GetMethod | Retrieves data from a specified resource. |
PostMethod | Submits data to be processed to a specified resource. |
PatchMethod | Partially updates data on a specified resource. |
PutMethod | Updates a resource or creates it if it doesn't exist. |
DeleteMethod | Removes data from a specified resource. |
DownloadFileMethod | Downloads a file from a specified resource. The progress is trackeable. |
UploadFileMethod | Uploads a file to a specified resource. The progress is trackeable. |
import { GetMethod } from '.';
GetMethod.build(Http.getInstance('ANOTHER_API'))
.send('/customers')
.then(console.log)
.catch((err) => console.log(HttpClient.parseError(err)));
import { GetMethod } from '.';
const instance = GetMethod.build(Http.getInstance('ANOTHER_API'));
instance
.send('/customers')
.then(console.log)
.catch((err) => console.log(HttpClient.parseError(err)));
instance.abort();
import { PostMethod } from '.';
type LogicResponse = {};
type BasicCredentials = { email: string; password: string };
class LoginUseCase extends PostMethod<BasicCredentials, BackendResponse<LogicResponse>> {
constructor(instance: AxiosInstance) {
super(instance);
}
public async execute(credentials: BasicCredentials): Promise<void> {
Assert.assertBasicCredentials(credentials);
const { data: userSession } = await this.send('/customers', credentials);
DomainStorage.persistSession(userSession);
DomainBus.dispatch(DomainEvents.SessionSuccess, userSession);
}
}
Here an example of how to use it. In this example I am creating a hoc that will create a downloadable generic component.
import { DownloadFileMethod } from '.';
const instance = DownloadFileMethod.build(Http.getInstance('ANOTHER_API'));
type ProgressState = { progress: number; loading: boolean; error?: string };
type DownloadComponentProps = { onClick(): void; progress: ProgressState };
function createDownloadComponent(Component: ComponentType<DownloadComponentProps>): ComponentType<Props> {
return function DownloadComponent({ src, children }: Props): JSX.Element {
const [progress, setProgress] = useState<ProgressState>({ loading: false, progress: 0 });
useEffect(() => {
instance.subscribeToProgress(({ progress }) => setProgress((pre) => ({ ...pre, progress })));
return () => instance.abort();
}, []);
const handleOnClick = () => {
setProgress((pre) => ({ ...pre, loading: true }));
instance
.send(src)
.then((response) => MediaUtils.download(response.data))
.catch((error) => setProgress((pre) => ({ ...pre, error: HttpClient.parseError(error).message })))
.finally(() => setProgress((pre) => ({ ...pre, loading: false })));
};
return (
<Component onClick={handleOnClick} progress={progress}>
{children}
</Component>
);
};
}
UploadFileMethod
is similar than DownloadFileMethod
, both extend from the same base class ProgressiveFileMethod
. So use it like the same.
// DownloadFileMethod
abort(): void
send(endpoint: string): Promise<AxiosResponse<Blob>> // ππΌ Check this
subscribeToProgress(subscriber: ProgressSubscriber)
// UploadFileMethod
abort(): void
send(endpoint: string, formData: FormData): Promise<AxiosResponse<T>> // ππΌ The difference is here, we need the `FormData` payload for uploading.
subscribeToProgress(subscriber: ProgressSubscriber)
The HttpClient
class has an static method called parseError
for parsing errors from http calls.
(async function () {
try {
await Http.getInstance('ANOTHER_API').get('/customers');
} catch (error) {
const { code, status, message, context } = HttpClient.parseError(normalError);
// Frontend side Example
Application.showToast('error', message);
}
})();