Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

To connect a REST API in Flutter, add the cross-platform http package, make an awaited request with a Uri, reject non-success status codes, decode the JSON into a typed Dart model, and expose the resulting Future to a widget such as FutureBuilder. This guide builds that complete flow with Flutter’s album example, then extends it to POST, PUT, DELETE, authentication, testing, and performance.

What connecting a REST API means in Flutter

A REST connection is an HTTP exchange between your app and a server. Flutter creates a request such as GET, sends it to an endpoint, receives an HTTP status and response body, and turns that body into values your widgets can display. The server’s contract determines the URL, method, headers, JSON shape, authentication scheme, pagination rules, and error format.

Flutter’s http package is the simplest general-purpose way to issue requests and supports Android, iOS, macOS, Windows, Linux, and web. Using it keeps ordinary networking code independent of platform-specific dart:io or dart:html APIs.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

1. Add the package and platform access

Add http to the project

  1. Open a terminal at the Flutter project root.
  2. Run:
flutter pub add http

Import the package with an alias so request classes are unambiguous:

#1 Best Overall
Elebase USB to USB C Adapter for iPhone 18 Pro Max,USBC Car Charger Adapter | 4Pack Type C Female to A Male Cable Converter for Apple Duo 17 16 15 14 Plus,iWatch Watch 12 11 10,iPad 9 8 Air,Airpods 5 4
  • Read Before You Buy — No Video Output: These adapters support charging and USB 2.0 data transfer, but cannot transmit video signals. Except for standard USB webcams (which use USB data only), they are not compatible with HDMI/DisplayPort cables, video-capable USB-C hubs, or docking stations with video output.
  • Convert USB-A Ports to USB-C: Designed to connect USB-C earphones, cables, flash drives, card readers, and other USB-C accessories to standard USB-A ports. Plug-and-play with no drivers or software required.
  • Aluminum Alloy Housing: Built with a sturdy aluminum alloy shell that aids in heat dissipation and protects against daily wear and scratches. Designed to maintain a stable and secure connection.
  • Compact & Travel-Friendly: The ultra-compact design allows the adapter to stay plugged into your device without blocking adjacent ports or adding bulk, reducing wear and tear on your original USB ports.
  • 12-Month Warranty: Backed by a 12-month manufacturer warranty for peace of mind. Designed to meet strict quality control standards for reliable everyday performance.
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

The command selects the current package release allowed by your project’s dependency constraints. The examples below do not depend on a particular package version.

Android permission

Android applications need network access declared in android/app/src/main/AndroidManifest.xml. Put this permission directly under the <manifest> element:

<uses-permission android:name='android.permission.INTERNET' />

Do not assume that this exact manifest edit is required on every target. Platform configuration differs; Android is the platform for which this permission is explicitly required in the Flutter networking guidance.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

macOS entitlement

For a macOS Flutter target, enable the network client entitlement in the macOS runner’s entitlements file, commonly macos/Runner/DebugProfile.entitlements and the release entitlements file:

<key>com.apple.security.network.client</key>
<true/>

Check the entitlement in each build configuration you distribute. iOS, Windows, Linux, web, and Android have different packaging and security rules, so apply the setup documented for the target rather than copying a macOS or Android setting everywhere.

2. Start with a small GET request

The educational endpoint https://jsonplaceholder.typicode.com/albums/1 returns one album as JSON. It is useful for learning the mechanics; it does not prove that a production service has the same fields, persistence, authentication, or status codes.

Define a model instead of passing raw maps around

A model gives the rest of the app a typed interface. Validate required values while constructing it so malformed or changed server data becomes an explicit error.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #2
Anker USB-C Hub, 5-in-1 USB Hub for Laptops, 4K HDMI Multiport Adapter | USB C Dongle with 90W Max Power Delivery, 3×5Gbps USB A Data Ports, for MacBook, Dell, and More (Charger Not Included)
  • 5-in-1 USB-C Hub: Experience comprehensive connectivity featuring a Power Delivery input, two USB-A 2.0 ports, a USB-A 3.0 port, and an HDMI port. (Note: The USB-C power delivery input port is only for connecting an external wall charger to power your laptop and cannot power peripheral devices.)
  • 90W Pass-Through Charging: Achieve optimal charging with 90W pass-through power to your laptop, supported by a total input of 100W, with the hub reserving 10W for operational efficiency. (Note: Wall charger not included.)
  • Quick Data Transfers: Accelerate your productivity with rapid data transfers using a high-speed 5Gbps USB 3.0 port and two 480Mbps USB 2.0 ports.
  • 4K HDMI Display: Enhance your visual experience with a hub capable of delivering 4K resolution at 30Hz in both mirror and extend modes. Please note that this hub is compatible with MacBook (macOS 12 and newer), Windows 10 and 11, ChromeOS, and laptops equipped with DP Alt Mode and Power Delivery. Note: This device is not compatible with Linux.
  • What You Get: Anker USB-C Hub (5-in-1, 4K HDMI), welcome guide, 18-month warranty, and our friendly customer service.
