RestEz

A comprehensive and easy-to-use REST API client package for Flutter applications with built-in error handling, timeout management, and web file download support.

Features

  • 🚀 Easy to use: Simple API for GET, POST, PATCH, and DELETE requests
  • 🔒 Built-in authentication: Automatic Bearer token handling
  • ⏱️ Timeout management: Configurable request timeouts
  • 🎯 Type safety: Generic responses with proper type casting
  • 📝 Error handling: Comprehensive error handling with interceptors
  • 🌐 Web support: File download and PDF printing for web platforms
  • 🔧 Configurable: Flexible configuration options
  • 📊 Logging: Optional debug logging for development

Installation

Add this to your package's pubspec.yaml file:

dependencies:
  rest_ez: ^0.1.0

Then run:

flutter pub get

Usage

Basic Setup

import 'package:rest_ez/rest_ez.dart';

void main() {
  // Initialize the client
  RestEzClient.instance.initialize(
    config: const RestEzConfig(
      baseUrl: 'https://api.example.com',
      defaultTimeout: Duration(seconds: 30),
      enableLogging: true,
    ),
  );
  
  // Set authentication token
  RestEzClient.instance.setAuthToken('your_bearer_token');
  
  runApp(MyApp());
}

Making Requests

GET Request

// Define your data model
class User {
  final int id;
  final String name;
  final String email;
  
  User({required this.id, required this.name, required this.email});
  
  factory User.fromJson(Map<String, dynamic> json) {
    return User(
      id: json['id'],
      name: json['name'],
      email: json['email'],
    );
  }
}

// Make a GET request
final response = await RestEzClient.instance.get<User>(
  endpoint: '/users/1',
  fromJson: (json) => User.fromJson(json),
  queryParameters: {'include': 'profile'},
);

if (response.success) {
  User user = response.data!;
  print('User: ${user.name}');
} else {
  print('Error: ${response.error}');
}

POST Request

final response = await RestEzClient.instance.post<User>(
  endpoint: '/users',
  body: {
    'name': 'John Doe',
    'email': 'john@example.com',
  },
  fromJson: (json) => User.fromJson(json),
);

if (response.success) {
  print('User created: ${response.data!.id}');
}

PATCH Request

final response = await RestEzClient.instance.patch<User>(
  endpoint: '/users/1',
  body: {
    'name': 'John Smith',
  },
  fromJson: (json) => User.fromJson(json),
);

DELETE Request

final response = await RestEzClient.instance.delete<void>(
  endpoint: '/users/1',
);

if (response.success) {
  print('User deleted successfully');
}

Advanced Usage

Custom Error Handling

class MyErrorInterceptor implements ErrorInterceptor {
  @override
  void handleError(EndpointResponse response) {
    // Custom error handling
    switch (response.response) {
      case ResponseType.unAuthorized:
        // Handle unauthorized access
        print('User needs to login again');
        break;
      case ResponseType.internetIssue:
        // Handle network issues
        print('Check your internet connection');
        break;
      default:
        print('An error occurred: ${response.response}');
    }
  }
  
  @override
  void handleSuccess(EndpointResponse response) {
    // Handle successful responses
    print('Request successful');
  }
}

// Initialize with custom error interceptor
RestEzClient.instance.initialize(
  config: const RestEzConfig(baseUrl: 'https://api.example.com'),
  errorInterceptor: MyErrorInterceptor(),
);

Custom Endpoints

enum MyApiEndpoint implements ApiEndpoint {
  users('/users'),
  posts('/posts'),
  comments('/comments');
  
  const MyApiEndpoint(this.path);
  
  @override
  final String path;
  
  @override
  String get name => toString().split('.').last;
}

// Use with requests
final response = await RestEzClient.instance.get<List<User>>(
  endpoint: MyApiEndpoint.users.path,
  endpointType: MyApiEndpoint.users,
  fromJson: (json) => (json as List)
      .map((item) => User.fromJson(item))
      .toList(),
);

Web File Downloads (Flutter Web only)

// Download a file
await RestEzClient.instance.downloadFileWeb(
  endpoint: '/reports/annual-report.pdf',
  filename: 'annual_report_2023.pdf',
  queryParameters: {'year': '2023'},
);

// Print a PDF
await RestEzClient.instance.printPdf(
  endpoint: '/invoices/123/pdf',
  queryParameters: {'format': 'A4'},
);

Configuration Options

const config = RestEzConfig(
  baseUrl: 'https://api.example.com',           // Required: Base URL for all requests
  defaultTimeout: Duration(seconds: 30),        // Default timeout for requests
  defaultHeaders: {                             // Default headers for all requests
    "Content-Type": "application/json",
    "Accept": "*/*",
  },
  enableTokenCheck: true,                       // Enable automatic token validation
  enableLogging: true,                          // Enable debug logging
);

Response Types

The package provides several response types for better error handling:

  • ResponseType.success - Request completed successfully
  • ResponseType.internetIssue - Network connectivity problems
  • ResponseType.unAuthorized - Authentication/authorization issues
  • ResponseType.unknownIssue - Unknown errors
  • ResponseType.serverIssue - Server-side errors
  • ResponseType.timeout - Request timeout

Error Handling

The APIResponse<T> class provides a consistent way to handle responses:

final response = await RestEzClient.instance.get<User>(...);

if (response.success) {
  // Handle successful response
  User user = response.data!;
} else {
  // Handle error
  print('Error (${response.statusCode}): ${response.error}');
}

Contributing

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

License

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

Libraries

rest_ez