$npx -y skills add flutter/agent-plugins --skill flutter-use-http-packageUse the http package to execute GET, POST, PUT, or DELETE requests. Use when you need to fetch from or send data to a REST API.
| 1 | # Implementing Flutter Networking |
| 2 | |
| 3 | ## Contents |
| 4 | - [Configuration & Permissions](#configuration--permissions) |
| 5 | - [Request Execution & Response Handling](#request-execution--response-handling) |
| 6 | - [Background Parsing](#background-parsing) |
| 7 | - [Workflow: Executing Network Operations](#workflow-executing-network-operations) |
| 8 | - [Examples](#examples) |
| 9 | |
| 10 | ## Configuration & Permissions |
| 11 | |
| 12 | Configure the environment and platform-specific permissions required for network access. |
| 13 | |
| 14 | 1. Add the `http` package dependency via the terminal: |
| 15 | ```bash |
| 16 | flutter pub add http |
| 17 | ``` |
| 18 | 2. Import the package in your Dart files: |
| 19 | ```dart |
| 20 | import 'package:http/http.dart' as http; |
| 21 | ``` |
| 22 | 3. Configure Android permissions by adding the Internet permission to `android/app/src/main/AndroidManifest.xml`: |
| 23 | ```xml |
| 24 | <uses-permission android:name="android.permission.INTERNET" /> |
| 25 | ``` |
| 26 | 4. Configure macOS entitlements by adding the network client key to both `macos/Runner/DebugProfile.entitlements` and `macos/Runner/Release.entitlements`: |
| 27 | ```xml |
| 28 | <key>com.apple.security.network.client</key> |
| 29 | <true/> |
| 30 | ``` |
| 31 | |
| 32 | ## Request Execution & Response Handling |
| 33 | |
| 34 | Execute HTTP operations and map responses to strongly typed Dart objects. |
| 35 | |
| 36 | * **URIs:** Always parse URL strings using `Uri.parse('your_url')`. |
| 37 | * **Headers:** Inject authorization and content-type headers via the `headers` parameter map. Use `HttpHeaders.authorizationHeader` for auth tokens. |
| 38 | * **Payloads:** For POST and PUT requests, encode the body using `jsonEncode()` from `dart:convert`. |
| 39 | * **Status Validation:** Evaluate `response.statusCode`. Treat `200 OK` (GET/PUT/DELETE) and `201 CREATED` (POST) as success. |
| 40 | * **Error Handling:** Throw explicit exceptions for non-success status codes. Never return `null` on failure, as this prevents `FutureBuilder` from triggering its error state and causes infinite loading indicators. |
| 41 | * **Deserialization:** Parse the raw string using `jsonDecode(response.body)` and map it to a custom Dart object using a factory constructor (e.g., `fromJson`). |
| 42 | |
| 43 | ## Background Parsing |
| 44 | |
| 45 | Offload expensive JSON parsing to a separate Isolate to prevent UI jank (frame drops). |
| 46 | |
| 47 | * Import `package:flutter/foundation.dart`. |
| 48 | * Use the `compute()` function to run the parsing logic in a background isolate. |
| 49 | * Ensure the parsing function passed to `compute()` is a top-level function or a static method, as closures or instance methods cannot be passed across isolates. |
| 50 | |
| 51 | ## Workflow: Executing Network Operations |
| 52 | |
| 53 | Use the following checklist to implement and validate network operations. |
| 54 | |
| 55 | **Task Progress:** |
| 56 | - [ ] 1. Define the strongly typed Dart model with a `fromJson` factory constructor. |
| 57 | - [ ] 2. Implement the network request method returning a `Future<Model>`. |
| 58 | - [ ] 3. Apply conditional logic based on the operation type: |
| 59 | - **If fetching data (GET):** Append query parameters to the URI. |
| 60 | - **If mutating data (POST/PUT):** Set `'Content-Type': 'application/json; charset=UTF-8'` and attach the `jsonEncode` body. |
| 61 | - **If deleting data (DELETE):** Return an empty model instance on success (`200 OK`). |
| 62 | - [ ] 4. Validate the `statusCode` and throw an `Exception` on failure. |
| 63 | - [ ] 5. Integrate the `Future` into the UI using `FutureBuilder`. |
| 64 | - [ ] 6. Handle `snapshot.hasData`, `snapshot.hasError`, and default to a `CircularProgressIndicator`. |
| 65 | - [ ] 7. **Feedback Loop:** Run the app -> trigger the network request -> review console for unhandled exceptions -> fix parsing or permission errors. |
| 66 | |
| 67 | ## Examples |
| 68 | |
| 69 | ### High-Fidelity Implementation: Fetching and Parsing in the Background |
| 70 | |
| 71 | ```dart |
| 72 | import 'dart:async'; |
| 73 | import 'dart:convert'; |
| 74 | import 'dart:io'; |
| 75 | import 'package:flutter/foundation.dart'; |
| 76 | import 'package:flutter/material.dart'; |
| 77 | import 'package:http/http.dart' as http; |
| 78 | |
| 79 | // 1. Top-level parsing function for Isolate |
| 80 | List<Photo> parsePhotos(String responseBody) { |
| 81 | final parsed = (jsonDecode(responseBody) as List<Object?>) |
| 82 | .cast<Map<String, Object?>>(); |
| 83 | return parsed.map<Photo>(Photo.fromJson).toList(); |
| 84 | } |
| 85 | |
| 86 | // 2. Network execution with background parsing |
| 87 | Future<List<Photo>> fetchPhotos() async { |
| 88 | final response = await http.get( |
| 89 | Uri.parse('https://jsonplaceholder.typicode.com/photos'), |
| 90 | headers: { |
| 91 | HttpHeaders.authorizationHeader: 'Bearer your_token_here', |
| 92 | HttpHeaders.acceptHeader: 'application/json', |
| 93 | }, |
| 94 | ); |
| 95 | |
| 96 | if (response.statusCode == 200) { |
| 97 | // Offload heavy parsing to a background isolate |
| 98 | return compute(parsePhotos, response.body); |
| 99 | } else { |
| 100 | throw Exception('Failed to load photos. Status: ${response.statusCode}'); |
| 101 | } |
| 102 | } |
| 103 | |
| 104 | // 3. Strongly typed model |
| 105 | class Photo { |
| 106 | final int id; |
| 107 | final String title; |
| 108 | final String thumbnailUrl; |
| 109 | |
| 110 | const Photo({ |
| 111 | required this.i |