Tutorial

Tutorial: Fetch REST data in Flutter

January 12, 2026 · Kabim Tech Mobile · 1 min read

← Back to blog
Mobile app interface on a smartphone
Mobile app interface on a smartphone
Flutter HTTP requests and JSON parsing
  • Flutter
  • Mobile

Build a simple Flutter screen that loads JSON from an API, handles loading and error states, and displays a refreshable list.

Most Flutter apps talk to REST APIs. This tutorial covers HTTP GET, model parsing, and UI states, without over-engineering architecture on day one.

What you will build

  • A `Job` model from JSON
  • A service class that calls `https://jsonplaceholder.typicode.com/posts` (stand-in for your API)
  • A `FutureBuilder` list screen with loading, error, and empty states
  • Pull-to-refresh

Prerequisites

  • Flutter SDK 3.16+ installed
  • Android emulator or iOS simulator
  • Dart async/await basics

Step-by-step

  1. Create a project: `flutter create jobs_viewer && cd jobs_viewer`.
  2. Add `http: ^1.2.0` to `pubspec.yaml` and run `flutter pub get`.
  3. Create `lib/models/job.dart` with `Job.fromJson` factory constructor.
  4. Create `lib/services/job_api.dart` with `Future<List<Job>> fetchJobs()` using `http.get`.
  5. Build `lib/screens/job_list_screen.dart` with `FutureBuilder`, show `CircularProgressIndicator` while waiting.
  6. Wrap the list in `RefreshIndicator` and call `setState` to re-fetch on pull.

Model parsing

class Job {
  const Job({ required this.id, required this.title, required this.body });

  final int id;
  final String title;
  final String body;

  factory Job.fromJson(Map<String, dynamic> json) {
    return Job(
      id: json['id'] as int,
      title: json['title'] as String,
      body: json['body'] as String,
    );
  }
}

API service

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

Future<List<Job>> fetchJobs() async {
  final res = await http.get(Uri.parse('https://jsonplaceholder.typicode.com/posts'));
  if (res.statusCode != 200) throw Exception('Failed to load jobs');
  final list = jsonDecode(res.body) as List<dynamic>;
  return list.map((e) => Job.fromJson(e as Map<String, dynamic>)).toList();
}

Improve from here

  • Swap `FutureBuilder` for Riverpod or Bloc when state grows
  • Add authenticated headers and token refresh
  • Cache responses with `shared_preferences` for offline read

This pattern is how Kabim bootstraps mobile apps before adding full clean architecture.

Want to talk about your product?

Need a dedicated squad or a fixed-scope MVP? We help teams ship on time.