@uphillhealth/react-service-provider
v1.3.1
Published
UpHill Health library proving service abstraction for react applications using Axios and TanStack Query
Readme
lib-ts-react-service-provider
aka react-service-provider
Installation
npm install --save-dev @uphillhealth/lib-ts-react-service-provider@latest @tanstack/react-query@latest axios@latest
Verify the minimal versions of react, react-dom, @tanstack/react-query and axios at package.json peerDependencies.
Service class
Provides request and useQuery abstractions.
Service.request
Abstracts an axios.request that never throws if the request occurs to fail, it is already handled internally.
It returns a customized response that you can see below:
interface ServiceResponse<ResponseData> {
data?: ResponseData;
error?: AxiosError<ServiceResponseError>;
headers?: AxiosResponseHeaders | RawAxiosResponseHeaders;
status?: number;
}Service.useQuery
Abstract react-query.useQuery with an axios.request as queryFn to be used as a hook at react components.
It returns the generic type provided as its data.
In the case that the request fails it returns
AxiosError<ServiceResponseError>data structure for both abstractions.interface ServiceResponseError { additionalInformation: string | null; constraints: Record<string, string>; error: string; errorNumber: number; status: number; statusMessage: string; timeStamp: number; }
Service.useMutation
Abstract react-query.useMutation with an axios.request as mutationFn to be used as a hook at react components.
It returns the generic type provided as its data.
In the case that the request fails it returns
AxiosError<ServiceResponseError>data structure for both abstractions.interface ServiceResponseError { additionalInformation: string | null; constraints: Record<string, string>; error: string; errorNumber: number; status: number; statusMessage: string; timeStamp: number; }
Creating a new service
import { Service } from '@uphillhealth/react-service-provider';
interface GetJourneyResponse {
pathwayId: string
}
interface PutPatientSessionRequestData {
language: string
}
export class PatientSessionService extends Service {
// using request abstraction
public putPatientSession(data: PutPatientSessionRequestData) {
return this.request<unknown, PutPatientSessionRequestData>({
data,
method: 'PUT',
url: `/patient-session/[institutionId]/[pathwayId]/[journeyId]`,
});
}
// The usage would be:
// PatientSessionService.putPatientSession().then(({ data, error, headers, status }) => { if(error){} else{} })
// or
// const { data, error, headers, status } = await PatientSessionService.putPatientSession()
// using useQuery abstraction
public useGetJourney() {
return this.useQuery<GetJourneyResponse>({
method: 'GET',
url: `/patient-session/[institutionId]/[pathwayId]/[journeyId]`,
});
}
// The usage would be:
// const { data, error, isLoading } = PatientSessionService.useGetJourney()
}
export class SmsReceiverService extends Service {
// using useMutation abstraction using abstracted data only
public usePostJourney() {
return this.useMutation<unknown, { comment: string }>({
method: 'PUT',
url: '/interactions/[institutionId]/inbound-records/[inboundRecordId]/comment',
});
}
// The usage would be:
// const usePostJourney = smsReceiverService.usePostJourney()
// usePostJourney.mutate({ comment: 'lorem ipsum' })
// using useMutation abstraction using params only
public usePostJourney() {
return this.useMutation<unknown, { params: { status: 'A' | 'B' | 'C' } }, unknown>({
method: 'PUT',
url: '/interactions/[institutionId]/inbound-records/[inboundRecordId]/status',
});
}
// The usage would be:
// const usePostJourney = SmsReceiverService.usePostJourney()
// usePostJourney.mutate({ params: { status: 'A' } })
}ServiceProvider
It handles react-query client provider and services initialization as singleton.
import { ServiceProvider } from '@uphillhealth/react-service-provider';
import { PathwayService, PatientSessionService } from '@/src/services'
export const App = () => {
const services = [PathwayService, PatientSessionService]
const serviceConfigurations: ServiceConfigurations = {
baseUrl: '/',
};
return (
<ServiceProvider
institutionId={182}
language="en" // it should be the language provided by I18n library
services={services}
serviceConfigurations={serviceConfigurations}>
<RestOfTheApp />
</ServiceProvider>
);
};useServices hook
Access your services directly by its name.
import { useServices } from '@uphillhealth/react-service-provider';
// one service
const SomeContainer1 = (): ReactElement => {
const [patientSessionService] = useServices(PatientSessionService) as [PatientSessionService];
// you can inject service specific props that later will be replaced at url
patientSessionService.serviceProps = { journeyId, pathwayId }
const useGetJourney = patientSessionService.useGetJourney();
return (
<div />
);
};
// multiple services
const SomeContainer2 = (): ReactElement => {
const [pathwayService, patientSessionService] = useServices([PathwayService, PatientSessionService]) as [PathwayService, PatientSessionService];
// you can inject service specific props that later will be replaced at url
pathwayService.serviceProps = { pathwayId }
patientSessionService.serviceProps = { journeyId, pathwayId }
const usePathwayRead = pathwayService.usePathwayRead()
const useGetJourney = patientSessionService.useGetJourney();
return (
<div />
);
};