Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(dart): add algolia_chopper_requester package #3291

Open
wants to merge 46 commits into
base: main
Choose a base branch
from

Conversation

techouse
Copy link
Contributor

@techouse techouse commented Jul 1, 2024

🧭 What and Why

In this PR I have created a custom Requester based on Chopper.

Why? Dio is great, but if my Flutter app uses http I now have to have 2 different clients. 🙈 On top of that Chopper gives the user the option to provide their own Client.

final Requester chopperRequester = ChopperRequester({
  /// Your Algolia Application ID
  required String appId,

  /// Your Algolia Search-Only API Key
  required String apiKey,

  /// Additional headers to send with the request
  Map<String, dynamic>? headers,

  /// The segments to include in the `User-Agent` header
  Iterable<AgentSegment>? clientSegments,

  /// The logger to use for debugging
  Logger? logger,

  /// The Chopper Interceptors to use for modifying the request
  Iterable<Interceptor>? interceptors,

  /// The HTTP client to use for sending requests
  /// Will use https://pub.dev/packages/http by default
  /// Accepts any [Client], for example https://pub.dev/packages/cupertino_http
  /// or https://pub.dev/packages/cronet_http
  Client? client,

  /// A custom JSON converter to use for serializing and deserializing JSON
  JsonConverter? converter,
});

Basic Usage

final String appId = 'latency';
final String apiKey = '6be0576ff61c053d5f9a3225e2a90f76';

final SearchClient _client = SearchClient(
  appId: appId,
  apiKey: apiKey,
  options: ClientOptions(
    requester: ChopperRequester(
      appId: appId,
      apiKey: apiKey,
    )
  ),
);

Future<SearchResponse> search(String query) => _client.searchIndex(
      request: SearchForHits(
        indexName: 'flutter',
        query: query,
        hitsPerPage: 5,
      ),
    );

Advanced Usage

To set the connect timeout one has to do that directly on the Client, i.e.

final requester = ChopperRequester(
  appId: appId,
  apiKey: apiKey,
  client: http.IOClient(
    HttpClient()..connectionTimeout = const Duration(seconds: 60),
  ),
);

Custom Interceptors

For interceptors please see the Chopper documentation.

Custom Clients

Via the client option users can use platform specific HTTP clients such:

  • cronet_http on Android
    final requester = ChopperRequester(
      appId: appId,
      apiKey: apiKey,
      client: CronetClient.fromCronetEngine(
        CronetEngine.build(
          cacheMode: CacheMode.memory,
          cacheMaxSize: 50 * 1024 * 1024,
        ),
        closeEngine: true,
      ),
    );
  • cupertino_http on iOS/macOS
    final requester = ChopperRequester(
      appId: appId,
      apiKey: apiKey,
      client: CupertinoClient.fromSessionConfiguration(
        (URLSessionConfiguration.defaultSessionConfiguration()
            ..timeoutIntervalForRequest = const Duration(seconds: 30)),
      ),
    );

NOTE: Custom HTTP clients must be manully disposed of, i.e.

final http.Client client = IOClient(
  HttpClient()..connectionTimeout = const Duration(seconds: 30),
);

/// ... use client ...

client.close();

Parsing JSON in the background using Isolates

Parsing JSON in the background is a good idea if you don't want to block the main thread.
Please see the Chopper documentation on Decoding JSON using Isolate worker pools.

Changes included:

  • export AlgoliaAgent from algolia_client_core package
  • add new package algolia_chopper_requester

Full disclosure: I'm one of the maintainers of Chopper.
Supersedes algolia/algoliasearch-client-dart#14

@techouse
Copy link
Contributor Author

techouse commented Jul 1, 2024

Since I've added a completely new package here there were a few defaults I chose, which should probably be modified in this PR:

  • the package's version is 1.0.0 and not 1.15.1 like the other of the Dart packages
  • the LICENSE of the package is MIT

Both of these should be reviewed and potentially changed.

Copy link
Member

@shortcuts shortcuts left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

awesome, thanks a lot for the contribution!

Some comments about standard package structure across the API clients, for the dart code itself I think @aallam will know better

@shortcuts
Copy link
Member

Since I've added a completely new package here there were a few defaults I chose, which should probably be modified in this PR:

  • the package's version is 1.0.0 and not 1.15.1 like the other of the Dart packages
  • the LICENSE of the package is MIT

Both of these should be reviewed and potentially changed.

Ah nice I was actually commenting on that, do you want to do it with the pointers I've gave or should I take over this part?

@techouse
Copy link
Contributor Author

techouse commented Jul 1, 2024

@shortcuts I think I've done all the tasks. I'm just not sure about d812167 😅

I synced version.dart with the Dart package version manually. Not sure if I should delete it since it's a dependency of chopper_requester.dart.

@techouse
Copy link
Contributor Author

techouse commented Jul 6, 2024

The only annoying bit left to fix is the fact that the user has to provide their appId and apiKey twice now, i.e.

final SearchClient _client = SearchClient(
  appId: appId, // <-- here
  apiKey: apiKey, // <-- here
  options: ClientOptions(
    requester: ChopperRequester(
      appId: appId, // <-- and here
      apiKey: apiKey, // <-- and here
    )
  ),
);

If only there were a way for these credentials to be passed down from the SearchClient to the ClientOptions.

CC/ @shortcuts @aallam

@techouse techouse requested a review from shortcuts July 11, 2024 07:27
@aallam
Copy link
Member

aallam commented Jul 16, 2024

The only annoying bit left to fix is the fact that the user has to provide their appId and apiKey twice now, i.e.

final SearchClient _client = SearchClient(
  appId: appId, // <-- here
  apiKey: apiKey, // <-- here
  options: ClientOptions(
    requester: ChopperRequester(
      appId: appId, // <-- and here
      apiKey: apiKey, // <-- and here
    )
  ),
);

If only there were a way for these credentials to be passed down from the SearchClient to the ClientOptions.

Indeed, this could be improved; however, I think this should be done in a separate PR since it's not specific to this package

aallam
aallam previously approved these changes Jul 16, 2024
@techouse
Copy link
Contributor Author

Indeed, this could be improved; however, I think this should be done in a separate PR since it's not specific to this package

Agreed.

@shortcuts
Copy link
Member

Almost there to make CI work on forks! We will try to get that sorted out soon, thanks a lot for your contribution :D

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants