Skip to content

flint-dart/flint-client

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

21 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

flint_client

Pub Version License: MIT Dart

Official Dart client for the Flint framework.
Developed and maintained by Eulogia.

A powerful, feature-rich HTTP client for Dart and Flutter with built-in caching, retry mechanisms, interceptors, and customizable status code handling.


πŸš€ Features

  • πŸ”„ Smart Retry Logic: Configurable retry with exponential backoff and jitter
  • πŸ’Ύ Built-in Caching: Memory cache with configurable TTL and freshness ratios
  • 🎯 Customizable Status Codes: Define your own success/error/redirect status mappings
  • πŸ“ File Upload/Download: Multipart form support with progress tracking
  • πŸ”§ Interceptors: Request/response interceptors for authentication and logging
  • ⏱️ Progress Tracking: Real-time upload/download progress callbacks
  • πŸ›‘οΈ Type Safety: Generic response types with custom JSON parsers
  • πŸ› Debug Logging: Comprehensive debug output for development
  • πŸ“¦ Zero Dependencies: Pure Dart implementation

πŸ“¦ Installation

Add this to your pubspec.yaml:

dependencies:
  flint_client:
    git:
      url: https://github.com/flint-dart/flint-client.git

Then run:

dart pub get

πŸ”§ Quick Start

Basic Usage

import 'package:flint_client/flint_client.dart';

void main() async {
  final client = FlintClient(
    baseUrl: "https://api.example.com",
    debug: true, // Enable debug logging
  );

  final response = await client.get<User>("/users/1",
    parser: (json) => User.fromJson(json),
  );

  if (response.isSuccess) {
    print("User: ${response.data}");
  } else {
    print("Error: ${response.error}");
  }

  client.dispose();
}

Advanced Configuration

final client = FlintClient(
  baseUrl: "https://api.example.com",
  headers: {
    'Authorization': 'Bearer your-token',
    'Content-Type': 'application/json',
  },
  timeout: Duration(seconds: 30),
  debug: true,
  statusCodeConfig: StatusCodeConfig.custom(
    successCodes: {200, 201, 204},
    errorCodes: {400, 401, 403, 404, 422, 500},
    redirectCodes: {301, 302},
  ),
  onError: (error) {
    print('Request failed: ${error.message}');
  },
);

πŸ“š Usage Examples

GET Request with Caching

final response = await client.get<List<Product>>(
  '/products',
  cacheConfig: CacheConfig(
    maxAge: Duration(minutes: 10),
    forceRefresh: false,
  ),
  parser: (json) {
    if (json is List) {
      return json.map((item) => Product.fromJson(item)).toList();
    }
    return [];
  },
);

POST Request with JSON Body

final response = await client.post<Product>(
  '/products',
  body: {
    'title': 'New Product',
    'price': 29.99,
    'category': 'electronics',
  },
  parser: (json) => Product.fromJson(json),
);

File Upload with Progress

final response = await client.post<Map<String, dynamic>>(
  '/upload',
  files: {
    'image': File('path/to/image.jpg'),
  },
  onSendProgress: (sent, total) {
    final progress = (sent / total * 100).round();
    print('Upload progress: $progress%');
  },
);

Custom Status Code Handling

// For APIs that use non-standard status codes
final customConfig = StatusCodeConfig.custom(
  successCodes: {200, 201, 204, 304}, // Include 304 as success
  errorCodes: {400, 401, 500}, // Only specific errors
  redirectCodes: {302, 307},
);

final response = await client.get<User>(
  '/user',
  statusConfig: customConfig,
);

if (response.isSuccess) {
  // Handle success according to your custom config
}

Error Handling with onDone Callback

final response = await client.get<User>(
  '/users/1',
  onDone: (response, error) {
    if (error != null) {
      print('Request completed with error: ${error.message}');
    } else {
      print('Request completed successfully: ${response.statusCode}');
    }
  },
);

πŸ”Œ API Reference

HTTP Methods

  • get<T>(path, {query, headers, cache, parser})
  • post<T>(path, {body, files, headers, parser})
  • put<T>(path, {body, files, headers, parser})
  • patch<T>(path, {body, files, headers, parser})
  • delete<T>(path, {headers, parser})

Configuration Options

Option Type Description
baseUrl String Base URL for all requests
headers Map<String, String> Default headers
timeout Duration Request timeout duration
debug bool Enable debug logging
statusCodeConfig StatusCodeConfig Custom status code mappings
onError ErrorHandler Global error callback
onDone RequestDoneCallback Request completion callback

Response Properties

Property Type Description
statusCode int HTTP status code
data T Response data (parsed)
isSuccess bool Whether request succeeded
isError bool Whether request failed
isRedirect bool Whether response is redirect
error FlintError Error object (if any)
headers HttpHeaders Response headers
duration Duration Request duration

πŸ› οΈ Advanced Features

Custom Interceptors

final client = FlintClient(
  baseUrl: 'https://api.example.com',
  requestInterceptor: (request) async {
    // Add auth token to all requests
    request.headers.set('Authorization', 'Bearer $token');
  },
  responseInterceptor: (response) async {
    // Log all responses
    print('Response: ${response.statusCode}');
  },
);

Retry Configuration

final response = await client.get<User>(
  '/users/1',
  retryConfig: RetryConfig(
    maxAttempts: 3,
    delay: Duration(seconds: 1),
    maxDelay: Duration(seconds: 10),
    retryStatusCodes: {500, 502, 503},
  ),
);

Cache Management

// Clear entire cache
await client.clearCache();

// Remove specific cached item
await client.removeCachedResponse('cache-key');

// Get cache size
final size = await client.cacheSize;

🎯 Status Code Configuration

Handle non-standard APIs with custom status code mappings:

// For APIs that use 200 for errors
final weirdApiConfig = StatusCodeConfig.custom(
  successCodes: {200}, // Only 200 is success
  errorCodes: {200, 400, 500}, // 200 can be error!
  redirectCodes: {302},
);

// Standard HTTP (default)
final standardConfig = StatusCodeConfig();

// Pre-defined configurations
final only200 = StatusCodeConfig.only200;
final broadSuccess = StatusCodeConfig.broadSuccess;

πŸ“– Documentation


🀝 Contributing

We love contributions! Here's how to help:

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature/amazing-feature
  3. Commit your changes: git commit -m 'Add amazing feature'
  4. Push to the branch: git push origin feature/amazing-feature
  5. Open a Pull Request

Development Setup

git clone https://github.com/flint-dart/flint-client.git
cd flint-client
dart pub get
dart test

πŸ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.


πŸ—οΈ Built With

  • Dart - Programming language
  • Flutter - UI framework (for Flutter apps)

πŸ‘₯ Maintainers


πŸ™ Acknowledgments

  • Thanks to all our contributors and users

⭐ Star this repo if you find it helpful!




About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages