How to do another API call after get the response of first one using Riverpod?

884 Views Asked by At

I have two APIs. The first one is giving drawList which has the List and the second one is giving a filter for the particular draw which I get in the first API's response.

API 1: <BASE_URL>/draws/list
API 2: <BASE_URL>/draws?filter[immigration_program]=drawList[0]

Response of API 1:

[
  "No Program Specified",
  "Canadian Experience Class",
  "Provincial Nominee Program",
  "Federal Skilled Trades"
]

When I get the response from the first one I want to call the second API.

For the drawList API, I used FutureProvider and for the drawFilter API I used StateNotifierProvider as I need to call it when the user selects another string from the dropdown.

Below is the provider for calling the drawFilter API

final updatedItemListProvider = StateNotifierProvider<UpdatedDropDownItemList,
        AsyncValue<PreviousDrawResponse>>(
    (ref) => UpdatedDropDownItemList(ref.read(apiProvider)));

class UpdatedDropDownItemList
    extends StateNotifier<AsyncValue<PreviousDrawResponse>> {
  UpdatedDropDownItemList(this.service) : super(const AsyncLoading()) {
    callChangeValueAPI(null);
  }

  final ApiService service;

  void callChangeValueAPI(String? newValue) async {
    debugPrint('callChangeValueAPI newValue: $newValue');
    state = const AsyncLoading();
    state = await service.getDrawItemList(newValue);
  }
}

Here is my ApiService. Currently, I used "No program specified" static.

Future<AsyncValue<PreviousDrawResponse>> getDrawItemList(
      String? newValue) async {
    String url;
    if (newValue == null) {
      url =
          "$baseUrl/draws?filter[immigration_program]=No program specified";
    } else {
      url =
          "$baseUrl/draws?filter[immigration_program]=$newValue";
    }

    final response = await get(Uri.parse(url));

    PreviousDrawResponse previousDrawResponse =
        PreviousDrawResponse.fromJson(jsonDecode(response.body));

    if (response.statusCode == 200) {
      debugPrint("getDrawItemList response: ${jsonDecode(response.body)}");
      return AsyncData(previousDrawResponse);
    } else {
      // throw Exception('Failed to load data!');
      debugPrint("getDrawItemList Error");
      return AsyncError('Failed to load data!', StackTrace.current);
    }
  }

I also used the .family modifier. But, It did not work when I change the dropdown value.

Any help?

1

There are 1 best solutions below

0
On

With Riverpod 2.0 this becomes much simpler.



@riverpod

Future<List<String>> drawList(DrawListRef ref) {
   final response = await get(Uri.parse(url));
   return parseResponse(response); // implement
}

Future<??> filteredDraws(DrawListRef ref, String? program) {
   program ??= "No program specified";

   final response = await get(Uri.parse(...));
   return parseResponse(response); // implement
}

in your Widget you can do something like this


class TestWidget extends ConsumerStatefulWidget {
  const TestWidget({super.key});

  @override
  ConsumerState<ConsumerStatefulWidget> createState() => _TestWidgetState();
}

class _TestWidgetState extends ConsumerState<TestWidget> {

   String? selectedProgram;
   
  @override
  Widget build(BuildContext context) {
    final drawListFuture = ref.watch(drawListProvider.future);

      return SomeContainer(children: [
          FutureBuilder<List<String>>(
             future: drawListFuture,
             builder: (snapshot, context) => 
                        DisplayProgramsList(
                          snapshot.data,
                          onSelected: (program) => 
                            setState((){
                                selectedProgram = program;
                            }))
          ),
          FilteredDraws(selectedDraw)
    ]);
  }
}


class FilteredDraws extends ConsumerWidget {
  final String? program;
  const FilteredDraws({super.key}, this.program);

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final filteredDrawsFuture = ref.watch(filteredDrawsProvider(program).future);

      return SomeContainer(children: [
          FutureBuilder<??>(
             future: filteredDrawsFuture,
             builder: (snapshot, context) => DisplayDraws(snapshot.data)
          ),
          FilteredList(selectedDraw)
    ]);
  }
}