flutter_axios 1.2.0 copy "flutter_axios: ^1.2.0" to clipboard
flutter_axios: ^1.2.0 copied to clipboard

A promise-based HTTP client for Flutter inspired by Axios. Provides interceptors, request/response transformation, error handling, and automatic JSON conversion.

Flutter Axios #

Documentation Languages: English | 中文 | 日本語

A powerful HTTP client for Flutter inspired by Axios.js, featuring revolutionary JSON mapping with build_runner integration.

pub package popularity likes

✨ Key Features #

  • 🚀 Zero-Code JSON Mapping - Just add @AxiosJson() annotation, no boilerplate
  • 🔧 build_runner Integration - Standard Dart ecosystem toolchain
  • 🎯 Type-Safe Requests - await api.get<User>('/users/123')
  • ⚡ 10x Development Speed - 2-3 minutes vs 20-30 minutes per model
  • 🔄 Smart Serialization - Automatic camelCase ↔ snake_case conversion
  • 📱 Flutter Optimized - No dart:mirrors, compile-time generation only
  • 🌐 Promise-based API - Familiar Axios.js experience for web developers
  • 🛡️ Comprehensive Error Handling - Network, timeout, and API errors
  • 🔌 Powerful Interceptors - Request/response transformation and logging
  • 🎨 TypeScript-like API - Familiar for web developers
  • 🔥 Hot Reload Support - Watch mode with build_runner
  • 📚 Comprehensive Documentation - Examples and guides
  • ✅ Unit Tested - Reliable and production-ready
  • 🌊 Streaming Support - Stream responses, SSE, and WebSocket connections
  • 📥 Progressive Downloads - Stream large files with progress tracking

🚀 Quick Start #

Annotation Note: We use @AxiosJson() instead of the common @JsonSerializable() to avoid conflicts with the json_annotation package while maintaining conciseness.

Installation #

Add to your pubspec.yaml:

dependencies:
  flutter_axios: ^1.2.0
  # WebSocket support is included automatically

dev_dependencies:
  build_runner: ^2.4.12

Step 1: Define Model #

Just add one annotation:

import 'package:flutter_axios/flutter_axios.dart';

@AxiosJson()  // 🎉 Concise annotation, avoids framework conflicts
class User {
  final String id;
  final String name;
  final String email;
  
  const User({required this.id, required this.name, required this.email});
}

Step 2: Generate Code #

dart run build_runner build --delete-conflicting-outputs

Step 3: Use It #

import 'package:flutter_axios/flutter_axios.dart';
import 'models/user.dart';
import 'axios_json_initializers.g.dart'; // Global initializer

void main() async {
  // 🎉 One-line initialization for all JSON mappers!
  initializeAllAxiosJsonMappers();
  
  // Create HTTP client
  final api = Axios.create(AxiosOptions(
    baseURL: 'https://api.example.com',
  ));
  
  // Type-safe HTTP requests
  final response = await api.get<List<User>>('/users');
  final users = response.data; // Already parsed as List<User>!
  
  // Create new user
  final newUser = User(id: '1', name: 'John', email: 'john@example.com');
  await api.post<User>('/users', data: newUser); // Auto-serialized!
}

🔧 Multiple Initialization Options #

import 'axios_json_initializers.g.dart';

void main() {
  // Initializes ALL @AxiosJson() classes automatically
  initializeAllAxiosJsonMappers();
  runApp(MyApp());
}

Option 2: Initialize Specific Types #

import 'axios_json_initializers.g.dart';

void main() {
  // Only initialize specific types you need
  initializeAxiosJsonMappers([User, Product, Order]);
  runApp(MyApp());
}

Option 3: Manual Initialization (Legacy) #

import 'models/user.flutter_axios.g.dart';
import 'models/product.flutter_axios.g.dart';

void main() {
  initializeJsonMapper();
  initializeUserJsonMappers();
  initializeProductJsonMappers();
  runApp(MyApp());
}

🎯 Complete CRUD Example #

Here's a real-world example using MockAPI:

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_axios/flutter_axios.dart';

// Import model and generated code
import 'models/user.dart';
import 'models/user.flutter_axios.g.dart';

void main() {
  initializeJsonMapper();
  initializeUserJsonMappers();
  runApp(MyApp());
}

class UserService {
  late final AxiosInstance _api;
  
  UserService() {
    _api = Axios.create(AxiosOptions(
      baseURL: 'https://your-api.mockapi.io',
      timeout: Duration(seconds: 10),
    ));
  }
  
