Lesson 42 of 51 intermediate

REST APIs & CRUD

Create, Read, Update & Delete with HTTP

Open interactive version (quiz + challenge)

Real-world analogy

Imagine ordering food at a restaurant. You (the client app) look at the menu (API documentation), tell the waiter (HTTP) your order using specific words like 'I would like the pasta' (GET request). The kitchen (server) prepares it and the waiter brings back your plate (response) with a receipt number (status code). 200 means 'here is your food!' and 404 means 'sorry, we do not have that dish.'

What is it?

REST APIs are a standardized way for your Flutter app to communicate with a backend server over HTTP. You send requests using methods like GET, POST, PUT, DELETE to specific URLs, and the server responds with status codes and JSON data. Every modern app uses REST APIs to fetch data, authenticate users, and sync information.

Real-world relevance

Every app you use daily relies on REST APIs. When you open Instagram, a GET request fetches your feed. When you post a photo, a POST request uploads it. When you like something, a PATCH request updates it. The team_mvp_kit project communicates with its backend entirely through REST APIs for authentication, user data, and all business operations.

Key points

Code example

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

// A complete REST API example in Dart

// 1. GET - Fetch a list of users
Future<List<User>> getUsers(String accessToken) async {
  final response = await http.get(
    Uri.parse('https://api.example.com/users'),
    headers: {
      'Authorization': 'Bearer $accessToken',
      'Content-Type': 'application/json',
    },
  );

  if (response.statusCode == 200) {
    final List<dynamic> data = jsonDecode(response.body);
    return data.map((json) => User.fromJson(json)).toList();
  }
  throw Exception('Failed: ${response.statusCode}');
}

// 2. POST - Create a new user
Future<User> createUser(String name, String email) async {
  final response = await http.post(
    Uri.parse('https://api.example.com/users'),
    headers: {'Content-Type': 'application/json'},
    body: jsonEncode({
      'name': name,
      'email': email,
    }),
  );

  if (response.statusCode == 201) {
    return User.fromJson(jsonDecode(response.body));
  }
  throw Exception('Create failed: ${response.statusCode}');
}

// 3. DELETE - Remove a user
Future<void> deleteUser(int id, String accessToken) async {
  final response = await http.delete(
    Uri.parse('https://api.example.com/users/$id'),
    headers: {'Authorization': 'Bearer $accessToken'},
  );

  if (response.statusCode != 204) {
    throw Exception('Delete failed: ${response.statusCode}');
  }
}

Line-by-line walkthrough

  1. 1. Import dart:convert for JSON encoding and decoding
  2. 2. Import the http package for making HTTP requests
  3. 3.
  4. 4. Comment: A complete REST API example in Dart
  5. 5.
  6. 6. Comment: GET request to fetch users
  7. 7. Define an async function that returns a list of Users
  8. 8. Send a GET request to the /users endpoint
  9. 9. Passing the full URL to Uri.parse
  10. 10. Opening the headers map
  11. 11. Authorization header with Bearer token for authentication
  12. 12. Content-Type header telling the server we speak JSON
  13. 13. Closing the headers and the get() call
  14. 14.
  15. 15. Check if the response status code is 200 (success)
  16. 16. Decode the JSON body into a List of dynamic maps
  17. 17. Map each JSON object to a User using fromJson and return the list
  18. 18. Closing the success check
  19. 19. Throw an exception if the status code was not 200
  20. 20. Closing the getUsers function
  21. 21.
  22. 22. Comment: POST request to create a new user
  23. 23. Define an async function that takes name and email, returns a User
  24. 24. Send a POST request to the /users endpoint
  25. 25. Passing the URL
  26. 26. Content-Type header for JSON
  27. 27. Encode the name and email as a JSON body string
  28. 28. Closing the jsonEncode map
  29. 29. Closing the post() call
  30. 30.
  31. 31. Check for 201 Created status code
  32. 32. Parse and return the created User from the response
  33. 33. Closing the success check
  34. 34. Throw if creation failed
  35. 35. Closing the createUser function
  36. 36.
  37. 37. Comment: DELETE request to remove a user
  38. 38. Define an async function that takes a user ID
  39. 39. Send a DELETE request with the user ID in the URL path
  40. 40. Passing the URL with the ID as path parameter
  41. 41. Authorization header for delete permission
  42. 42. Closing the delete() call
  43. 43.
  44. 44. Check if status code is NOT 204 No Content
  45. 45. Throw if delete failed
  46. 46. Closing the deleteUser function

Spot the bug

Future<User> getUser(int id) async {
  final response = await http.get(
    'https://api.example.com/users/$id',
    headers: {'Content-Type': 'application/json'},
  );
  return User.fromJson(jsonDecode(response.body));
}
Need a hint?
Look at what http.get expects as its first parameter, and what happens if the request fails...
Show answer
Two bugs: 1) http.get expects a Uri object, not a raw String. Wrap it with Uri.parse(). 2) There is no status code check -- if the server returns 404 or 500, the code tries to parse an error response as a User and will crash. Add 'if (response.statusCode == 200)' before parsing.

Explain like I'm 5

Think of a REST API like a library. You go to the front desk (the server) and say 'Can I GET the book about dinosaurs?' (GET request). The librarian checks if you have a library card (authentication), finds the book (queries the database), and hands it to you with a little note saying 'Here you go, found it!' (200 OK response). If the book does not exist, the note says 'Sorry, not found' (404). If you want to donate a new book, you POST it to the library.

Fun fact

The term REST was coined by Roy Fielding in his PhD dissertation in 2000. He was one of the principal authors of the HTTP specification itself. So the guy who helped create HTTP also defined the best way to use it!

Hands-on challenge

Using Dart's http package, write a function that GETs a list of posts from https://jsonplaceholder.typicode.com/posts, parses the JSON response, and prints the title of each post. Handle the case where the status code is not 200.

More resources

Open interactive version (quiz + challenge) ← Back to course: Flutter & Dart