Riverpod: Simple way to ingest REST API
This is an example using AsyncValue
- It eliminates the repository
Have your service.dart file like this:
final blogServiceProvider = Provider<BlogService>((ref) => BlogService());
class BlogService {
Future<AsyncValue<List<BlogPost>>> getBlogPost() async {
try {
var dio = Dio();
Response response = await dio.get('https://wordpress-site.com/wp-json/wp/v2/posts/');
var posts = (response.data as List);
List<BlogPost> list = posts.map<BlogPost>((post) => BlogPost.fromJson(post)).toList();
return AsyncData(list);
} catch (e) {
return AsyncError("Something went wrong");
}
}
}
And your provider like so:
final blogNotifierProvider = StateNotifierProvider<BlogNotifier, AsyncValue<List<BlogPost>>>((ref){
BlogService _service = ref.read(blogServiceProvider);
return BlogNotifier(_service);
});
class BlogNotifier extends StateNotifier<AsyncValue<List<BlogPost>>> {
BlogNotifier(this._service) : super(AsyncLoading()) {
getPosts();
}
final BlogService _service;
void getPosts() async {
state = await _service.getBlogPost();
}
}
Edit: To merge existing posts with new ones, try this:
class BlogService {
List<BlogPost> _posts = [];
Future<AsyncValue<List<BlogPost>>> getBlogPost() async {
try {
var dio = Dio();
Response response = await dio.get('https://wordpress-site.com/wp-json/wp/v2/posts/');
var posts = (response.data as List);
List<BlogPost> list = posts.map<BlogPost>((post) => BlogPost.fromJson(post)).toList();
_posts = list;
return AsyncData(list);
} catch (e) {
return AsyncError("Something went wrong");
}
}
Future<AsyncValue<List<BlogPost>>> morePosts() async {
try {
var dio = Dio();
Response response = await dio.get('https://wordpress-site.com/wp-json/wp/v2/posts/?offset=' + length.toString());
var posts = (response.data as List);
List<BlogPost> list = posts.map<BlogPost>((post) => BlogPost.fromJson(post)).toList();
_posts.addAll(list);
return AsyncData(_posts);
} catch (e) {
return AsyncError("Something went wrong");
}
}
}
And the notifier class would be:
class BlogNotifier extends StateNotifier<AsyncValue<List<BlogPost>>> {
BlogNotifier(this._service) : super(AsyncLoading()) {
getPosts();
}
final BlogService _service;
void getPosts() async {
state = await _service.getBlogPost();
}
void morePosts() async {
state = await _service.morePosts();
}
}
Zach Russell
I am a Philadelphia based WordPress Developer & SEO who runs ProTech Internet Group. I have been doing SEO for over 5 years where i've helped countless businesses reach top ranks on search engines. I have developed on WordPress for about two years where I have build countless sites and am looking to make some outside-the-box web applications with in the near future. I am currently a Software Engineering Student at the University of Phoenix where I'd like to concentrate diversify my programming palette. I plan on learning Ruby (Rails), Python, and advanced shell scripting in the near future. Keep on the lookout for my WordPress plugins and themes
Updated on January 03, 2023Comments
-
Zach Russell over 1 year
I'm currently building an app that is ingesting the WordPress REST API to display blog posts. On initial app load, I want to have it pull initial data with a method to then pull more posts via user interaction. I currently have this working, however, my implementation seems complex and there may be a cleaner way to get this working. I based my implementation on this GitHub issue response. Here is what my code looks like:
In
main.dart
:final blogRepository = FutureProvider((ref) async { final posts = await getPosts(); return BlogService(posts); }, ); final blogProvider = StateNotifierProvider<BlogService, List<BlogPost>>((ref) => throw UnimplementedError( "Access to a [BlogService] should be provided through a [ProviderScope]."));
In
blogservice.dart
:class BlogService extends StateNotifier<List<BlogPost>> { final List<BlogPost> _posts; BlogService(this._posts) : super(_posts); List<BlogPost> get posts => _posts; Future<void> morePosts(int length) async { Response response; var dio = Dio(); response = await dio.get('https://wordpress-site.com/wp-json/wp/v2/posts/?offset=' + length.toString()); var posts = (response.data as List); state = [...state, ...posts.map((post) => BlogPost.fromJson(post)).toList()]; } } Future<List<BlogPost>> getPosts() async { Response response; var dio = Dio(); response = await dio.get('https://wordpress-site.com/wp-json/wp/v2/posts/'); var posts = (response.data as List); return posts.map((post) => BlogPost.fromJson(post)).toList(); }
I think a better way of doing this would be to use
AsyncValue
, however, I wasn't able to find any good reference implementations consuming an API using this. -
princeonwhitemb over 2 yearsplease to generate code use build_runner build commands
-
Zach Russell over 2 yearsThis worked perfect! One follow up question - for a
getMorePosts()
method how would I merge the twoAsyncValue
s together (state
+ new result of_service.getBlogPost
) -
Josteve over 2 yearsHello @ZachRussell, I've added to how do that in an edit.
-
Josteve over 2 yearsKindly accept and upvote if it works for you.
-
Zach Russell over 2 yearsThis made complete sense - I was trying to merge the
AsyncValue
s in theStateNotifier
which didn't seem correct. Thank you!