my api needs time to process a request, how can I use React + SWR to continue checking on the status?

I have an endpoint in my API that initiates a process on AWS. This process takes time. It can last several seconds or minutes depending on the size of the request. As of right now, I’m rebuilding my app to use swr. However, before this new update with swr I created a recursive function that would call itself with a timeout and continuously ping the API to request the status of my AWS process, only exiting once the response had the appropriate type.

I’d like to dump that recursive function because, well … it was kinda hacky. Though, I’m still getting familiar with swr and I’m not a NodeJS API building master so I’m curious what thoughts come to mind in regards to improving the pattern below.

Ideally, the lowest hanging fruit would be to set up swr in some way to handle the incoming response and keep ping if the response isn’t type: "complete" but I’m not sure how I’d do that. It pretty much just pings once and shows me whatever status it found at that time.

any help is appreciated!

tldr;

how can I set up swr to continually ping the API until my content is finished loading?

part of my API that sends out responses based how far along the AWS process is:

 if (serviceResponse !== undefined) {
        // * task is not complete
        const { jobStatus } = serviceResponse.serviceJob;
        if (serviceJobStatus.toLowerCase() === 'in_progress') {
          return res.status(200).send({ type: 'loading', message: serviceJobStatus });
        }

        if (serviceJobStatus.toLowerCase() === 'queued') {
          return res.status(200).send({ type: 'loading', message: serviceJobStatus });
        }

        if (serviceJobStatus.toLowerCase() === 'failed') {
          return res.status(400).send({ type: 'failed', message: serviceJobStatus });
        }

        // * task is complete
        if (serviceJobStatus.toLowerCase() === 'completed') {
          const { serviceFileUri } = serviceResponse.serviceJob?.Data;
          const { data } = await axios.get(serviceUri as string);
          const formattedData = serviceDataParser(data.results);
          return res.status(200).send({ type: 'complete', message: formattedData });
        }
      } else {
        return res.status(400).send({ type: 'error', message: serviceResponse });
      }
}

my current useSWR hook:

  const { data: rawServiceData } = useSwr(
    serviceEndpoint,
    url => axios.get(url).then(r => r.data),
    {
      onSuccess: data => {
        if (data.type === 'complete') {
          dispatch(
            setStatus({
              type: 'success',
              data: data.message,
              message: 'service has been successfully generated.',
              display: 'support-both',
            })
          );
          dispatch(setRawService(data.message));
        }
        if (data.type === 'loading') {
          dispatch(
            setStatus({
              type: 'success',
              data: data.message,
              message: 'service job is in progress.',
              display: 'support-both',
            })
          );
        }
      },
    }
  );

Answer

After some digging around, figured I’d use the refreshInterval option that comes with swr. I am changing the state of a boolean on my component.

  • while the request is ‘loading’ the boolean in state is false.
  • once the job is ‘complete’ the boolean in state is set to true.

there is a ternary within my hook that sets the refreshInterval to 0 (default:off) or 3000.

const [serviceJobComplete, setServiceJobComplete] = useState(false);

  const { data: serviceData } = useSwr(
    serviceEndpoint,
    url => axios.get(url).then(r => r.data),
    {
      revalidateIfStale: false,
      revalidateOnFocus: false,
      revalidateOnReconnect: false,
      refreshInterval: serviceJobComplete ? 0 : 3000,
    ...
    // other options
    }
);

helpful resources: