peek_dio

Reports the calls Dio makes to Peek, so they can be read inside the app.

Peek records the call, it does not take part in it. This package hands Dio's view of a call over and nothing more: the request goes on as it arrived, and so does the response.

Install

dependencies:
  peek: ^1.0.0
  peek_dio: ^1.0.0

Use

Two lines, once, where the client is built:

final dio = Dio(BaseOptions(baseUrl: 'https://api.example.com'));
dio.interceptors.add(PeekDioInterceptor(Peek.instance));

Peek.instance is the default instance, created on first use. An app that wants its own — with different limits, or one per client — passes it instead:

final peek = Peek(options: PeekOptions(enabled: kDebugMode));
dio.interceptors.add(PeekDioInterceptor(peek));

Then show it, from a debug menu or a shake:

showPeek(context, peek: peek);

The compiled version of these lines lives in example/lib/dio_setup.dart.

Add it last

Interceptors run in the order they were added. Added last, Peek reports the call as it went out — with the tokens and correlation ids the interceptors before it put on the request. Added first, it would report the call as it was written. LogInterceptor asks for the same place, for the same reason.

dio.interceptors
  ..add(AuthInterceptor())
  ..add(RetryInterceptor())
  ..add(PeekDioInterceptor(peek)); // last

A retry interceptor that builds fresh RequestOptions produces a second entry, because a second call is what happened.

What is not captured

  • Streamed bodies. A request or response Dio never buffers is marked as streamed rather than read: reading it would consume the stream the app is about to use.
  • File contents in a FormData. Only the part's name, file name, media type and size are kept.
  • Anything past the limits. A body larger than PeekLimits.maxBodyBytes is truncated, and the entry says so.

Redaction

Peek shows a call as it happened: nothing is masked unless the app asks. What is hidden is Peek's decision, not the adapter's, so it is configured on the instance and applies to every adapter at once. The default policy covers the usual names — Authorization, Cookie, token, password and their relatives:

final peek = Peek(
  options: const PeekOptions(redaction: PeekRedactionPolicy()),
);

Every set of names replaces the built-in one rather than adding to it, so extend a set by spreading the defaults back in:

PeekRedactionPolicy(
  headerNames: {...PeekRedactionPolicy.defaultHeaderNames, 'x-api-key'},
  bodyKeys: {...PeekRedactionPolicy.defaultBodyKeys, 'pin'},
)

Masking runs before anything is stored, so a masked value never reaches the screen, the clipboard or an exported file. Worth turning on wherever a log leaves the device — a HAR attached to an issue, a screenshot in a chat.

See the repository README for the full picture.

Libraries

peek_dio
Reports the calls Dio makes to Peek.