Flutter HTTP Request

This section will introduce how to make HTTP network requests in Flutter applications, including GET, POST requests, and JSON data handling.


Add HTTP dependency

Add the http package in pubspec.yaml:

dependencies:
  http: ^1.0.0

Then run:

$ flutter pub get

Send GET request

Example: GET request

import 'dart:convert';
import 'package:http/http.dart' as http;

// Simple GET request
Future<void> fetchData() async {
  final response = await http.get(Uri.parse('https://jsonplaceholder.typicode.com/posts/1'));

  if (response.statusCode == 200) {
    // Parse JSON data
    final data = jsonDecode(response.body);
    print('Title: ${data['title']}');
  } else {
    print('Request failed: ${response.statusCode}');
  }
}

// GET request with parameters
Future<void> searchData(String query) async {
  final uri = Uri.parse('https://api.example.com/search')
      .replace(queryParameters: {'q': query, 'page': '1'});

  final response = await http.get(uri);

  if (response.statusCode == 200) {
    final data = jsonDecode(response.body);
    print(Result: $data);
  }
}

Send POST request

Example: POST request

import 'dart:convert';
import 'package:http/http.dart' as http;

// POST request - send JSON data
Future<void> postData() async {
  final uri = Uri.parse('https://jsonplaceholder.typicode.com/posts');

  final response = await http.post(
    uri,
    headers: {
      'Content-Type': 'application/json',  // Set request header
    },
    body: jsonEncode({  // Convert a Dart object to a JSON string
      'title': Flutter Tutorial,
      'body': 'Learning Flutter Network Requests',
      'userId': 1,
    }),
  );

  if (response.statusCode == 201) {
    final data = jsonDecode(response.body);
    print('Created successfully: $data');
  } else {
    print('Request failed: ${response.statusCode}');
  }
}

// POST request - send form data
Future<void> postFormData() async {
  final uri = Uri.parse('https://example.com/api/login');

  final response = await http.post(
    uri,
    body: {
      'username': 'admin',
      'password': '123456',
    },
  );

  print('Response: ${response.body}');
}

Process JSON data

Example: JSON parsing

import 'dart:convert';

// Define data model
class Article {
  final int id;
  final String title;
  final String body;
  final User user;

  Article({
    required this.id,
    required this.title,
    required this.body,
    required this.user,
  });

  // Parse from JSON
  factory Article.fromJson(Map<String, dynamic> json) {
    return Article(
      id: json['id'],
      title: json['title'],
      body: json['body'],
      user: User.fromJson(json['user']),
    );
  }

  // Convert to JSON
  Map<String, dynamic> toJson() {
    return {
      'id': id,
      'title': title,
      'body': body,
      'user': user.toJson(),
    };
  }
}

class User {
  final int 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};
  }
}

// Usage example
void parseJson() {
  final jsonString = '''
  {
    "id": 1,
"title": "Flutter Tutorial",
"body": "Learn Flutter",
"user": {"id": 1, "name": "Zhang San"}
  }
  '
'';

  // Parse JSON string
  final Map<String, dynamic> json = jsonDecode(jsonString);
  final article = Article.fromJson(json);

  print('Article ID: ${article.id}');
  print('Author: ${article.user.name}');
}

Error Handling

Example: Complete network request example

import 'dart:convert';
import 'package:http/http.dart' as http;

class ApiService {
  // Base URL
  static const String baseUrl = 'https://jsonplaceholder.typicode.com';

  // Generic GET request method
  static Future<dynamic> get(String endpoint) async {
    try {
      final response = await http.get(
        Uri.parse('$baseUrl/$endpoint'),
      );
      return _handleResponse(response);
    } catch (e) {
      throw ApiException('Network error: $e');
    }
  }

  // Generic POST request method
  static Future<dynamic> post(
    String endpoint,
    Map<String, dynamic> data,
  ) async {
    try {
      final response = await http.post(
        Uri.parse('$baseUrl/$endpoint'),
        headers: {'Content-Type': 'application/json'},
        body: jsonEncode(data),
      );
      return _handleResponse(response);
    } catch (e) {
      throw ApiException('Network error: $e');
    }
  }

  // Handle response
  static dynamic _handleResponse(http.Response response) {
    if (response.statusCode >= 200 && response.statusCode < 300) {
      // Successful response
      if (response.body.isEmpty) {
        return null;
      }
      return jsonDecode(response.body);
    } else if (response.statusCode == 404) {
      throw ApiException(Resource not found, statusCode: 404);
    } else if (response.statusCode >= 500) {
      throw ApiException('Server error', statusCode: response.statusCode);
    } else {
      throw ApiException(
        'Request failed',
        statusCode: response.statusCode,
      );
    }
  }
}

// Custom exception class
class ApiException implements Exception {
  final String message;
  final int? statusCode;

  ApiException(this.message, {this.statusCode});

  @override
  String toString() => 'ApiException: $message (status: $statusCode)';
}

// Usage example
Future<void> fetchArticles() async {
  try {
    final articles = await ApiService.get('posts');
    print('Fetched ${articles.length} articles');
  } on ApiException catch (e) {
    print('API error: $e');
  }
}

In real applications, it is recommended to encapsulate network requests into service classes to uniformly handle errors, loading states, and caching logic.

other extensions