# How to Use the `http` Package for Different HTTP Requests in Flutter: Complete Guide

> Master Flutter HTTP requests with the http package. Learn GET, POST, PUT, and DELETE calls efficiently for robust app development.

- Repository: [Flutter/skills](https://github.com/flutter/skills)
- Tags: how-to-guide
- Published: 2026-05-09

---

**The `http` package provides a lightweight, platform-agnostic client for making GET, POST, PUT, and DELETE requests in Flutter by combining `Uri` construction, asynchronous `Future` handling, and proper response status code validation.**

The `http` package is the canonical way to perform network operations in Flutter applications, offering a simple yet powerful API for RESTful communication. According to the `flutter/skills` repository documentation, implementing robust HTTP workflows requires separating configuration, request execution, response handling, and UI integration into distinct logical layers. This guide demonstrates production-ready patterns for using the `http` package for different HTTP requests in Flutter while maintaining performance and error safety.

## Installation and Platform Configuration

Start by adding the dependency to your [`pubspec.yaml`](https://github.com/flutter/skills/blob/main/pubspec.yaml):

```bash
flutter pub add http

```

Import the package with a namespace alias to avoid conflicts:

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

```

Before making requests, configure platform-specific permissions. Android requires the `INTERNET` permission in [`AndroidManifest.xml`](https://github.com/flutter/skills/blob/main/AndroidManifest.xml), while macOS needs the `com.apple.security.network.client` entitlement as documented in [`skills/flutter-use-http-package/SKILL.md`](https://github.com/flutter/skills/blob/main/skills/flutter-use-http-package/SKILL.md). These permissions allow the underlying platform sockets to establish outbound connections.

## Executing HTTP Requests

All HTTP methods follow a consistent pattern: construct a `Uri` using `Uri.parse()`, optionally set `headers` for content type or authorization, and await the asynchronous call. For mutating requests (POST, PUT), encode the body using `jsonEncode` from `dart:convert`.

### GET Requests

Use `http.get` to retrieve data. Always validate the `response.statusCode` equals `200` (OK) before processing the payload:

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

Future<List<dynamic>> fetchPhotos() async {
  final response = await http.get(
    Uri.parse('https://jsonplaceholder.typicode.com/photos'),
    headers: {
      HttpHeaders.acceptHeader: 'application/json',
    },
  );

  if (response.statusCode == 200) {
    return jsonDecode(response.body) as List<dynamic>;
  } else {
    throw Exception('Failed to load photos (status: ${response.statusCode})');
  }
}

```

### POST Requests

Use `http.post` to create resources. Set the `Content-Type` header to `application/json` and encode the body. A successful creation returns status `201` (Created):

```dart
Future<http.Response> createPost(Map<String, dynamic> data) async {
  final response = await http.post(
    Uri.parse('https://example.com/api/posts'),
    headers: {
      HttpHeaders.contentTypeHeader: 'application/json; charset=UTF-8',
      HttpHeaders.authorizationHeader: 'Bearer YOUR_TOKEN',
    },
    body: jsonEncode(data),
  );

  if (response.statusCode == 201) {
    return response;
  }
  throw Exception('Failed to create post (status: ${response.statusCode})');
}

```

### PUT Requests

Use `http.put` to update existing resources. Like POST, you must encode the JSON body and set appropriate headers. Successful updates return status `200`:

```dart
Future<http.Response> updatePost(String id, Map<String, dynamic> data) async {
  final response = await http.put(
    Uri.parse('https://example.com/api/posts/$id'),
    headers: {
      HttpHeaders.contentTypeHeader: 'application/json; charset=UTF-8',
      HttpHeaders.authorizationHeader: 'Bearer YOUR_TOKEN',
    },
    body: jsonEncode(data),
  );

  if (response.statusCode == 200) {
    return response;
  }
  throw Exception('Failed to update post (status: ${response.statusCode})');
}

```

### DELETE Requests

Use `http.delete` to remove resources. The `204 No Content` or `200 OK` status typically indicates success:

```dart
Future<void> deletePost(String id) async {
  final response = await http.delete(
    Uri.parse('https://example.com/api/posts/$id'),
    headers: {
      HttpHeaders.authorizationHeader: 'Bearer YOUR_TOKEN',
    },
  );

  if (response.statusCode != 200) {
    throw Exception('Failed to delete post (status: ${response.statusCode})');
  }
}

```

## Response Handling and Background Parsing

Never return `null` from network functions; Flutter widgets like `FutureBuilder` require explicit error states to distinguish between loading and failure. Always throw an `Exception` for non-success status codes.

For large JSON payloads, offload parsing to a background isolate using `compute` from `flutter/foundation.dart`. The parsing function must be a top-level function or static method, as required by Dart's isolate communication:

```dart
import 'package:flutter/foundation.dart';

Future<List<Photo>> fetchPhotosWithCompute() async {
  final response = await http.get(
    Uri.parse('https://jsonplaceholder.typicode.com/photos'),
  );

  if (response.statusCode == 200) {
    return compute(_parsePhotos, response.body);
  } else {
    throw Exception('Failed to load photos');
  }
}

// Top-level function for compute()
List<Photo> _parsePhotos(String body) {
  final parsed = jsonDecode(body) as List<dynamic>;
  return parsed.map((e) => Photo.fromJson(e as Map<String, dynamic>)).toList();
}

class Photo {
  final int id;
  final String title;
  final String thumbnailUrl;

  const Photo({required this.id, required this.title, required this.thumbnailUrl});

  factory Photo.fromJson(Map<String, dynamic> json) => Photo(
    id: json['id'] as int,
    title: json['title'] as String,
    thumbnailUrl: json['thumbnailUrl'] as String,
  );
}

```

This pattern prevents UI jank when processing megabytes of JSON data on the main thread.

## Integrating with Flutter Widgets

Expose network calls as `Future<Model>` methods and consume them with `FutureBuilder`. Initialize the `Future` in `initState` or similar lifecycle methods to prevent redundant network calls on widget rebuilds:

```dart
class PhotoGallery extends StatefulWidget {
  const PhotoGallery({super.key});
  @override
  State<PhotoGallery> createState() => _PhotoGalleryState();
}

class _PhotoGalleryState extends State<PhotoGallery> {
  late final Future<List<Photo>> _photosFuture;

  @override
  void initState() {
    super.initState();
    _photosFuture = fetchPhotosWithCompute();
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<List<Photo>>(
      future: _photosFuture,
      builder: (context, snapshot) {
        if (snapshot.hasData) {
          final photos = snapshot.data!;
          return ListView.builder(
            itemCount: photos.length,
            itemBuilder: (_, i) => ListTile(
              leading: Image.network(photos[i].thumbnailUrl),
              title: Text(photos[i].title),
            ),
          );
        } else if (snapshot.hasError) {
          return Center(child: Text('Error: ${snapshot.error}'));
        }
        return const Center(child: CircularProgressIndicator());
      },
    );
  }
}

```

## Internal Implementation and Testing

The `flutter/skills` repository demonstrates advanced usage in `tool/generator/lib/src/services/resource_fetcher_service.dart`, which wraps `http.Client` for fetching remote resources with custom headers and timeout handling. For testing, reference `tool/generator/test/validate_skills_test.dart` to see how to mock HTTP clients using `package:mockito` or `package:http/testing.dart`, allowing unit tests to validate network-dependent logic without real socket connections.

## Summary

- **Install and configure** the `http` package via `flutter pub add http`, adding platform permissions for Android and macOS.
- **Execute requests** using `http.get`, `http.post`, `http.put`, and `http.delete`, always constructing `Uri` objects via `Uri.parse()`.
- **Encode JSON bodies** with `jsonEncode` and set `Content-Type` headers to `application/json` for mutation operations.
- **Validate responses** by checking `statusCode` (200 for GET/PUT/DELETE, 201 for POST) and throwing exceptions on failure rather than returning null.
- **Parse in background** using `compute` for heavy JSON processing to maintain 60 FPS UI performance.
- **Integrate with UI** via `FutureBuilder`, initializing futures in `initState` to handle loading, data, and error states cleanly.

## Frequently Asked Questions

### Do I need to manually add the `http` package to my Flutter project?

Yes. The `http` package is not part of the Flutter SDK core libraries. You must add it via `flutter pub add http` and import it with `import 'package:http/http.dart' as http;` to access the client methods.

### How do I handle JSON parsing without blocking the UI thread?

Use the `compute` function from `flutter/foundation.dart` to run parsing logic on a separate isolate. The parsing function must be a top-level function or static method that takes a single argument and returns a serializable object, as shown in the [`skills/flutter-use-http-package/SKILL.md`](https://github.com/flutter/skills/blob/main/skills/flutter-use-http-package/SKILL.md) documentation.

### What is the difference between status code 200 and 201 in HTTP responses?

Status `200 OK` indicates a successful request for GET, PUT, and DELETE operations, while `201 Created` specifically signals that a POST request successfully created a new resource on the server. Always check the appropriate code for the specific HTTP method you are using.

### How can I test HTTP requests in Flutter without making real network calls?

Import `package:http/testing.dart` or use mocking libraries like `mockito` to create a mock `http.Client` that returns predefined responses. The `flutter/skills` repository demonstrates this pattern in `tool/generator/test/validate_skills_test.dart`, allowing you to unit test service layers without internet connectivity or latency.