endpoint_lens 0.2.0
endpoint_lens: ^0.2.0 copied to clipboard
A debug-only Flutter inspector. Attach Dio once, then long-press anywhere to see recent API activity.
API Lens #
Created and maintained by Nehal Elsamoly
Add API Lens once. Run your Flutter app in debug. Long-press anywhere to inspect recent API activity.
API Lens is a debug-only network inspector for Flutter apps that use Dio. It helps Flutter developers, backend engineers, and QA engineers see the requests the app just made without searching the codebase and without wrapping individual widgets.
- GitHub: https://github.com/NehalElsamoly
- LinkedIn: https://www.linkedin.com/in/nehal-elsamoly-5a6977202/
- Package: https://pub.dev/packages/endpoint_lens
- Repository: https://github.com/NehalElsamoly/endpoint-lens
No widget wrapping is required for basic usage. No API_LENS dart-define is required. Debug sessions turn the tool on. Profile and release builds leave it off.
Global mode shows recent API traffic, and the current route when you opt in. It cannot know which arbitrary widget owns an endpoint. A call may have been started by a Bloc, use case, or repository long before the long press.
Installation #
dependencies:
endpoint_lens: ^0.2.0
import 'package:dio/dio.dart';
import 'package:endpoint_lens/endpoint_lens.dart';
final dio = Dio();
void main() {
ApiLens.init(dio: dio);
runApp(const MyApp());
}
Use that same dio instance everywhere the app makes requests. API Lens does not create a second client.
Then:
flutter run
Long-press anywhere in the app for about 700ms.
API Lens
Recent requests
GET /notifications
200 • 121 ms
Last: 2s ago
That is the whole basic setup.
flutter run --release, flutter build apk --release, and flutter build appbundle --release do not enable API Lens. You do not remove the ApiLens.init call before shipping.
What you will see #
The sheet lists recent calls, newest first. Each row shows the method, path, status, duration, and how long ago it finished. Repeats of the same method and path collapse into one row with a call count.
Filters: All, GET, POST, PUT, PATCH, DELETE, and Errors.
Open a row for the full URL, status, duration, timestamp, query parameters, and the route name if one was known when the request started. Copy the endpoint, the full URL, or a cURL command. Secrets are redacted. Request and response bodies are not stored, so they are not copied.
If nothing finished in the last 15 seconds, the sheet shows earlier history instead of an empty screen.
A request that starts within 1.5 seconds of a tap can be labeled Likely related. That is a hint about timing. It is not proof that a widget triggered the call.
Optional route names #
Basic inspection works without a navigator observer. Add one when you want the current screen name and a split between requests that started on that route and other recent requests:
MaterialApp(
navigatorObservers: [ApiLensNavigatorObserver()],
home: const HomePage(),
)
Only RouteSettings.name is shown. Unnamed routes stay blank. API Lens does not invent a class name such as HomeScreen.
GoRouter, auto_route, and other Router setups should pass ApiLensNavigatorObserver to the navigator they actually use. Tab switches inside one route do not change the route name. Long press still shows recent requests without the observer.
If the app's navigator is hard to find, pass the key you already give MaterialApp:
final navigatorKey = GlobalKey<NavigatorState>();
ApiLens.init(dio: dio, navigatorKey: navigatorKey);
MaterialApp(
navigatorKey: navigatorKey,
)
Most MaterialApp and CupertinoApp trees do not need the key. API Lens looks up the navigator when the long press completes.
More than one Dio client #
ApiLens.init(dio: apiDio);
ApiLens.attach(uploadDio);
Attaching the same client twice does nothing.
Debug and release #
| Command | API Lens |
|---|---|
flutter run |
On |
flutter test |
On |
flutter run --profile |
Off |
flutter run --release |
Off |
flutter build apk --release |
Off |
flutter build appbundle --release |
Off |
When the tool is off it does not store history, does not install a pointer listener, does not add an interceptor, and does not build inspector UI. ApiLens.init returns immediately.
Configuration #
Defaults are enough for normal use. Override them only when you need to:
ApiLens.init(
dio: dio,
config: const ApiLensConfig(
longPressDuration: Duration(milliseconds: 700),
recentWindow: Duration(seconds: 15),
maxHistory: 200,
),
);
A pointer that moves more than 18 logical pixels cancels the long press, so taps, scrolls, and drags keep working.
Redaction #
Authorization, proxy authorization, cookies, API keys, passwords, passcodes, OTPs, access tokens, refresh tokens, and similar fields are replaced with [REDACTED] before anything is stored. Extra names are added to those defaults; they cannot turn the defaults off.
ApiLens.init(
dio: dio,
config: ApiLensConfig(
redactHeaders: <String>['X-Custom-Secret'],
redactFields: <String>['pin'],
),
);
cURL is built from the redacted URL and headers. It does not include a request body. Response bodies are never read.
Path segments are kept, so /users/123 stays visible. Do not put secrets in the path.
Advanced: exact mapping #
You do not need this for the global inspector. Use it only when you want a specific call tagged with a feature id.
await ApiLens.track(
feature: 'profile',
request: () => dio.get('/users/1'),
);
dio.get('/users/1', options: ApiLens.options('profile'));
ApiLens.track follows async/await that starts inside the callback. It does not follow a Bloc or Cubit handler, a Riverpod rebuild, or an isolate. For those, tag the repository method that calls Dio, or pass ApiLens.options.
ApiLensWidget is an optional long-press target for one feature. It is not required around cards, buttons, or screens.
Migrating from 0.1.x #
0.1.x asked you to tag features and wrap widgets, and it used an API_LENS dart-define. 0.2.0 records the Dio client you pass to ApiLens.init and opens from a long press anywhere while the app is running in debug mode. Delete the dart-define and the wrappers unless you still want the advanced feature tags.
Example #
cd example
flutter run
The example loads Home, Products, and Profile through one Dio client and a local mock. Long-press any screen. The Advanced page is the only place that uses exact feature mapping.
Author & Maintainer #
Nehal Elsamoly
Creator and maintainer of API Lens.