sonic 1.3.0 copy "sonic: ^1.3.0" to clipboard
sonic: ^1.3.0 copied to clipboard

A fluent interface for handling network requests.

⚡ Sonic

An HTTP Client with a fluent interface and improved type support.

pub version pub points license MIT

Blazingly simple, production-ready networking on top of Dio — with smart caching, retries, dedup, and observability.


✨ Features #

  • ✨ Fluent interface and typed decoders (cached per type)
  • 🔁 Retries with backoff, jitter, and Retry-After; 429-aware
  • 🧠 Caching: in-memory TTL+LRU, SWR, ETag/Last-Modified/Expires
  • 🤝 Request deduplication for identical in-flight GETs
  • 🧑‍💻 Per-host rate limiting (token bucket) with priority
  • 🛡️ Circuit breaker per host with event hooks
  • 🧩 Templates for reusable request presets
  • 📊 Observability: detailed response.extra metrics
  • 📤 Fluent uploads (multipart, fields/files)
  • 📄 Pagination utilities (Link headers, cursors, adapters, Paged
  • 🧭 Per-request API versioning with {baseUrl} placeholders

📦 Install #

Use your preferred tool:

# Dart
dart pub add sonic

# Flutter
flutter pub add sonic

🚀 Getting Started #

See the Quickstart in the Wiki: Getting Started

🔧 Usage #

Minimal example:

// Create the client (initialize() is called automatically in this ctor)
final sonic = Sonic.initialize(
  baseConfiguration: const BaseConfiguration(baseUrl: 'https://api.example.com'),
);

// Typed GET with a decoder
final res = await sonic
  .create<User>(url: '/users/1')
  .withMethod(HttpMethod.get)
  .withDecoder((j) => User.fromJson(j as Map<String, dynamic>))
  .execute();

if (res.isSuccess) {
  final user = res.data; // User
}

📚 Wiki #

Deep dives are available in the wiki:

  • Pagination
  • Circuit breaker and health probe
  • Templates
  • Stage timers and response metrics
  • Rate limiting and priorities

🧭 API Versioning #

If you work with multiple API versions from the same client, configure versioned base URLs and select the version per request:

final sonic = Sonic.initialize(
  baseConfiguration: const BaseConfiguration(
    baseUrl: 'https://api.example.com',
    apiVersions: {
      // You can avoid repetition with the {baseUrl} placeholder
      'v1': '{baseUrl}/v1',
      'v2': '{baseUrl}/v2',
    },
  ),
);

// This request goes to https://api.example.com/v2/users
final res = await sonic
  .create<User>(url: '/users')
  .withApiVersion('v2')
  .withMethod(HttpMethod.get)
  .withDecoder((j) => User.fromJson(j as Map<String, dynamic>))
  .execute();

When no version is selected (or the key is unknown), the default baseUrl is used.

Supported placeholders inside apiVersions values: {baseUrl}, {origin}, {scheme}, {host}, {port}, {basePath}, {version}.

Advanced: You can also resolve {env:NAME} via optional flags in BaseConfiguration:

  • envPlaceholdersFromDartDefines: reads String.fromEnvironment(NAME)
  • envPlaceholdersFromProcessEnv: reads Platform.environment[NAME]

See the Wiki: API Versioning

📝 Notes #

  • You can bypass type parsing by using withRawRequest() and typing as dynamic.
  • Decoders are cached per type; after first registration, you typically don’t need to pass them again.
  • URLs can be relative (resolved against baseUrl) or absolute.
  • If debugMode is true, a LogInterceptor is added to the internal Dio client to log requests/responses.
  • You can have multiple Sonic instances, but a single shared instance via DI is recommended for most apps.
  • For uploads, use multipart FormData and MultipartFile (see the Uploads wiki page).

🧪 Example #

🔍 Check a runnable example in example/sonic_example.dart.

📄 License #

📄 MIT © Arun Prakash. See LICENSE.

🙌 Contributions #

Contributions are always welcome!

2
likes
140
points
27
downloads

Publisher

verified publisherarunprakashg.com

Weekly Downloads

A fluent interface for handling network requests.

Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (license)

Dependencies

collection, dio, http_parser, meta, path, synchronized

More

Packages that depend on sonic