Riverpod: Simple way to ingest REST API

799

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();
  }
}
Share:
799
Zach Russell
Author by

Zach Russell

I am a Philadelphia based WordPress Developer &amp; 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, 2023

Comments

  • Zach Russell
    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
    princeonwhitemb over 2 years
    please to generate code use build_runner build commands
  • Zach Russell
    Zach Russell over 2 years
    This worked perfect! One follow up question - for a getMorePosts() method how would I merge the two AsyncValues together (state + new result of _service.getBlogPost)
  • Josteve
    Josteve over 2 years
    Hello @ZachRussell, I've added to how do that in an edit.
  • Josteve
    Josteve over 2 years
    Kindly accept and upvote if it works for you.
  • Zach Russell
    Zach Russell over 2 years
    This made complete sense - I was trying to merge the AsyncValues in the StateNotifier which didn't seem correct. Thank you!