  // GET - Read users
  Future<List<User>> getUsers() async {
    final response = await _api.get('/user');
    if (response.data is List) {
      final rawList = response.data as List;
      return rawList.map((item) => 
        UserJsonFactory.fromMap(item as Map<String, dynamic>)
      ).whereType<User>().toList();
    }
    return [];
  }
  
  // POST - Create user
  Future<User?> createUser(User user) async {
    final response = await _api.post<User>('/user', data: user);
    return response.data;
  }
  
  // PUT - Update user
  Future<User?> updateUser(String id, User user) async {
    final response = await _api.put<User>('/user/$id', data: user);
    return response.data;
  }
  
  // DELETE - Remove user
  Future<bool> deleteUser(String id) async {
    try {
      await _api.delete<void>('/user/$id');
      return true;
    } catch (e) {
      return false;
    }
  }
}

// Model definition (in models/user.dart)
@AxiosJson()
class User {
  final String id;
  final String name;
  final String avatar;
  final String city;

  const User({
    required this.id,
    required this.name,
    required this.avatar,
    required this.city,
  });

  User copyWith({String? id, String? name, String? avatar, String? city}) {
    return User(
      id: id ?? this.id,
      name: name ?? this.name,
      avatar: avatar ?? this.avatar,
      city: city ?? this.city,
    );
  }
}

🔧 Advanced Features #

1. Complex Nested Objects #

@AxiosJson()
class Order {
  final String id;
  final User customer;           // Nested object
  final List<Product> items;     // List of objects
  final Address? shipping;       // Nullable object
  final DateTime createdAt;      // Auto ISO8601 conversion
  final Map<String, dynamic> metadata; // Dynamic data
  
  const Order({
    required this.id,
    required this.customer,
    required this.items,
    this.shipping,
    required this.createdAt,
    this.metadata = const {},
  });
}

@AxiosJson()
class Product {
  final String id;
  final String name;
  final double price;
  final List<String> tags;
  
  const Product({required this.id, required this.name, required this.price, required this.tags});
}

2. Generated Helper Methods #

After running build_runner, you get powerful helper methods:

// Serialization
final jsonString = user.toJsonString();
final map = user.toMap();

// Deserialization
final user = UserJsonFactory.fromJsonString('{"id":"1","name":"John"}');
final users = UserJsonFactory.listFromJsonString('[{"id":"1"},{"id":"2"}]');

// From maps
final user = UserJsonFactory.fromMap({'id': '1', 'name': 'John'});
final users = UserJsonFactory.listFromMaps([{'id': '1'}, {'id': '2'}]);

3. Interceptors with Auto JSON Handling #

class LoggingInterceptor extends Interceptor {
  @override
  Future<AxiosRequest> onRequest(AxiosRequest request) async {
    print('🚀 ${request.method} ${request.url}');
    if (request.data != null) {
      // Data is automatically serialized
      print('📤 ${request.data}');
    }
    return request;
  }

  @override
  Future<AxiosResponse> onResponse(AxiosResponse response) async {
    print('✅ ${response.status} ${response.request.url}');
    // Response data is automatically parsed
    print('📥 ${response.data}');
    return response;
  }
}

final api = Axios.create(AxiosOptions(baseURL: 'https://api.example.com'));
api.interceptors.add(LoggingInterceptor());

4. Error Handling #

try {
  final user = await api.get<User>('/users/123');
  print('User: ${user.data?.name}');
} on AxiosError catch (e) {
  if (e.type == AxiosErrorType.timeout) {
    print('Request timeout');
  } else if (e.response?.status == 404) {
    print('User not found');
  } else {
    print('Error: ${e.message}');
  }
}

5. Streaming Features 🌊 #

Stream Responses

// Stream large responses line by line
final response = await api.getStream('/large-data');
await for (final line in response.dataStream) {
  print('Received: $line');
}

Progressive Downloads

// Download with progress tracking
final downloadStream = api.downloadStream('/large-file.zip');
await for (final progress in downloadStream) {
  print('Downloaded: ${progress.progressPercent?.toStringAsFixed(1)}%');
  print('Speed: ${progress.speed != null ? (progress.speed! / 1024).toStringAsFixed(1) : "?"} KB/s');
}

Server-Sent Events (SSE)

// Real-time server events
final sseStream = api.connectSSE('/events');
await for (final event in sseStream) {
  print('Event: ${event.event} - Data: ${event.data}');
}

WebSocket Connections

