Skip to main content

go_http 0.1.1 copy "go_http: ^0.1.1" to clipboard
go_http: ^0.1.1 copied to clipboard

Reliable HTTP client for Dart — built for control, cancellation and consistency.

go_http #

Reliable HTTP client for Dart — built for control, cancellation and consistency.

pub package License: BSD 3-Clause

go_http is a modern, cross-platform HTTP client for Dart that provides fine-grained control over requests, built-in retry mechanisms, cancellation support, and a powerful interceptor system.

✨ Features #

  • ✅ Cross-platform: Works identically on Dart CLI, Flutter Mobile/Desktop, and Web
  • ✅ Cancellation: Every request can be cancelled at any time with CancellationToken
  • ✅ Retry Policy: Smart retry with decorrelated jitter backoff (only for idempotent methods)
  • ✅ Interceptors: Request/response/error interceptors for logging, auth, etc.
  • ✅ Cookie Store: Automatic cookie management with MemoryCookieStore
  • ✅ Metrics: Built-in metrics collection with ConsoleMetricsSink
  • ✅ Type-safe: Full type safety with generics
  • ✅ Error Handling: Comprehensive error types (NetworkError, HttpResponseError, TimeoutError, CancellationError)
  • ✅ Redirects: Configurable redirect handling
  • ✅ Timeouts: Per-request timeout configuration

📦 Installation #

Add go_http to your pubspec.yaml:

dependencies:
  go_http: ^0.1.1

Then run:

dart pub get

🚀 Quick Start #

Basic GET Request #

import 'package:go_http/go_http.dart';

final client = GoHttpClient();

try {
  final response = await client.get<Uint8List>(
    Uri.parse('https://api.example.com/data'),
  );
  
  print('Status: ${response.statusCode}');
  print('Data: ${response.data?.length} bytes');
} catch (e) {
  print('Error: $e');
} finally {
  client.dispose();
}

POST Request with JSON #

import 'dart:convert';
import 'package:go_http/go_http.dart';

final client = GoHttpClient();

try {
  final response = await client.post<Uint8List>(
    Uri.parse('https://api.example.com/users'),
    data: jsonEncode({
      'name': 'John Doe',
      'email': 'john@example.com',
    }),
    options: RequestOptions(
      headers: {
        'Content-Type': 'application/json',
      },
    ),
  );
  
  print('Created: ${response.statusCode}');
  final responseData = jsonDecode(utf8.decode(response.data!));
  print('Response: $responseData');
} catch (e) {
  print('Error: $e');
} finally {
  client.dispose();
}

🎯 Core Concepts #

Request Cancellation #

Every request can be cancelled at any time using CancellationToken:

import 'dart:async';
import 'package:go_http/go_http.dart';

final client = GoHttpClient();
final cancelSource = CancellationSource();

// Cancel the request after 2 seconds
Timer(const Duration(seconds: 2), () {
  print('Cancelling request...');
  cancelSource.cancel('User cancelled');
});

try {
  final response = await client.get<Uint8List>(
    Uri.parse('https://api.example.com/slow-endpoint'),
    cancel: cancelSource.token,
  );
  
  print('Response: ${response.statusCode}');
} on CancellationError catch (e) {
  print('Request was cancelled: ${e.reason}');
} catch (e) {
  print('Error: $e');
} finally {
  cancelSource.dispose();
  client.dispose();
}

Retry Policy #

By default, go_http retries failed requests up to 3 times with decorrelated jitter backoff. Retries are only performed for idempotent methods (GET, HEAD, OPTIONS) to ensure safety.

final client = GoHttpClient(
  retryPolicy: DefaultRetryPolicy(
    maxAttempts: 5,
    baseDelay: const Duration(milliseconds: 500),
    maxDelay: const Duration(seconds: 5),
  ),
  metrics: ConsoleMetricsSink(), // See retry attempts in console
);

try {
  final response = await client.get<Uint8List>(
    Uri.parse('https://api.example.com/unstable-endpoint'),
  );
} catch (e) {
  print('Error after retries: $e');
}

Retry triggers:

  • Network errors (NetworkError)
  • Timeout errors (TimeoutError)
  • HTTP status codes: 429 (Too Many Requests), 503 (Service Unavailable), 504 (Gateway Timeout)

Interceptors #

Interceptors allow you to modify requests, responses, and handle errors. They are executed in the order they are added.

Logging Interceptor

final client = GoHttpClient(
  interceptors: [
    LoggingInterceptor(
      logRequest: true,
      logResponse: true,
      logError: true,
    ),
  ],
);

// All requests/responses will be logged
// Sensitive headers (authorization, cookie, etc.) are automatically masked

Auth Interceptor

Automatically add authentication tokens and refresh them when needed:

String? authToken;

final client = GoHttpClient(
  interceptors: [
    AuthInterceptor(
      tokenProvider: () async => authToken,
      tokenRefresher: () async {
        // Refresh token logic
        final newToken = await refreshAuthToken();
        authToken = newToken;
        return newToken;
      },
      headerName: 'Authorization',
      headerPrefix: 'Bearer ',
    ),
  ],
);

