Home State in Flutter Apps Make HTTP Requests

🌐 Make HTTP Requests — Fetch Real Wikipedia Data!

⏱️ 40-45 minutes 📊 Intermediate — Real API calls! 📦 2 Projects included 🏷️ HTTP, async/await, MVVM, JSON, API

🧒 How Do Apps Talk to the Internet?

📡

Your App Is Currently "Offline" — Let's Connect It!

Right now, your Wikipedia app just shows "Loading..." — it's not actually fetching anything. To get real data, your app needs to make an HTTP request — the same thing your browser does when you visit a website.

Think of it like ordering a pizza 🍕:

  • 📞 You call the pizza place — This is your app making an HTTP request
  • You wait for delivery — This is await (waiting for the response)
  • 📦 You open the box — This is parsing the JSON response
  • 🍽️ You eat the pizza — This is displaying the data in your UI!
🎯
Today you'll learn:
  • ✅ The MVVM architecture pattern (Model-View-ViewModel)
  • ✅ How to use async/await for network calls
  • ✅ How to handle errors when the internet fails
  • ✅ How to parse JSON into Dart objects
🏛️

MVVM — The Professional Way to Structure Your App

MVVM stands for Model-View-ViewModel. It's like dividing your app into three specialized teams:

🗄️

Model

The data expert. Handles HTTP requests, database calls, JSON parsing. Doesn't know anything about UI.

Your ArticleModel class

🖼️

View

The display expert. Shows widgets on screen. Doesn't know where data comes from — just displays whatever it's given.

Your Flutter widgets

🧠

ViewModel

The middleman. Gets data from the Model, holds it in state, and tells the View when to update.

Your ArticleViewModel (next lesson!)

Why bother? If you mix data-fetching code with UI code, your app becomes a tangled mess. MVVM keeps things clean and testable — the same pattern used by professional apps!

async/await — "Don't Freeze While Waiting!"

When your app makes an HTTP request, it takes time — maybe 100ms, maybe 2 seconds. If your app stopped everything while waiting, it would freeze and feel broken.

async/await solves this:

  • async — Marks a function as "this takes time, don't freeze the app"
  • await — Says "pause HERE until the data arrives, but let other stuff keep running"
  • Future<Summary> — The return type means "I'll give you a Summary... eventually!"
💡
Analogy: You're cooking dinner. You put water on to boil (async). While waiting, you chop vegetables (other code runs). When the water boils, you come back to it (await). You didn't just stare at the pot the whole time!

1 Define the ArticleModel — The Data Expert

The Model is the only place in your app that knows how to fetch data. UI widgets should never make HTTP calls directly!

Step 1.1 Create the Empty ArticleModel Class

Add this code to your main.dart file, below the MainApp class:

lib/main.dart — Add below MainApp
class ArticleModel {
    // Properties and methods will be added here.
}

This is just a placeholder — we'll fill it with the HTTP request logic next!

2 Build the HTTP Request — Call Wikipedia!

Now we'll write the actual code that calls the Wikipedia API and gets a random article summary.

Step 2.1 The Wikipedia API Endpoint

Wikipedia provides a free REST API. This URL returns a random article summary in JSON format:

🔗
https://en.wikipedia.org/api/rest_v1/page/random/summary

Try it now! Copy that URL and paste it into your browser. You'll see a big chunk of JSON data — that's exactly what our Flutter app will receive!

Step 2.2 Add the getRandomArticleSummary Method

Update your ArticleModel class with the method that fetches data:

🔍 The HTTP Request Method — Line by Line

Updated ArticleModel
class ArticleModel {
    Future<Summary> getRandomArticleSummary() async {
        final uri = Uri.https(
            'en.wikipedia.org',
            '/api/rest_v1/page/random/summary',
        );
        final response = await get(uri);

        // TODO: Add error handling and JSON parsing.
        throw UnimplementedError();
    }
}

What each part means:

  • Future<Summary> — "This method will return a Summary... but not right now. It returns a promise (Future) that will complete later."
  • async — "This method does something that takes time (network call). Don't freeze the app!"
  • Uri.https(...) — Safely builds the URL. Better than string concatenation because it handles special characters and encoding properly.
  • await get(uri) — "Call the Wikipedia server and wait here until we get a response. But don't freeze — other things can still happen."
  • get() — The HTTP GET function from the http package. It's like typing a URL into your browser.
🧠
Why use Uri.https instead of just a string? Strings can break if there are spaces, special characters, or accents. Uri.https automatically encodes everything properly. It's like the difference between building a car from scratch vs using a factory — the factory gets it right every time!

3 Handle Network Errors — The Internet Is Unreliable!