class Album {
  final int userId;
  final int id;
  final String title;

  const Album({
    required this.userId,
    required this.id,
    required this.title,
  });

  factory Album.fromJson(Map<String, dynamic> json) {
    final userId = json['userId'];
    final id = json['id'];
    final title = json['title'];

    if (userId is! int || id is! int || title is! String) {
      throw const FormatException('Album JSON has an unexpected shape');
    }

    return Album(userId: userId, id: id, title: title);
  }
}

The checks matter because jsonDecode returns dynamic maps and lists. A missing key, a numeric value represented in an unexpected form, or an HTML error page can otherwise reach the UI as a confusing null or cast failure.

Fetch, check, decode, and construct

Future<Album> fetchAlbum({http.Client? client}) async {
  final httpClient = client ?? http.Client();
  final ownsClient = client == null;

  try {
    final uri = Uri.parse(
      'https://jsonplaceholder.typicode.com/albums/1',
    );
    final response = await httpClient.get(uri);

    if (response.statusCode != 200) {
      throw http.ClientException(
        'Album request failed with status ${response.statusCode}',
        uri,
      );
    }

    final decoded = jsonDecode(response.body);
    if (decoded is! Map<String, dynamic>) {
      throw const FormatException('Album response is not a JSON object');
    }

    return Album.fromJson(decoded);
  } finally {
    if (ownsClient) {
      httpClient.close();
    }
  }
}

Uri.parse makes the destination explicit, and await pauses this asynchronous function without blocking Flutter’s UI thread. A 200 status is checked before parsing. Treating every response body as success can render an error document as though it were valid application data.

When a service returns a different success code, follow that service’s contract. The cookbook’s create example expects 201, while a particular update or delete endpoint may document 200, 202, or 204. Status handling belongs to each operation, not to a blanket assumption that every successful call is 200.

3. Keep the request out of build()

Flutter can call build() many times because of state changes, parent rebuilds, orientation changes, or inherited-widget updates. Starting a request there can send the same GET repeatedly. Store the future once, normally in initState, and give that future to FutureBuilder.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
class AlbumPage extends StatefulWidget {
  const AlbumPage({super.key});

  @override
  State<AlbumPage> createState() => _AlbumPageState();
}

class _AlbumPageState extends State<AlbumPage> {
  late final Future<Album> _albumFuture;

  @override
  void initState() {
    super.initState();
    _albumFuture = fetchAlbum();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Album')),
      body: FutureBuilder<Album>(
        future: _albumFuture,
        builder: (context, snapshot) {
          if (snapshot.connectionState == ConnectionState.waiting) {
            return const Center(child: CircularProgressIndicator());
          }

          if (snapshot.hasError) {
            return Center(
              child: Padding(
                padding: const EdgeInsets.all(16),
                child: Text('Could not load album: ${snapshot.error}'),
              ),
            );
          }

          final album = snapshot.data;
          if (album == null) {
            return const Center(child: Text('The server returned no album.'));
          }

          return ListTile(
            leading: Text('${album.id}'),
            title: Text(album.title),
            subtitle: Text('User ${album.userId}'),
          );
        },
      ),
    );
  }
}

This widget has three deliberate states: a loading indicator while the future is incomplete, an error view when the future fails, and a data view after a validated Album arrives. In a real app, provide a retry action that assigns a new future inside setState rather than silently issuing requests during every build.

4. Understand the request lifecycle

