Implement remote fetch featured books
Data Layer
Summary
In this lesson, we implement the fetchFeaturedBooks method within the HomeRemoteDataSourceImpl. We inject the ApiService to handle the HTTP GET request to the Google Books API. The response data is parsed from JSON into a list of BookModel objects, which are safely returned as a list of BookEntity objects due to inheritance. Finally, we extract the JSON parsing logic into a separate helper method to adhere to the Single Responsibility Principle.
Key Ideas
- ApiService is injected into the remote data source to handle HTTP requests abstractly.
- Google Books API endpoint volumes?Filtering=free-ebooks&q=programming is used to fetch the featured books.
- The returned JSON data contains a Map where the target book objects are nested under the items key.
- BookModel objects are instantiated using the fromJson factory constructor inside a loop.
- BookModel instances can be added directly to a List<BookEntity> because BookModel extends BookEntity.
- The super constructor in BookModel maps the parsed JSON data directly to the required BookEntity fields.
- Single Responsibility Principle (SRP) is applied by extracting the JSON-to-List parsing logic into a dedicated getBooksList helper method.
Code Snippets
List<BookEntity> getBooksList(Map<String, dynamic> data) {
List<BookEntity> books = [];
for (var bookMap in data['items']) {
books.add(BookModel.fromJson(bookMap));
}
return books;
}class HomeRemoteDataSourceImpl extends HomeRemoteDataSource {
final ApiService apiService;
HomeRemoteDataSourceImpl(this.apiService);
@override
Future<List<BookEntity>> fetchFeaturedBooks() async {
var data = await apiService.get(
endPoint: 'volumes?Filtering=free-ebooks&q=programming');
List<BookEntity> books = getBooksList(data);
return books;
}
@override
Future<List<BookEntity>> fetchNewestBooks() {
// TODO: implement fetchNewestBooks
throw UnimplementedError();
}
}My Notes
The instructor elegantly demonstrates polymorphism in Dart: returning a List<BookModel> where a List<BookEntity> is expected works seamlessly because BookModel extends BookEntity and calls super(). Refactoring the parsing logic out of fetchFeaturedBooks into getBooksList is a great call for the Single Responsibility Principle (SRP). [Editor's note] Placing getBooksList as a top-level function in the data source file might pollute the file over time. In a strict Clean Architecture setup, data mapping often lives inside the Model itself (e.g., BookModel.fromJsonList(...)) or inside a dedicated Mapper class to keep the Data Source purely focused on orchestration. [Editor's note] There is no error handling (like a try-catch block or checking if data['items'] is null) implemented yet. If the API returns an error or an empty response without the items key, the for...in loop will crash.