CS310
Mobile Application
Development
Using JSONPlaceholder & HTTP Requests in Flutter
JSONPlaceholder – Fake Online REST API for Testing
What is JSONPlaceholder?
• A free online fake API for testing and learning.
• Used by developers to simulate real server data.
Why do we use it?
• To practice HTTP requests (GET, POST, PUT, DELETE)
• To learn how to work with JSON data
• To build and test apps without creating a real backend
JSON Placeholder
[Link]
What Does JSONPlaceholder Provide?
Resource Endpoint Description Example ID range
Posts /posts Blog posts 1–100
Comments on
Comments /comments 1–500
posts
Albums /albums Photo albums 1–100
Photos /photos Photos in albums 1–5000
Todos /todos To-do items 1–200
User profiles
(authors of posts,
Users /users 1–10
owners of albums,
etc.)
REST API
▪ A web service that provides data using simple URLs and JSON.
▪ REST stands for Representational State Transfer
▪ It is a style of building APIs on the web
▪ REST APIs use HTTP methods:
GET → read data
POST → create data
PUT/PATCH → update data
DELETE → delete data
▪ REST APIs return JSON, not HTML
▪ REST is stateless
API-Application Programming Interface
An API ( Application Programming Interface) is a set of rules and
protocols that allows different software applications to
communicate and exchange information with each other.
API of an Application is a set of programming
codes that allows other 3rd party systems to interact
with that Application.
What is an Endpoint
● A specific URL of a REST API where you can request or send data.
● Each endpoint gives you a different part of the data
For example:
List of products
[Link]
List of users
[Link]
▪ Endpoints always return JSON
An endpoint is a URL in a REST API that returns or accepts JSON data.
HTTP-Hyper Text Transfer Protocol
▪ The main communication protocol of the internet.
▪ HTTP defines how data is sent between a device and a web server
▪ HTTP uses URLs ( Uniform Resource Locators)
HTTP works through “methods” (actions):
• GET → retrieve data
• POST → add new data
• PUT/PATCH → update data
• DELETE → remove data
▪ HTTP is text-based
▪ HTTP responses usually return JSON
HTTP Package
HTTP libraries, such as package:http, allow to specify the following kinds
of communication:
▪ An HTTP method defining the desired action, such as GET to retrieve
data or POST to submit new data.
▪ The location of the resource through a URI.
▪ The version of HTTP being used.
▪ Headers that provide extra information to the server.
▪ An optional body, so the request can send data to the server, not just
retrieve it.
URIs and URLs
• To send an HTTP request, a URI (Uniform Resource Identifier) should be
provided.
A URI is a text string that uniquely identifies a resource.
• A URL (Uniform Resource Locator) is a type of URI that also tells you where the
resource is located.
A URL contains three main parts:
1. Scheme – the protocol used
Example: https
2. Authority / Hostname – the server name
Example: [Link]
3. Path – the exact location of the resource
Example: /tutorials/server/[Link]
Build a URL
▪ To make an HTTP request, you first need a URL that identifies
the resource being requested or endpoint being accessed.
▪ In Dart, URLs are represented through URI objects. There are
many ways to build an URI
▪ Parsing a string with [Link] to create one is a common
solution.
Build a URL
A Problem Scenario based on Dynamic API Request in a Flutter App
▪ You are developing a Flutter application that allows users to filter a list
of products from an online server.
▪ The user can choose:
A category (e.g., electronics, books)
A minimum price
A maximum price
▪ These values are entered by the user at runtime and can change every
time the search is performed.
Task:
Write Dart code to construct a valid URL for this API request using the
following information:
Host: [Link]
Path: /products
Query parameters:
• category
• minPrice
• maxPrice
The values of these parameters should be added dynamically.
Make a Network Request
▪ Use read() when you only need the response as a String
-Returns: Future<String>
-Throws: ClientException on failure
▪ Use get() when you need more details from the response
Returns: Future<Response>
Gives access to:
-Status code (e.g., 200)
-Headers
-Full response body
Using [Link]
Using [Link]
Helpful resources
[Link]
[Link]
HTTP Status Codes
All HTTP response status codes are separated into five classes or
categories.
The first digit of the status code defines the class of response, while
the last two digits do not have any classifying or categorization role.
There are five classes defined by the standard:
[Link]
HTTP-Informational Response Code
1xx — Informational
Server is processing the request
(rarely used in mobile apps)
HTTP 2xx — Success Code
Request worked.
• 200 OK → Request successful (most common)
• 201 Created → New resource created (POST)
HTTP 3xx — Redirects
Resource moved to another URL
(browser handles this; apps rarely use it)
HTTP 4xx — Client Errors
Something wrong with your request.
• 400 Bad Request → Invalid input
• 401 Unauthorized → Need login/auth
• 403 Forbidden → Not allowed
• 404 Not Found → Wrong URL / resource missing
HTTP 5xx — Server Errors
Something wrong on server side.
• 500 Internal Server Error
• 503 Service Unavailable
• 504 Gateway Timeout
Common Errors in Mobile Apps
Code Meaning Who is responsible?
200 Success Everything OK
400 Wrong request App developer
401 Not logged in App developer
404 Wrong URL App developer
500 Server broke Backend server
HTTP Requests - POST
Sending Data with POST
● Use [Link]() to send data to a server.
● Include headers and body (e.g., JSON).
Future<void> sendData() async {
final response = await [Link](
[Link]('[Link]
headers: {'Content-Type': 'application/json'},
body: jsonEncode({'title': 'New Item'}),
);
if ([Link] == 201) {
print('Created!');
}
}
Terminology
Encoding and serialization are the same thing—turning a data structure into a string.
Decoding and deserialization are the opposite process—turning a string into a data
structure.
However, serialization also commonly refers to the entire process of translating data
structures to and from a more easily readable format.
To avoid confusion, use "serialization" when referring to the overall process, and
"encoding" and "decoding" when specifically referring to those processes.
HTTP Requests – Error Handling
● Use try-catch for network failures.
● Handle non-200 status codes.
Future<void> fetchWithErrorHandling() async {
try {
final response = await [Link]([Link]('[Link]
if ([Link] != 200) {
throw Exception('Failed to load: ${[Link]}');
}
print([Link]);
} catch (e) {
print('Error: $e');
}
}
FutureBuilder
FutureBuilder is a Flutter widget that helps you build UI based on the state of a
Future.
A Future represents a potential value or error that will be available at some point
in the future (typically from an asynchronous operation like an API call).
FutureBuilder makes it easy to handle the different states of this asynchronous
operation without manually managing them yourself.
● Give FutureBuilder a Future (e.g., the result of an API call).
● It rebuilds its builder function whenever the state of the Future changes (e.g.,
loading, success, or error).
● Inside the builder, you define how the UI should look based on the current
state.
FutureBuilder Syntax
FutureBuilder<T>(
future: yourFuture, // The Future you want to work
with
builder: (BuildContext context, AsyncSnapshot<T>
snapshot) {
// Return a widget based on the snapshot
state
},
)
FutureBuilder Syntax
T is the type of data the Future will return (e.g., List<User> in your case).
future: The Future you’re waiting for (e.g., fetchUsers()).
builder: A function that takes the current context and an AsyncSnapshot and
returns a widget.
● The future should be initialized before or in initState() (not in build), because if
it’s recreated every build, it could trigger unnecessary API calls or reset the
state.
● FutureBuilder automatically listens to the Future and updates the UI when the
Future resolves (completes with data or an error).
Snapshot
▪ The snapshot is an object of type AsyncSnapshot<T> that
represents the current state of the Future.
▪ It’s passed to the builder function and gives you information
about whether the Future is still loading, has completed
successfully, or has failed with an error.
Snapshot
Snapshot to decide what to show based on the state of the Future.
● [Link]: Tells you the current state of the Future.
● [Link]: A boolean that’s true if the Future completed
successfully and data is available. Access the data with [Link].
● [Link]: A boolean that’s true if the Future completed with an
error. Access the error with [Link].
● [Link]: The actual data returned by the Future once it completes
successfully (e.g., List<User>).It’s null if the Future hasn’t completed or if
there’s an error.
● [Link]: The error object if the Future fails (e.g., an Exception).It’s
null if there’s no error.
Snapshot
FutureBuilder<List<User>>(
future: futureUsers,
builder: (context, snapshot) {
if ([Link]) {
// Build the list with the data
} else if ([Link]) {
// Show error
}
// Default: Show loading (covers waiting state)
return const CircularProgressIndicator();
},
)
A [Link] & ListTile
[Link] is a Flutter widget for creating scrollable lists efficiently. Builds list
items on-demand (lazy loading) to optimize performance.
ListTile is a pre-styled widget for creating list items with a consistent layout.
Combines text, icons, and actions in a single row. Properties:
● leading: Icon/image before the title.
● title: Main text content.
● subtitle: Secondary text below title.
● trailing: Icon/button at the end.
[Link] handles the scrolling list structure. ListTile provides a polished,
ready-to-use item design. Add padding / Divider or Card for better visuals.
[Link] & ListTile
[Link](
itemCount: [Link],
itemBuilder: (context, index) {
return ListTile(
leading: CircleAvatar(child:
Text(contacts[index][0])),
title: Text(contacts[index]),
subtitle: Text('Contact #$index'),
onTap: () => print('Tapped ${contacts[index]}'),
);
},
)
JSON serialization methods
General strategies for working with JSON:
• Manual serialization (for smaller projects) using the built-in
JSON decoder in dart:convert. It involves passing the raw JSON
string to the jsonDecode() function, and then looking up the
values you need in the resulting Map<String, dynamic>.
• Automated serialization using code generation (mid-size to
bigger projects) using external library and code generation. E.g.
json_serializable library
An Example App Using JSONPlaceholder and HTTP
A Flutter app that demonstrates HTTP
networking by fetching user data from the
public JSONPlaceholder API.
The endpoint for this example is:
[Link]
Step 1: Add HTTP Dependency
● In [Link]:
dependencies:
flutter:
sdk: flutter
http: ^1.6.0 # or latest
● Run:
flutter pub get
Step 2 – Create the User model (manual serialization)
JSONPlaceholder /users returns data like:
{ },
"id": 1, "phone": "1-770-736-8031
"name": "Leanne Graham", x56442",
"username": "Bret", "website": "[Link]",
"email": "Sincere@[Link]", "company": {
"address": { "name": "Romaguera-Crona",
"street": "Kulas Light", "catchPhrase": "Multi-layered
"suite": "Apt. 556", client-server neural-net",
"city": "Gwenborough", "bs": "harness real-time e-
"zipcode": "92998-3874", markets"
"geo": { }
"lat": "-37.3159", }
"lng": "81.1496"
}
Model Classes for Users
We will make 3 model classes:
▪ Use
▪ Address
▪ Geo
(You can later add Company if you want)
Services
In Flutter projects, services (often placed in a services/ folder) are classes
responsible for handling business logic that involves external interactions, such
as
● APIs
● Local storage
● Authentication
● Firebase
● WebSocket
● Device features (camera, location, etc.), or any third-party SDKs.
They act as a clean separation layer between your UI (widgets) and
data/external systems, making your code more maintainable, testable, and
scalable.
Common Types of Services in a Flutter Project
Service Type Purpose Typical Filename Example
API / Network Service HTTP requests (GET, POST, api_service.dart
etc.)
Authentication Service Login, logout, token auth_service.dart
management, social logins
Local Storage Service SharedPreferences, Hive, local_storage_service.dart
SQLite, SecureStorage
Location Service Get user location, geocoding location_service.dart
Typical Flutter Project Structure
Step 3 – Create a service to fetch users
import 'package:http/[Link]' as http;
static const String _baseUrl = '[Link]
Step 4 – Simple UI: show users in a ListView
▪ [Link] is ideal for showing dynamic API data
▪ Efficient for large lists because it builds items on demand
▪ Easily displays multiple fields (e.g., name, email, city)
▪ Works well with FutureBuilder for asynchronous data loading
JSON Automatic Serialization
Step 1: Install packages for automatic serialization
● In [Link]:
dependencies:
flutter:
sdk: flutter
http: ^1.2.0
json_annotation: ^4.9.0
dev_dependencies:
build_runner: ^2.4.9
json_serializable: ^6.9.0
● Then run:
flutter pub get
Step 2: Create automatic model
import 'package:json_annotation/json_annotation.dart';
part 'user_auto.[Link]';
1. A simple version without nesting @JsonSerializable()
class UserAuto {
final int id;
2. Generate the .[Link] file final String name;
final String username;
final String email;
flutter pub run build_runner build
UserAuto({
required [Link],
You will see an auto generated file required [Link],
required [Link],
required [Link],
lib/models/auto/user_auto.[Link] });
factory [Link](Map<String, dynamic> json) =>
_$UserAutoFromJson(json);
Map<String, dynamic> toJson() =>
_$UserAutoToJson(this);
}
Import & Part Files
▪ json_annotation.dart provides JSON annotations
▪ part 'user_auto.[Link]' links generated code file
** it means a part of this file will be generated automatically
What does @JsonSerializable() do?
▪ @JsonSerializable() // This is the marker/annotation
▪ When we put @JsonSerializable() on a class, we're telling Dart that this
class should be able to automatically convert to/from JSON
(serialize/deserialize) using generated code.
The factory constructor
factory [Link](Map<String, dynamic> json) =>
_$UserAutoFromJson(json);
Map<String, dynamic> toJson() =>
_$UserAutoToJson(this);
▪ This creates a UserAuto object from/to JSON.
▪ _$UserAutoFromJson(json) is auto generated
▪ _UserAutoToJson is auto generated
'user_auto.dart'
Next Steps:
● Create Auto Service class
● Add the [Link]() to it as well
** just for simulation as JsaonPlaceholder is a fake api and cannot store
the data
Modify the UI accordingly