Stage What your code does Failure to handle
Build the destination Create a parsed Uri containing the service’s scheme, host, path, and query parameters. Malformed or incorrectly encoded addresses can prevent the request from reaching the intended endpoint.
Send asynchronously Call get, post, or another method and await the response. Blocking work or an unhandled future can freeze the interface or produce an uncaught error.
Validate HTTP status Compare the returned code with the operation’s documented success code. An error payload may be parsed as normal data.
Decode JSON Pass the response body to jsonDecode. Malformed JSON raises a format error.
Validate and map Check required fields and construct a model. Unexpected schema changes become late null, cast, or layout failures.
Render state Show loading, data, or an actionable error. Users see a blank screen with no explanation or recovery path.

5. Send JSON with POST

For a write, encode a Dart map, set the JSON content type, await the response, and check the status expected by the API. The cookbook’s create example treats 201 as success.

Future<Album> createAlbum({
  required String title,
  required int userId,
  http.Client? client,
}) async {
  final httpClient = client ?? http.Client();
  final ownsClient = client == null;
  final uri = Uri.parse('https://jsonplaceholder.typicode.com/albums');

  try {
    final response = await httpClient.post(
      uri,
      headers: <String, String>{
        'Content-Type': 'application/json; charset=UTF-8',
      },
      body: jsonEncode(<String, dynamic>{
        'title': title,
        'userId': userId,
      }),
    );

    if (response.statusCode != 201) {
      throw http.ClientException(
        'Create failed with status ${response.statusCode}',
        uri,
      );
    }

    final decoded = jsonDecode(response.body);
    if (decoded is! Map<String, dynamic>) {
      throw const FormatException('Create response is not a JSON object');
    }
    return Album.fromJson(decoded);
  } finally {
    if (ownsClient) {
      httpClient.close();
    }
  }
}

JSONPlaceholder is a teaching service, so its apparent write behavior should not be generalized to a persistent backend. Your API may require additional fields, return a different representation, or use a validation-error object. Display server-provided validation messages only after treating the response as an error according to that service’s contract.

Rank #3
Sale
Anker USB C Hub, 7in1 Multi-Port USB Adapter, 4K@60Hz USBC to HDMI Splitter | 85W Max PD, 2 USB 3.0 & 1 USBC Data Ports, SD/TF Card Reader, for Laptops/Mac and Other Type C Devices (Charger Not Included)
  • Sleek 7-in-1 USB-C Hub: Features an HDMI port, two USB-A 3.0 ports, and a USB-C data port, each providing 5Gbps transfer speeds. It also includes a USB-C PD input port for charging up to 100W and dual SD and TF card slots, all in a compact design.
  • Flawless 4K@60Hz Video with HDMI: Delivers exceptional clarity and smoothness with its 4K@60Hz HDMI port, making it ideal for high-definition presentations and entertainment. (Note: Only the HDMI port supports video projection; the USB-C port is for data transfer only.)
  • Double Up on Efficiency: The two USB-A 3.0 ports and a USB-C port support a fast 5Gbps data rate, significantly boosting your transfer speeds and improving productivity.
  • Fast and Reliable 85W Charging: Offers high-capacity, speedy charging for laptops up to 85W, so you spend less time tethered to an outlet and more time being productive.
  • What You Get: Anker USB-C Hub (7-in-1), welcome guide, 18-month warranty, and our friendly customer service.

6. PUT and DELETE need their own status rules

PUT for an update

Use put with the resource identifier in the path and a JSON body containing the fields the API expects:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
final response = await client.put(
  Uri.parse('https://api.example.com/albums/1'),
  headers: {'Content-Type': 'application/json; charset=UTF-8'},
  body: jsonEncode({'title': 'Updated title'}),
);

if (response.statusCode != 200 && response.statusCode != 204) {
  throw http.ClientException('Update failed: ${response.statusCode}');
}

The accepted codes in this illustrative branch are not universal; replace them with the documented behavior of your service. Some APIs use PATCH for partial updates instead of PUT.

DELETE for removal

final response = await client.delete(
  Uri.parse('https://api.example.com/albums/1'),
);

if (response.statusCode != 200 &&
    response.statusCode != 202 &&
    response.statusCode != 204) {
  throw http.ClientException('Delete failed: ${response.statusCode}');
}

A successful delete may have no body, especially with 204. Do not call jsonDecode on an empty response. Update local state only after the server’s documented success response, or clearly mark an optimistic update so a later failure can roll it back.

7. Add authentication without guessing the scheme

