apify_client/clients/store_collection.rs
1//! Client for browsing the Apify Store (`/v2/store`).
2
3use crate::clients::base::{list_resource, ResourceContext};
4use crate::clients::pagination::{list_iterator, ListIterator};
5use crate::common::{PaginationList, QueryParams};
6use crate::error::ApifyClientResult;
7use crate::http_client::HttpClient;
8use crate::models::ActorStoreListItem;
9
10/// A lazy, page-fetching iterator over Apify Store Actors.
11///
12/// Returned by [`StoreCollectionClient::iterate`]. This is an alias for the shared
13/// [`ListIterator`]; call its `next()` to yield one Actor at a time, fetching further pages
14/// from the API transparently until the listing is exhausted.
15pub type StoreActorIterator = ListIterator<ActorStoreListItem>;
16
17/// Options for searching the Apify Store.
18#[derive(Debug, Default, Clone)]
19pub struct StoreListOptions {
20 /// Number of items to skip.
21 pub offset: Option<i64>,
22 /// Item limit. Its meaning depends on the method: for [`StoreCollectionClient::list`] it is a
23 /// single page's size (the maximum items that one call returns); for
24 /// [`StoreCollectionClient::iterate`] it is a cap on the *total* number of items yielded across
25 /// all pages. See each method's docs.
26 pub limit: Option<i64>,
27 /// Full-text search query.
28 pub search: Option<String>,
29 /// Sort key (e.g. `popularity`, `newest`).
30 pub sort_by: Option<String>,
31 /// Filter by category.
32 pub category: Option<String>,
33 /// Filter by owner username.
34 pub username: Option<String>,
35 /// Filter by pricing model.
36 pub pricing_model: Option<String>,
37 /// Include Actors that the current user cannot run (e.g. needing a missing integration).
38 pub include_unrunnable_actors: Option<bool>,
39 /// Filter to Actors that allow agentic (x402/Skyfire) users.
40 pub allows_agentic_users: Option<bool>,
41 /// Response format requested from the API (e.g. `json`).
42 pub response_format: Option<String>,
43}
44
45/// Client for the Apify Store.
46#[derive(Debug, Clone)]
47pub struct StoreCollectionClient {
48 ctx: ResourceContext,
49}
50
51impl StoreCollectionClient {
52 pub(crate) fn new(http: HttpClient, base_url: &str) -> Self {
53 Self {
54 ctx: ResourceContext::collection(http, base_url, "store"),
55 }
56 }
57
58 /// Lists Actors from the Apify Store matching the given options.
59 ///
60 /// Awaiting once returns a single page; use [`StoreCollectionClient::iterate`] to lazily
61 /// iterate across pages.
62 pub async fn list(
63 &self,
64 options: StoreListOptions,
65 ) -> ApifyClientResult<PaginationList<ActorStoreListItem>> {
66 let params = self.build_params(&options);
67 list_resource(&self.ctx, None, ¶ms).await
68 }
69
70 /// Lazily iterates all Store Actors matching `options`, fetching pages on demand.
71 ///
72 /// Returns a [`StoreActorIterator`] whose `next()` method yields one Actor at a time,
73 /// transparently fetching subsequent pages.
74 ///
75 /// `options.limit` caps the *total* number of items yielded across all pages, unlike
76 /// [`list`](Self::list) where `limit` is a single page's size. Set the per-page fetch size
77 /// with [`with_chunk_size`](crate::ListIterator::with_chunk_size); see
78 /// [`ListIterator`] for details.
79 pub fn iterate(&self, options: StoreListOptions) -> StoreActorIterator {
80 list_iterator!(self, options, list)
81 }
82
83 fn build_params(&self, options: &StoreListOptions) -> QueryParams {
84 let mut params = QueryParams::new();
85 params
86 .add_int("offset", options.offset)
87 .add_int("limit", options.limit)
88 .add_str("search", options.search.clone())
89 .add_str("sortBy", options.sort_by.clone())
90 .add_str("category", options.category.clone())
91 .add_str("username", options.username.clone())
92 .add_str("pricingModel", options.pricing_model.clone())
93 .add_bool("includeUnrunnableActors", options.include_unrunnable_actors)
94 .add_bool("allowsAgenticUsers", options.allows_agentic_users)
95 .add_str("responseFormat", options.response_format.clone());
96 params
97 }
98}