Custom Interceptor

Create your own interceptors:

class RequestIdInterceptor extends Interceptor {
  @override
  Future<Request> onRequest(Request request) async {
    final headers = Map<String, String>.from(request.headers);
    headers['X-Request-ID'] = _generateRequestId();
    return request.copyWith(headers: headers);
  }

  String _generateRequestId() {
    return DateTime.now().millisecondsSinceEpoch.toString();
  }
}

final client = GoHttpClient(
  interceptors: [
    RequestIdInterceptor(),
    LoggingInterceptor(),
  ],
);

Error Handling #

go_http provides comprehensive error types:

try {
  final response = await client.get<Uint8List>(uri);
} on NetworkError catch (e) {
  // Network issues (connection timeout, DNS failure, etc.)
  print('Network error: ${e.message}');
} on HttpResponseError catch (e) {
  // HTTP error responses (4xx, 5xx)
  print('HTTP ${e.statusCode}: ${e.message}');
} on TimeoutError catch (e) {
  // Request timeout
  print('Timeout after ${e.timeout.inSeconds}s');
} on CancellationError catch (e) {
  // Request was cancelled
  print('Cancelled: ${e.reason}');
} catch (e) {
  // Other errors
  print('Unexpected error: $e');
}

Automatic cookie handling with MemoryCookieStore:

final client = GoHttpClient(
  cookieStore: MemoryCookieStore(),
);

// Cookies are automatically stored from responses
// and added to subsequent requests for the same domain
final response = await client.get<Uint8List>(
  Uri.parse('https://example.com/login'),
);

// Cookies from login response are now stored
// and will be sent with subsequent requests

You can also create custom cookie stores:

class PersistentCookieStore implements CookieStore {
  // Implement persistent storage (file, database, etc.)
  @override
  List<String> getCookies(Uri uri) {
    // Load cookies from storage
  }

  @override
  void setCookies(Response response) {
    // Save cookies to storage
  }

  @override
  void clear() {
    // Clear all cookies
  }

  @override
  void clearDomain(String domain) {
    // Clear cookies for specific domain
  }
}

Metrics #

Track request metrics with ConsoleMetricsSink:

final client = GoHttpClient(
  metrics: ConsoleMetricsSink(),
);

// Metrics will be logged:
// - Request start
// - Request completion
// - Retry attempts
// - Errors

You can also create custom metrics sinks:

class CustomMetricsSink implements MetricsSink {
  @override
  void onRequestStart(Request request) {
    // Track request start
  }

  @override
  void onRequestEnd(Request request, Response response) {
    // Track request completion
  }

  @override
  void onRetry(Request request, int attempt, Duration delay) {
    // Track retry attempts
  }

  @override
  void onError(HttpError error) {
    // Track errors
  }
}

⚙️ Configuration #

Full Configuration Example #

final client = GoHttpClient(
  // Transport (auto-detected by platform)
  // transport: IoTransport() or WebTransport(),
  
  // Interceptors
  interceptors: [
    LoggingInterceptor(),
    AuthInterceptor(/* ... */),
  ],
  
  // Retry policy
  retryPolicy: DefaultRetryPolicy(
    maxAttempts: 3,
    baseDelay: const Duration(milliseconds: 300),
    maxDelay: const Duration(milliseconds: 2000),
  ),
  
  // Redirect policy
  redirectPolicy: DefaultRedirectPolicy(
    maxRedirects: 5,
  ),
  
  // Cookie store
  cookieStore: MemoryCookieStore(),
  
  // Timeouts
  connectTimeout: const Duration(seconds: 10),
  sendTimeout: const Duration(seconds: 30),
  receiveTimeout: const Duration(seconds: 30),
  
  // Redirects
  followRedirects: true,
  maxRedirects: 5,
  
  // Other options
  autoDecompress: true,
  defaultHeaders: {
    'User-Agent': 'my-app/1.0',
    'Accept': 'application/json',
  },
  
  // Metrics
  metrics: ConsoleMetricsSink(),
);

Per-Request Options #

You can override client settings for individual requests:

final response = await client.get<Uint8List>(
  Uri.parse('https://api.example.com/data'),
  options: RequestOptions(
    headers: {
      'X-Custom-Header': 'value',
    },
    connectTimeout: const Duration(seconds: 5),
    receiveTimeout: const Duration(seconds: 10),
  ),
);

📚 Examples #

See the example/ directory for complete examples:

  • simple_get.dart - Basic GET request
  • cancel_request.dart - Request cancellation
  • retry_policy.dart - Custom retry policy with metrics
  • download_progress.dart - File download

Running Examples #

# Simple GET request
dart run example/simple_get.dart

# Cancel request example
dart run example/cancel_request.dart

# Retry policy example
dart run example/retry_policy.dart

# Download example
dart run example/download_progress.dart

🔧 Advanced Usage #

Custom Transport #

You can provide a custom transport implementation:

class CustomTransport implements Transport {
  @override
  Future<Response> send(
    Request request, {
    CancellationToken? cancel,
    // ... other parameters
  }) async {
    // Custom implementation
  }

  @override
  void dispose() {
    // Cleanup
  }
}

final client = GoHttpClient(
  transport: CustomTransport(),
);

Type-Safe Responses #

Use generics for type-safe responses:

// Get raw bytes
final bytesResponse = await client.get<Uint8List>(uri);

// Get as string (you'll need to decode)
final stringResponse = await client.get<Uint8List>(uri);
final text = utf8.decode(stringResponse.data!);

// Use decoders for automatic conversion
final jsonDecoder = JsonDecoder();
final response = await client.get<Uint8List>(uri);
final jsonData = jsonDecoder.decode(response.data!);

Response Decoders #

go_http provides decoders for common response formats:

JSON Decoder

import 'package:go_http/go_http.dart';

final jsonDecoder = JsonDecoder();
final response = await client.get<Uint8List>(uri);

// Automatically decode JSON from bytes or string
final jsonData = jsonDecoder.decode(response.data!);
print(jsonData['key']); // Access decoded JSON

Bytes Decoder

import 'package:go_http/go_http.dart';

final bytesDecoder = BytesDecoder();
final response = await client.get<Uint8List>(uri);

// Ensure data is Uint8List
final bytes = bytesDecoder.decode(response.data!);

Custom Decoder

You can create your own decoders:

class XmlDecoder implements Decoder<String> {
  @override
  String decode(dynamic data) {
    if (data is String) {
      return data;
    } else if (data is Uint8List) {
      return utf8.decode(data);
    }
    throw ArgumentError('Cannot decode to XML string');
  }
}

Redirect Policy #

Control how redirects are handled:

final client = GoHttpClient(
  redirectPolicy: DefaultRedirectPolicy(
    maxRedirects: 10, // Allow up to 10 redirects
  ),
  followRedirects: true,
);

// Custom redirect policy
class CustomRedirectPolicy implements RedirectPolicy {
  @override
  int get maxRedirects => 3;

  @override
  bool shouldFollowRedirect(
    Request request,
    Response response,
    int redirectCount,
  ) {
    // Only follow redirects for specific status codes
    return response.statusCode == 301 || response.statusCode == 302;
  }
}

🛡️ Security #

  • Retries: Only performed for idempotent HTTP methods (GET, HEAD, OPTIONS)
  • Sensitive Data: Headers like authorization, cookie, x-api-key are automatically masked in logs
  • TLS: TLS verification is enabled by default
  • Timeouts: Timeouts are always active to prevent hanging requests

🌐 Platform Support #

Platform Transport Status
Dart CLI / Server IoTransport (dart:io) ✅ Fully supported
Flutter Mobile/Desktop IoTransport (dart:io) ✅ Fully supported
Flutter Web WebTransport (dart:html) ✅ Fully supported

The appropriate transport is automatically selected based on the platform using conditional imports. This ensures that:

  • Native platforms (Dart CLI, Flutter Mobile/Desktop) use IoTransport with dart:io
  • Web platforms (Flutter Web) use WebTransport with dart:html
  • No platform-specific code is required in your application

The library uses Dart's conditional imports (if (dart.library.io) and if (dart.library.html)) to automatically select the correct transport implementation. Stub classes are provided for platforms where a transport is not available, ensuring the code compiles on all platforms without any additional configuration.

📖 API Reference #

GoHttpClient #

Main HTTP client class.

Methods:

  • Future<Response<T>> get<T>(Uri url, {RequestOptions? options, CancellationToken? cancel})
  • Future<Response<T>> post<T>(Uri url, {Object? data, RequestOptions? options, CancellationToken? cancel})
  • Future<Response<T>> request<T>(Request req, {CancellationToken? cancel})
  • void dispose() - Clean up resources

CancellationSource #

Source for creating cancellation tokens.

Methods:

  • CancellationToken get token - Get the cancellation token
  • void cancel([String? reason]) - Cancel the token
  • void dispose() - Clean up resources

DefaultRetryPolicy #

Default retry policy with decorrelated jitter backoff.

Parameters:

  • maxAttempts (default: 3) - Maximum number of retry attempts
  • baseDelay (default: 300ms) - Base delay for backoff
  • maxDelay (default: 2000ms) - Maximum delay between retries

🤝 Contributing #

Contributions are welcome! Please feel free to submit a Pull Request.

📄 License #

This project is licensed under the BSD 3-Clause License.

🙏 Acknowledgments #

Inspired by modern HTTP clients like axios, requests, and http package, but built specifically for Dart with focus on cancellation, retry policies, and cross-platform consistency.


Made with ❤️ for the Dart community

1
likes
0
points
35
downloads

Publisher

unverified uploader

Weekly Downloads

Reliable HTTP client for Dart — built for control, cancellation and consistency.

Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

meta

More

Packages that depend on go_http