Flutter HTTP APIs and JSON
Real apps pull data from the internet — weather info, product listings, news articles. They do this through APIs (Application Programming Interfaces) using HTTP requests. This topic covers how to fetch data, convert JSON to Dart objects, and display it in the UI.
What Is an API
An API is a service that gives you data when you ask for it. You send a request to a web address (URL), and it returns data in JSON format.
Your Flutter App Server (API)
───────────── ────────────
"Give me user #5" ──► Looks up user #5
◄── Returns JSON data
What Is JSON
JSON (JavaScript Object Notation) is a text format for sending data. It looks like a Dart Map.
{
"id": 5,
"name": "Ravi Kumar",
"email": "ravi@mail.com",
"city": "Delhi"
}
Step 1 — Add the http Package
In pubspec.yaml:
─────────────────
dependencies:
flutter:
sdk: flutter
http: ^1.2.0
Run: flutter pub get
Step 2 — Add Internet Permission (Android)
In android/app/src/main/AndroidManifest.xml, add this line inside <manifest>: ──────────────────────────────────────────── <uses-permission android:name="android.permission.INTERNET" />
Step 3 — Make an HTTP GET Request
import 'dart:convert';
import 'package:http/http.dart' as http;
Future<Map<String, dynamic>> fetchUser(int id) async {
final url = Uri.parse('https://jsonplaceholder.typicode.com/users/$id');
final response = await http.get(url);
if (response.statusCode == 200) {
// Decode JSON string into a Dart Map
return jsonDecode(response.body);
} else {
throw Exception('Failed to load user. Status: ${response.statusCode}');
}
}
HTTP Status Codes
200 → OK — request succeeded 201 → Created — new resource created 400 → Bad Request — you sent something wrong 401 → Unauthorized — login required 404 → Not Found — resource does not exist 500 → Server Error — problem on the server side
Step 4 — Create a Dart Model Class
Convert the raw Map into a typed Dart class. This makes the data easier and safer to use.
class User {
final int id;
final String name;
final String email;
User({required this.id, required this.name, required this.email});
// Create a User from JSON map
factory User.fromJson(Map<String, dynamic> json) {
return User(
id: json['id'],
name: json['name'],
email: json['email'],
);
}
// Convert User back to JSON
Map<String, dynamic> toJson() {
return {'id': id, 'name': name, 'email': email};
}
}
JSON → Model Diagram
API Response (raw JSON):
─────────────────────────────────────────
{"id": 1, "name": "Leanne", "email": "a@b.com"}
↓
jsonDecode()
↓
Dart Map: {'id': 1, 'name': 'Leanne', ...}
↓
User.fromJson()
↓
Dart Object: User(id:1, name:'Leanne', email:'a@b.com')
Step 5 — Fetch a List of Items
Future<List<User>> fetchAllUsers() async {
final url = Uri.parse('https://jsonplaceholder.typicode.com/users');
final response = await http.get(url);
if (response.statusCode == 200) {
List<dynamic> jsonList = jsonDecode(response.body);
return jsonList.map((json) => User.fromJson(json)).toList();
} else {
throw Exception('Failed to fetch users');
}
}
Step 6 — Display in Flutter UI
class UserListScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Users')),
body: FutureBuilder<List<User>>(
future: fetchAllUsers(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
}
if (snapshot.hasError) {
return Center(child: Text('Error: ${snapshot.error}'));
}
final users = snapshot.data!;
return ListView.builder(
itemCount: users.length,
itemBuilder: (context, index) {
final user = users[index];
return ListTile(
leading: CircleAvatar(child: Text('${user.id}')),
title: Text(user.name),
subtitle: Text(user.email),
);
},
);
},
),
);
}
}
POST Request — Sending Data to API
Future<void> createUser(User user) async {
final url = Uri.parse('https://jsonplaceholder.typicode.com/users');
final response = await http.post(
url,
headers: {'Content-Type': 'application/json'},
body: jsonEncode(user.toJson()),
);
if (response.statusCode == 201) {
print('User created successfully');
} else {
throw Exception('Failed to create user');
}
}
HTTP Methods Summary
| Method | Purpose | Example Use |
|---|---|---|
| GET | Fetch data | Load product list |
| POST | Send new data | Submit a form, create account |
| PUT | Replace existing data | Update full profile |
| PATCH | Update part of data | Change just the email |
| DELETE | Remove data | Delete a post |
Best Practices
- Always check
response.statusCodebefore using the body. - Always use a model class instead of raw Maps in your UI code.
- Show a loading indicator while the request runs.
- Show a useful error message when the request fails.
- Store the base API URL in a constant so you only change it in one place.
