flutter-handling-http-and-json
SKILL.md
Handling HTTP and JSON
Contents
- Core Guidelines
- Workflow: Executing HTTP Operations
- Workflow: Implementing JSON Serialization
- Workflow: Parsing Large JSON in the Background
- Examples
Core Guidelines
- Enforce HTTPS: iOS and Android disable cleartext (HTTP) connections by default. Always use HTTPS endpoints. If HTTP is strictly required for debugging, configure
network_security_config.xml(Android) andNSAppTransportSecurity(iOS). - Construct URIs Safely: Always use
Uri.https(authority, unencodedPath, [queryParameters])to safely build URLs. This handles encoding and formatting reliably, preventing string concatenation errors. - Handle Status Codes: Always validate the
http.Response.statusCode. Treat200(OK) and201(Created) as success. Throw explicit exceptions for other codes (do not returnnull). - Prevent UI Jank: Move expensive JSON parsing operations (taking >16ms) to a background isolate using the
compute()function. - Structured AI Output: When integrating LLMs, enforce reliable JSON output by specifying a strict JSON schema in the system prompt and setting the response MIME type to
application/json.
Workflow: Executing HTTP Operations
Use this workflow to implement network requests using the http package.
Task Progress:
- Add the
httppackage topubspec.yaml. - Configure platform permissions (Internet permission in
AndroidManifest.xmland macOS.entitlements). - Construct the target
Uri. - Execute the HTTP method.
- Validate the response and parse the JSON payload.
Conditional Implementation:
- If fetching data (GET): Use
http.get(uri). - If sending new data (POST): Use
http.post(uri, headers: {...}, body: jsonEncode(data)). EnsureContent-Typeisapplication/json; charset=UTF-8. - If updating data (PUT): Use
http.put(uri, headers: {...}, body: jsonEncode(data)). - If deleting data (DELETE): Use
http.delete(uri, headers: {...}).
Feedback Loop: Validation & Error Handling
- Run the HTTP request.
- Check
response.statusCode. - If
200or201, calljsonDecode(response.body)and map to a Dart object. - If any other code, throw an
Exception('Failed to load/update/delete resource'). - Review errors -> fix endpoint, headers, or payload structure.
Workflow: Implementing JSON Serialization
Choose the serialization strategy based on project complexity.
Conditional Implementation:
- If building a small prototype or simple models: Use manual serialization with
dart:convert. - If building a production app with complex/nested models: Use code generation with
json_serializable.
Manual Serialization Setup
Task Progress:
- Import
dart:convert. - Define the Model class with
finalproperties. - Implement a
factory Model.fromJson(Map<String, dynamic> json)constructor. - Implement a
Map<String, dynamic> toJson()method.
Code Generation Setup (json_serializable)
Task Progress:
- Add dependencies:
flutter pub add json_annotationandflutter pub add -d build_runner json_serializable. - Import
json_annotation.dartin the model file. - Add the
part 'model_name.g.dart';directive. - Annotate the class with
@JsonSerializable(). UseexplicitToJson: trueif the class contains nested models. - Define the
fromJsonfactory andtoJsonmethod delegating to the generated functions. - Run the generator:
dart run build_runner build --delete-conflicting-outputs.
Workflow: Parsing Large JSON in the Background
Use this workflow to prevent frame drops when parsing large JSON payloads (e.g., lists of 1000+ items).
Task Progress:
- Create a top-level or static function that takes a
String(the response body) and returns the parsed Dart object (e.g.,List<Model>). - Inside the function, call
jsonDecodeand map the results to the Model class. - In the HTTP fetch method, pass the top-level parsing function and the
response.bodyto Flutter'scompute()function.
Examples
Example 1: HTTP GET with Manual Serialization
import 'dart:convert';
import 'package:http/http.dart' as http;
class Album {
final int id;
final String title;
const Album({required this.id, required this.title});
factory Album.fromJson(Map<String, dynamic> json) {
return Album(
id: json['id'] as int,
title: json['title'] as String,
);
}
}
Future<Album> fetchAlbum() async {
final uri = Uri.https('jsonplaceholder.typicode.com', '/albums/1');
final response = await http.get(uri);
if (response.statusCode == 200) {
return Album.fromJson(jsonDecode(response.body) as Map<String, dynamic>);
} else {
throw Exception('Failed to load album');
}
}
Example 2: HTTP POST Request
Future<Album> createAlbum(String title) async {
final uri = Uri.https('jsonplaceholder.typicode.com', '/albums');
final response = await http.post(
uri,
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
body: jsonEncode(<String, String>{'title': title}),
);
if (response.statusCode == 201) {
return Album.fromJson(jsonDecode(response.body) as Map<String, dynamic>);
} else {
throw Exception('Failed to create album.');
}
}
Example 3: Background Parsing with compute
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:http/http.dart' as http;
// 1. Top-level function for parsing
List<Photo> parsePhotos(String responseBody) {
final parsed = (jsonDecode(responseBody) as List<Object?>)
.cast<Map<String, Object?>>();
return parsed.map<Photo>(Photo.fromJson).toList();
}
// 2. Fetch function using compute
Future<List<Photo>> fetchPhotos(http.Client client) async {
final uri = Uri.https('jsonplaceholder.typicode.com', '/photos');
final response = await client.get(uri);
if (response.statusCode == 200) {
// Run parsePhotos in a separate isolate
return compute(parsePhotos, response.body);
} else {
throw Exception('Failed to load photos');
}
}
Example 4: Code Generation (json_serializable)
import 'package:json_annotation/json_annotation.dart';
part 'user.g.dart';
(explicitToJson: true)
class User {
final String name;
(name: 'registration_date_millis')
final int registrationDateMillis;
User(this.name, this.registrationDateMillis);
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
Map<String, dynamic> toJson() => _$UserToJson(this);
}
Weekly Installs
678
Repository
flutter/skillsGitHub Stars
685
First Seen
3 days ago
Security Audits
Installed on
codex668
gemini-cli667
opencode667
amp664
cline664
github-copilot664