// Bidirectional real-time communication
final wsStream = api.connectWebSocket('/ws');
await for (final message in wsStream) {
  if (message.type == WebSocketMessageType.text) {
    print('Received: ${message.data}');
  }
}

🔄 Development Workflow #

dart run build_runner watch --delete-conflicting-outputs

This watches for changes and automatically regenerates code when you modify your models.

Build Once #

dart run build_runner build --delete-conflicting-outputs

Clean Generated Files #

dart run build_runner clean

📊 Performance Comparison #

Feature Manual JSON json_serializable flutter_axios
Development Time 20-30 min/model 10-15 min/model 2-3 min/model
Code Lines 80-120 lines 40-60 lines 0 user lines
Type Safety Manual Complete Complete
Hot Reload Manual Rebuild needed Watch mode
Framework Conflicts None Possible None
Learning Curve High Medium Low
Streaming Support Manual None Built-in
Real-time Features Manual None SSE + WebSocket

🏗️ Project Structure #

your_project/
├── lib/
│   ├── models/
│   │   ├── user.dart                      # Your model
│   │   └── user.flutter_axios.g.dart      # Generated code
│   └── main.dart
├── pubspec.yaml
└── build.yaml                             # build_runner config

🔧 Configuration #

build.yaml #

targets:
  $default:
    builders:
      flutter_axios:json_serializable:
        enabled: true
        generate_for:
          - lib/**
          - example/lib/**

Supported Types #

  • Basic: String, int, double, bool, DateTime
  • Collections: List<T>, Map<String, dynamic>
  • Nullable: String?, DateTime?, etc.
  • Custom Objects: Any class with @AxiosJson()
  • Nested: Complex object hierarchies
  • Streaming: Stream<String>, Stream<DownloadProgress>
  • Real-time: Stream<SSEEvent>, Stream<WebSocketMessage>

🚀 Migration Guide #

From json_annotation #

Replace @JsonSerializable() with @AxiosJson():

// Before
@JsonSerializable()
class User {
  // ... fields
  
  factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
  Map<String, dynamic> toJson() => _$UserToJson(this);
}

// After
@AxiosJson()
class User {
  // ... fields only, no manual methods needed!
}

From Manual JSON #

Replace all manual fromJson/toJson with just @AxiosJson():

// Before: 50+ lines of manual JSON code
class User {
  final String id;
  final String name;
  
  User({required this.id, required this.name});
  
  factory User.fromJson(Map<String, dynamic> json) {
    return User(
      id: json['id'] ?? '',
      name: json['name'] ?? '',
    );
  }
  
  Map<String, dynamic> toJson() {
    return {
      'id': id,
      'name': name,
    };
  }
}

// After: Just the annotation!
@AxiosJson()
class User {
  final String id;
  final String name;
  
  const User({required this.id, required this.name});
}

🆕 What's New in v1.1.1 #

Changed #

  • Annotation Renamed: @JsonSerializable()@AxiosJson()
    • Avoids conflicts with json_annotation package
    • More concise 10-character annotation
    • Clearly indicates this is Flutter Axios specific
    • Maintains all existing functionality

🛠️ Troubleshooting #

Common Issues #

  1. Generated file not found

    dart run build_runner build --delete-conflicting-outputs
    
  2. Type 'dynamic' is not a subtype

    • Make sure to initialize JSON mappers: initializeUserJsonMappers()
    • Check that your model has @AxiosJson() annotation
  3. Build runner conflicts

    dart run build_runner clean
    dart run build_runner build --delete-conflicting-outputs
    

Best Practices #

  • Use const constructors when possible
  • Initialize JSON mappers early in main()
  • Use watch mode during development
  • Handle nullable fields appropriately
  • Use descriptive field names

📚 Examples #

Check out the /example directory for:

  • Complete CRUD application
  • Complex nested objects
  • Error handling patterns
  • Interceptor usage
  • Real API integration

🤝 Contributing #

We welcome contributions! Please see our Contributing Guide for details.

📄 License #

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

⭐ Show Your Support #

If this package helped you, please give it a ⭐ on GitHub and 👍 on pub.dev!

1
likes
130
points
145
downloads

Publisher

unverified uploader

Weekly Downloads

A promise-based HTTP client for Flutter inspired by Axios. Provides interceptors, request/response transformation, error handling, and automatic JSON conversion.

Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (license)

Dependencies

build, flutter, glob, http, meta, web_socket_channel

More

Packages that depend on flutter_axios