Network requests can fail for many reasons: no internet, server down, wrong URL. Always handle errors!

Step 3.1 Check the Status Code

HTTP responses come with a status code. 200 means "success" — anything else means "problem":

📊
200✅ OK — Everything worked!
404❓ Not Found — The URL doesn't exist
500💥 Server Error — Wikipedia's server crashed
403🚫 Forbidden — You don't have permission

Update your method to check the status:

Add error handling
Future<Summary> getRandomArticleSummary() async {
    final uri = Uri.https(
        'en.wikipedia.org',
        '/api/rest_v1/page/random/summary',
    );
    final response = await get(uri);

    if (response.statusCode != 200) {                    // ← Check for errors!
        throw const HttpException('Failed to update resource');
    }

    // TODO: Parse JSON and return Summary.
    throw UnimplementedError();
}

If the status code is NOT 200, we throw an exception — this stops execution and lets the calling code know something went wrong.

4 Parse the JSON Response — Turn Text Into Objects

The Wikipedia API returns JSON text. We need to convert it into a Summary object using our data model.

Step 4.1 Complete the Method

Replace the throw UnimplementedError() with the actual JSON parsing:

Complete getRandomArticleSummary
Future<Summary> getRandomArticleSummary() async {
    final uri = Uri.https(
        'en.wikipedia.org',
        '/api/rest_v1/page/random/summary',
    );
    final response = await get(uri);

    if (response.statusCode != 200) {
        throw const HttpException('Failed to update resource');
    }

    return Summary.fromJson(                           // ← Parse the JSON!
        jsonDecode(response.body) as Map<String, Object?>,
    );
}

What this does:

  1. response.body — The raw text of the response (a big JSON string).
  2. jsonDecode(response.body) — Converts the JSON text into a Dart Map (key-value pairs).
  3. as Map<String, Object?> — Tells Dart: "Trust me, this is a Map with String keys."
  4. Summary.fromJson(...) — Uses our data model's factory method to create a proper Summary object from the Map.
The complete ArticleModel is now ready! It can fetch a random Wikipedia article summary, check for errors, parse the JSON response, and return a clean Dart Summary object. In the next lesson, we'll connect this to the UI!

📝 What You Learned Today

MVVM Architecture

Learned to separate your app into Model (data), View (UI), and ViewModel (state). This keeps code clean and testable.

Built an HTTP Request

Used Uri.https for safe URL building and get() from the http package to fetch live Wikipedia data.

Handled Errors

Checked response.statusCode — only proceed if it's 200. Otherwise, throw an HttpException.

Parsed JSON

Used jsonDecode to convert raw text into a Map, then Summary.fromJson to create a typed Dart object.

🧠 Test Yourself!

Q1 What do the async and await keywords do in Dart?

Q2 Why is Uri.https preferred over string concatenation when building URLs?

📦 Project 1: Test the ArticleModel in main()

Project 1Beginner

Objective: Call your model and print a real Wikipedia article!

📋 Requirements:

  1. In main.dart, update your main() function to be async
  2. Create an instance of ArticleModel
  3. Call getRandomArticleSummary() and await the result
  4. Print the summary's title (summary.titles.display) and extract (first few sentences)
  5. Run the app and check your terminal — you should see a real Wikipedia article printed!

🎯 Expected Output:

In your terminal, you should see something like: "Fetched: [Article Title] — [First paragraph of the article...]"

💡
Hint: Change void main() to Future<void> main() async so you can use await inside it.

📦 Project 2: Add a Method to Fetch a Specific Article

Project 2Intermediate

Objective: Create a method that fetches an article by title

📋 Requirements:

  1. Add a new method getArticleSummary(String title) to ArticleModel
  2. It should call the Wikipedia endpoint: /api/rest_v1/page/summary/{title}
  3. Use Uri.https with the path including the title
  4. Handle errors (check for status 200)
  5. Parse and return the Summary
  6. Test it by calling model.getArticleSummary('Flutter_(software)')

🎯 Expected Output:

The article about Flutter from Wikipedia, with its title and extract printed to the console.

💡
Hint: The path for Uri.https should be: '/api/rest_v1/page/summary/$title'. Use string interpolation to insert the title parameter.

🚀 What's Next?

Your Model can now fetch real Wikipedia data! In the next lesson:

  • ChangeNotifier — The ViewModel that manages app state
  • Hold fetched data in a state class that notifies the UI when to update
  • Connect the Model and View through the ViewModel
🎉

Lesson Complete!

You built a working HTTP client that fetches real data from Wikipedia! Your app can now talk to the internet — that's a huge milestone!

Click the button above to track your progress!