Welcome back to our Flutter Clean Architecture series!
In the previous post, we delve deep into the Domain Layer — the home of our pure business logic.
Now, it’s time to get more practical: the Data Layer
Quick Reminder: What Is Clean Architecture?
-
Domain Layer: What your app does (business rules, logic)
-
Data Layer: How your app talks to the outside world (APIs, databases, cache)
-
Presentation Layer: Flutter widgets that show data and interact with the user
In this post, we focus fully on the Data Layer.
Why Do We Need a Data Layer?
Imagine your app needs to:
-
Fetch data from an API.
-
Store data locally.
-
Read from device storage.
The Data Layer handles all of these. It:
-
Talks to APIs and databases.
-
Converts external data into your app’s internal Entities.
-
Implements the repository interfaces we defined in the Domain Layer.
The Building Blocks of Data Layer
1. Models (DTOs - Data Transfer Objects)
-
Represent raw data as received from external sources (APIs, databases).
-
Responsible for converting to/from Entities. (Not strictly. to/from Entities or Models can be done in a separate file outside the model file. eg. a mapper file)
2. Data Sources
-
Responsible for actually talking to APIs, databases, or local storage.
-
Can be split into:
-
Remote Data Sources (e.g. REST APIs)
-
Local Data Sources (e.g. SQLite, Hive)
-
3. Repository Implementations
-
Implements the repository interfaces from Domain Layer.
-
Uses data sources to get/save data.
-
Converts models to entities before returning to Domain Layer.
Let’s Build It Step-by-Step
🔧 The Scenario
We want to fetch user profiles from a REST API.
📝 Domain Layer Recap
We already have:
User Entity:
class User {
final String id;
final String name;
final String email;
User({
required this.id,
required this.name,
required this.email,
});
}
abstract class UserRepository {
Future<User> getUserProfile();
}
Now: The Data Layer
1. Create the User Model (DTO)
This matches the API response format.
class UserModel {
final String id;
final String name;
final String email;
UserModel({required this.id, required this.name, required this.email});
// Factory constructor to parse from JSON
factory UserModel.fromJson(Map<String, dynamic> json) {
return UserModel(
id: json['id'],
name: json['name'],
email: json['email'],
);
}
// Convert back to JSON if needed
Map<String, dynamic> toJson() {
return {
'id': id,
'name': name,
'email': email,
};
}
// Convert to Entity (if we were to use mappers, this toEntity method wouldn't be here)
User toEntity() {
return User(id: id, name: name, email: email);
}
}
2. Create the Remote Data Source
import 'package:http/http.dart' as http;
import 'dart:convert';
class RemoteUserDataSource {
final http.Client client;
RemoteUserDataSource({required this.client});
Future<UserModel> fetchUser() async { //Note: Replace https://api.example.com/user with your actual API endpoint when implementing in your app.
final response = await client.get(Uri.parse('https://api.example.com/user'));
if (response.statusCode == 200) {
final jsonMap = json.decode(response.body);
return UserModel.fromJson(jsonMap);
} else {
throw Exception('Failed to load user');
}
}
}
3. Implement the Repository
class UserRepositoryImpl implements UserRepository {
final RemoteUserDataSource remoteUserDataSource;
UserRepositoryImpl({required this.remoteUserDataSource});
@override
Future<User> getUserProfile() async {
final userModel = await remoteUserDataSource.fetchUser();
return userModel.toEntity();
}
}
Full Data Flow Summary
UI --> UseCase --> UserRepository (interface) --> UserRepositoryImpl --> RemoteUserDataSource --> API
Key Takeaways
-
The Data Layer handles external data sources and converts data to usable Entities.
-
Models (DTOs) are only used inside the Data Layer — the Domain Layer stays clean.
-
Repository Implementations connect Domain and Data Layers.
What’s Next?
In the next post, we’ll move to the most exciting part for many Flutter developers:
The Presentation Layer — how to actually display this data in your Flutter app.
I hope this tutorial made the Data Layer simple and clear. Feel free to leave questions or suggestions in the comments!
Comments
Post a Comment