requestURL method

Future<HttpResponse> requestURL(
  1. HttpClient? httpClient,
  2. HttpMethod method,
  3. String requestURL, {
  4. Credential? authorization,
  5. Map<String, String?>? queryParameters,
  6. Object? body,
  7. String? contentType,
  8. String? accept,
  9. OnCachedResponse? onStaleResponse,
  10. Duration? staleResponseDelay,
})

Does a cached request using httpClient and requestURL.

  • authorization a Credential for authorization.
  • queryParameters the request query parameters.
  • body the request body.
  • contentType the Content-Type header of the request body.
  • accept the Accept header.
  • onStaleResponse function to call when a stale response (already cached) is available to use while requesting a new response.
  • staleResponseDelay a delay to call onStaleResponse function. If the new response arrives before this delay, no call to onStaleResponse will be performed.

Implementation

Future<HttpResponse> requestURL(
  HttpClient? httpClient,
  HttpMethod method,
  String requestURL, {
  Credential? authorization,
  Map<String, String?>? queryParameters,
  Object? body,
  String? contentType,
  String? accept,
  OnCachedResponse? onStaleResponse,
  Duration? staleResponseDelay,
}) async {
  httpClient ??= HttpClient(requestURL);

  var cacheRequest = _CacheRequest(
    method,
    requestURL,
    queryParameters,
    body,
    contentType,
    accept,
    authorization,
  );

  var cachedEntry = _cache[cacheRequest];

  HttpResponse? cachedResponse;
  if (cachedEntry != null) {
    var cachedRequest = cachedEntry.request;
    cachedResponse = cachedEntry.response;

    if (cachedRequest.isValid(timeout.inMilliseconds)) {
      cachedRequest.updateAccessTime();

      if (verbose) {
        _log('Cached request: $method > $requestURL > $cachedResponse');
      }

      return cachedResponse;
    }
  }

  Completer<HttpResponse?>? cachedAvailableDelayed;
  if (onStaleResponse != null && cachedResponse != null) {
    if (staleResponseDelay != null && staleResponseDelay.inMilliseconds > 1) {
      cachedAvailableDelayed = Completer<HttpResponse?>();

      // ignore: unawaited_futures
      cachedAvailableDelayed.future.then((cachedResponse) {
        if (cachedResponse != null) {
          onStaleResponse(cachedResponse);
        }
      });

      Future.delayed(staleResponseDelay, () {
        if (!cachedAvailableDelayed!.isCompleted) {
          cachedAvailableDelayed.complete(cachedResponse);
        }
      });
    } else {
      onStaleResponse(cachedResponse);
    }
  }

  var ret = httpClient.requestURL(
    method,
    requestURL,
    authorization: authorization,
    queryParameters: queryParameters,
    body: body,
    contentType: contentType,
    accept: accept,
  );

  var response = await ret;

  if (cachedAvailableDelayed != null && !cachedAvailableDelayed.isCompleted) {
    cachedAvailableDelayed.complete(null);
  }

  // A network or server error is not cached (a stale response, if any, is
  // kept): the next request tries again.
  if (response.isStatusNetworkError || response.isStatusServerError) {
    return response;
  }

  var entry = _CacheEntry(cacheRequest, response);

  // Without the expired entry of this request: not counted as used memory.
  _removeEntry(cacheRequest);
  ensureCacheBelowMaxMemory(entry.memory);

  _putEntry(entry);

  if (verbose) _log('Used memory: $_usedMemory / $maxCacheMemory');

  return response;
}