Protected APIs commonly expect credentials in an Authorization header, but the scheme and token format are service-specific. Follow the API’s documentation rather than assuming Basic, Bearer, an API-key header, or a particular token lifetime.

final response = await client.get(
  Uri.parse('https://api.example.com/profile'),
  headers: <String, String>{
    'Authorization': 'Bearer $accessToken',
    'Accept': 'application/json',
  },
);

The placeholder $accessToken represents a value obtained through your service’s authentication flow. Do not hard-code a real credential in source control, log it with request details, or expose a long-lived secret in a client app when the service requires a confidential server-side credential. Handle expired credentials as a distinct state so the app can refresh or ask the user to sign in again.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

8. Handle network and data errors deliberately

A robust fetch function distinguishes transport failures, HTTP failures, and format failures even if the first UI displays them together.

  • Transport failure: DNS problems, offline mode, timeouts, or a dropped connection can prevent any HTTP response. Catch the package’s client exception and offer retry or offline content.
  • HTTP failure: A 401 points to authentication, 403 to authorization, 404 to an incorrect or unavailable resource, and 5xx to a server-side problem, subject to the API’s own semantics.
  • Format failure: Valid HTTP does not guarantee valid JSON or the expected fields. Let FormatException reach an error state and record enough context for diagnosis without logging secrets.

Set timeouts when an endpoint may hang longer than your screen can reasonably wait:

Rank #4
Sale
UGREEN USB to USB C Adapter Combo 4-Pack, 10Gbps USB C Converter Space Gray | Data transfer & Fast charging for MacBook, iPhone 17/16/15, iPad, Samsung Galaxy, Apple Watch
  • Dual Converters, Infinite Potential:Includes 2× USB C male to USB A female adapters and 2× USB A male to USB C female adapters. Perfect for a wide range of uses—tablets with Bluetooth keyboards, expand USB ports on macbook, and more. Two different converters for all your daily needs
  • Next-Level 10Gbps & 3A Charging: No more slow 480Mbps, this usb to usb c adapter has a transfer speed of up to 10Gbps, allowing you to do more transferring in less time. This usb adapter fits both USB A and USB C charger, supporting up to 3A fast charging
  • Upgraded Exquisite Craftsmanship: With an aluminum alloy housing and metal connector, the usbc to usb adapter is extremely durable and sturdy. Rigorously tested to withstand more than 10,000 times of plugging and unplugging, ensuring long-lasting performance
  • Broad Compatible: The usb c to usb adapter widely supports all USB C/ USB A devices like laptops, tablets, cellphones, car chargers, and phone chargers. Such as compatible with MacBook Pro/Air 2023/2022, Thunderbolt 4/3 Devices,Apple MagSafe Watch 9/8/7/SE/Ultra, iPad Pro 2022/2021, Samsung Galaxy S23/S20/S10, and iPhone 17/16/15 Pro. Plug and play
  • Please Note: To reach 10Gbps speed, keep the cable under 3.3 ft. For USB A Male to USB C adapters, try flipping the USB C connector. USB C Male to USB A adapters support bidirectional 10Gbps transfer within 3.3 ft
final response = await client
    .get(uri)
    .timeout(const Duration(seconds: 10));

Choose timeout and retry policies based on the operation. Retrying a GET can be safe in many systems; automatically repeating a payment or other non-idempotent POST can create duplicates unless the API supplies an idempotency mechanism.

9. Test by injecting an http.Client

The optional client parameter in fetchAlbum is more than a convenience. Production code can use a normal client, while a test can provide a mock client that returns controlled status codes and bodies. This avoids depending on a live network for unit tests.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Keep request construction and response mapping in a service function, then test cases such as:

  • a 200 response with a complete album produces the expected model;
  • a non-200 response throws an HTTP error;
  • invalid JSON throws a format error;
  • a missing or wrongly typed required field is rejected; and
  • a timeout or client exception reaches the caller as an actionable failure.

Widget tests can then supply a known future or a fake service and verify that loading, success, error, and retry controls render without making real requests.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

10. Move expensive JSON parsing off the UI isolate when needed

Do not begin with isolate code for a one-object response. Flutter’s background-parsing recipe uses a large list of 5,000 photo objects to illustrate the situation in which decoding and mapping can make frames jank. The recipe explains that work taking more than about 16 milliseconds can interfere with a smooth frame; treat that as the guide’s frame-budget context, not as a universal measurement for every device or payload.

