How to use rest api

#api

Answer

Overview

Using a REST API in Flutter involves making HTTP requests to a server and handling the JSON response. The most common packages are

text
http
(simple) and
text
dio
(feature-rich).


Setup — pubspec.yaml

yaml
dependencies:
  http: ^1.2.0
  # or
  dio: ^5.4.0

Basic GET Request (http package)

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

Future<List<Post>> fetchPosts() async {
  final response = await http.get(
    Uri.parse('https://jsonplaceholder.typicode.com/posts'),
    headers: {'Content-Type': 'application/json'},
  );

  if (response.statusCode == 200) {
    final List<dynamic> json = jsonDecode(response.body);
    return json.map((e) => Post.fromJson(e)).toList();
  } else {
    throw Exception('Failed to load posts: ${response.statusCode}');
  }
}

POST Request

dart
Future<Post> createPost(String title, String body) async {
  final response = await http.post(
    Uri.parse('https://jsonplaceholder.typicode.com/posts'),
    headers: {'Content-Type': 'application/json'},
    body: jsonEncode({'title': title, 'body': body, 'userId': 1}),
  );

  if (response.statusCode == 201) {
    return Post.fromJson(jsonDecode(response.body));
  } else {
    throw Exception('Failed to create post');
  }
}

Using Dio (Recommended for Production)

dart
import 'package:dio/dio.dart';

final dio = Dio(BaseOptions(
  baseUrl: 'https://api.example.com
  headers: {'Authorization': 'Bearer $token'},
  connectTimeout: Duration(seconds: 10),
  receiveTimeout: Duration(seconds: 10),
));

// GET
final response = await dio.get('/users');
final users = (response.data as List).map((e) => User.fromJson(e)).toList();

// POST
final res = await dio.post('/users', data: {'name': 'Alice', 'email': 'alice@example.com'});

// With Interceptor (add auth token automatically)
dio.interceptors.add(InterceptorsWrapper(
  onRequest: (options, handler) {
    options.headers['Authorization'] = 'Bearer $token';
    handler.next(options);
  },
  onError: (DioException error, handler) {
    if (error.response?.statusCode == 401) {
      // Handle token expiry
    }
    handler.next(error);
  },
));

Model Class (JSON Serialization)

dart
class Post {
  final int id;
  final String title;
  final String body;

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

  factory Post.fromJson(Map<String, dynamic> json) => Post(
    id: json['id'],
    title: json['title'],
    body: json['body'],
  );

  Map<String, dynamic> toJson() => {'id': id, 'title': title, 'body': body};
}

Error Handling

dart
Future<List<Post>> fetchPostsSafely() async {
  try {
    final response = await http.get(Uri.parse('https://api.example.com/posts'))
        .timeout(Duration(seconds: 10));

    switch (response.statusCode) {
      case 200: return (jsonDecode(response.body) as List)
          .map((e) => Post.fromJson(e)).toList();
      case 401: throw UnauthorizedException();
      case 404: throw NotFoundException();
      default: throw ServerException(response.statusCode);
    }
  } on TimeoutException {
    throw NetworkTimeoutException();
  } on SocketException {
    throw NoInternetException();
  }
}

Display in Widget with FutureBuilder

dart
FutureBuilder<List<Post>>(
  future: fetchPosts(),
  builder: (context, snapshot) {
    if (snapshot.connectionState == ConnectionState.waiting) {
      return CircularProgressIndicator();
    }
    if (snapshot.hasError) return Text('Error: ${snapshot.error}');
    return ListView.builder(
      itemCount: snapshot.data!.length,
      itemBuilder: (context, i) => ListTile(title: Text(snapshot.data![i].title)),
    );
  },
)

Best Practice: Use

text
dio
for production apps — it includes interceptors, cancellation, file upload/download, and retry logic. Use
text
http
for simple/small apps.