For genuinely expensive parsing, download the body first and use compute to run a top-level parsing function in another isolate:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
List<Album> parseAlbums(String body) {
  final decoded = jsonDecode(body);
  if (decoded is! List) {
    throw const FormatException('Expected a JSON list');
  }

  return decoded
      .map((item) {
        if (item is! Map<String, dynamic>) {
          throw const FormatException('Album item is not an object');
        }
        return Album.fromJson(item);
      })
      .toList();
}

final response = await client.get(uri);
if (response.statusCode != 200) {
  throw http.ClientException('Request failed: ${response.statusCode}', uri);
}
final albums = await compute(parseAlbums, response.body);

An isolate adds serialization overhead and complexity, so measure or reason about the payload before using it. It does not replace pagination, server-side filtering, or reducing an unnecessarily large response.

Best Value
Anker USB C Hub, 5-in-1 USBC to HDMI Splitter with 4K Display | 85W Max PD, 1 Powered USB-C 5Gbps & 2 Powered USB-A 3.0 5Gbps Data Ports, for MacBook Pro, MacBook Air, Dell and More (Black)
  • 5-in-1 Connectivity: Equipped with a 4K HDMI port, a 5 Gbps USB-C data port, two 5 Gbps USB-A ports, and a USB C 100W PD-IN port. Note: The USB C 100W PD-IN port supports only charging and does not support data transfer devices such as headphones or speakers.
  • Powerful Pass-Through Charging: Supports up to 85W pass-through charging so you can power up your laptop while you use the hub. Note: Pass-through charging requires a charger (not included). Note: To achieve full power for iPad, we recommend using a 45W wall charger.
  • Transfer Files in Seconds: Move files to and from your laptop at speeds of up to 5 Gbps via the USB-C and USB-A data ports. Note: The USB C 5Gbps Data port does not support video output.
  • HD Display: Connect to the HDMI port to stream or mirror content to an external monitor in resolutions of up to 4K@30Hz. Note: The USB-C ports do not support video output.
  • What You Get: Anker 332 USB-C Hub (5-in-1), welcome guide, our worry-free 18-month warranty, and friendly customer service.

11. A practical production checklist

  • Confirm the real base URL, path, HTTP method, query parameters, and required headers.
  • Use Uri construction for encoded query values instead of concatenating unescaped user input.
  • Validate every required response field before creating a model.
  • Represent loading, success, empty, and error states separately in the UI.
  • Keep futures and side effects out of build().
  • Use operation-specific success codes, including 201 for a create endpoint when documented.
  • Respect pagination, rate limits, and the service’s documented error format.
  • Protect credentials, redact authorization headers from logs, and plan token expiry behavior.
  • Inject an http.Client so request code can be tested without a live service.
  • Use caching, repositories, retries, environment configuration, or generated serialization only when the app’s requirements justify them; none is required for the basic connection flow.

Common problems and fixes

The app shows a blank screen

Check that the future is assigned before the first build, that the builder handles waiting, hasError, and missing data, and that the widget is not swallowing an exception.

The request runs repeatedly

Move the call from build() to initState, or trigger it only from an explicit user action. Rebuilding a widget should not implicitly start another network operation.

Android reports a network failure immediately

Verify the INTERNET permission is in the application manifest, rebuild the app, and confirm that the URL is reachable from the emulator or device.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

macOS blocks the connection

Check that the network client entitlement is enabled in the entitlements file used by the build configuration you launched.

Parsing fails even though the status is successful

Inspect the actual response shape and content type. A successful status can still carry an empty body, a different JSON object, a list instead of an object, or an HTML proxy page. Validate the decoded type and required fields before mapping.

Authentication returns 401 or 403

Verify the documented header name, scheme, token audience, expiration, and user permissions. Do not switch schemes by guesswork or print the credential while debugging.

What to adapt for your real API

Replace the JSONPlaceholder URL and Album model with the service’s documented endpoint and schema. Confirm whether the operation is read-only or writes data, whether the response is an object or collection, how pagination is represented, which status codes indicate success, and how validation errors are encoded. The Flutter mechanics remain the same: create a URI, await a request, validate its status, decode and validate JSON, map it to a model, and render each asynchronous state.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.