Skip to main content

apify_client/
models.rs

1//! Data models for Apify API resources.
2//!
3//! Each resource is modelled with the fields most commonly used by clients, mirroring
4//! the reference JavaScript client. To remain forward-compatible with additive changes to
5//! the API, none of the models set `deny_unknown_fields`, so unknown API fields are ignored
6//! rather than breaking deserialization. Most resource models additionally capture any unknown
7//! fields in an `extra` map via `#[serde(flatten)]` so they remain accessible to callers.
8
9use std::collections::HashMap;
10
11use chrono::{DateTime, Utc};
12use serde::{Deserialize, Serialize};
13use serde_json::Value;
14
15/// Convenience alias for the catch-all map of unmodelled JSON fields.
16pub type Extra = HashMap<String, Value>;
17
18/// An Actor on the Apify platform.
19#[derive(Debug, Clone, Deserialize, Serialize)]
20#[serde(rename_all = "camelCase")]
21pub struct Actor {
22    /// Unique Actor ID.
23    pub id: String,
24    /// ID of the user who owns the Actor.
25    #[serde(default)]
26    pub user_id: Option<String>,
27    /// Technical name of the Actor (used in API paths).
28    #[serde(default)]
29    pub name: Option<String>,
30    /// Username of the Actor's owner.
31    #[serde(default)]
32    pub username: Option<String>,
33    /// Human-readable title shown in the UI.
34    #[serde(default)]
35    pub title: Option<String>,
36    /// Description of what the Actor does.
37    #[serde(default)]
38    pub description: Option<String>,
39    /// Whether the Actor is publicly available in Apify Store.
40    #[serde(default)]
41    pub is_public: Option<bool>,
42    /// When the Actor was created.
43    #[serde(default)]
44    pub created_at: Option<DateTime<Utc>>,
45    /// When the Actor was last modified.
46    #[serde(default)]
47    pub modified_at: Option<DateTime<Utc>>,
48    /// Any other fields returned by the API.
49    #[serde(flatten)]
50    pub extra: Extra,
51}
52
53/// A single execution of an Actor (an Actor run).
54#[derive(Debug, Clone, Deserialize, Serialize)]
55#[serde(rename_all = "camelCase")]
56pub struct ActorRun {
57    /// Unique run ID.
58    pub id: String,
59    /// ID of the Actor that produced this run.
60    #[serde(default)]
61    pub act_id: Option<String>,
62    /// ID of the task that started this run, if any.
63    #[serde(default)]
64    pub actor_task_id: Option<String>,
65    /// ID of the user who owns the run.
66    #[serde(default)]
67    pub user_id: Option<String>,
68    /// Current run status, e.g. `READY`, `RUNNING`, `SUCCEEDED`, `FAILED`, `ABORTED`, `TIMED-OUT`.
69    #[serde(default)]
70    pub status: Option<String>,
71    /// Optional human-readable status message.
72    #[serde(default)]
73    pub status_message: Option<String>,
74    /// When the run started.
75    #[serde(default)]
76    pub started_at: Option<DateTime<Utc>>,
77    /// When the run finished (absent while still running).
78    #[serde(default)]
79    pub finished_at: Option<DateTime<Utc>>,
80    /// ID of the build used for the run.
81    #[serde(default)]
82    pub build_id: Option<String>,
83    /// Default dataset ID associated with the run.
84    #[serde(default)]
85    pub default_dataset_id: Option<String>,
86    /// Default key-value store ID associated with the run.
87    #[serde(default)]
88    pub default_key_value_store_id: Option<String>,
89    /// Default request queue ID associated with the run.
90    #[serde(default)]
91    pub default_request_queue_id: Option<String>,
92    /// URL of the run's container, if running.
93    #[serde(default)]
94    pub container_url: Option<String>,
95    /// Any other fields returned by the API.
96    #[serde(flatten)]
97    pub extra: Extra,
98}
99
100/// Terminal run/build statuses, used by wait-for-finish helpers.
101pub(crate) const TERMINAL_STATUSES: &[&str] =
102    &["SUCCEEDED", "FAILED", "ABORTED", "TIMED-OUT", "TIMED_OUT"];
103
104impl ActorRun {
105    /// Returns `true` if the run has reached a terminal state.
106    pub fn is_terminal(&self) -> bool {
107        self.status
108            .as_deref()
109            .map(|s| TERMINAL_STATUSES.contains(&s))
110            .unwrap_or(false)
111    }
112}
113
114/// A build of an Actor.
115#[derive(Debug, Clone, Deserialize, Serialize)]
116#[serde(rename_all = "camelCase")]
117pub struct Build {
118    /// Unique build ID.
119    pub id: String,
120    /// ID of the Actor that was built.
121    #[serde(default)]
122    pub act_id: Option<String>,
123    /// Current build status.
124    #[serde(default)]
125    pub status: Option<String>,
126    /// When the build started.
127    #[serde(default)]
128    pub started_at: Option<DateTime<Utc>>,
129    /// When the build finished.
130    #[serde(default)]
131    pub finished_at: Option<DateTime<Utc>>,
132    /// Build number, e.g. `0.1.2`.
133    #[serde(default)]
134    pub build_number: Option<String>,
135    /// Any other fields returned by the API.
136    #[serde(flatten)]
137    pub extra: Extra,
138}
139
140impl Build {
141    /// Returns `true` if the build has reached a terminal state.
142    pub fn is_terminal(&self) -> bool {
143        self.status
144            .as_deref()
145            .map(|s| TERMINAL_STATUSES.contains(&s))
146            .unwrap_or(false)
147    }
148}
149
150/// An Actor task (a saved, reusable Actor configuration).
151#[derive(Debug, Clone, Deserialize, Serialize)]
152#[serde(rename_all = "camelCase")]
153pub struct Task {
154    /// Unique task ID.
155    pub id: String,
156    /// ID of the Actor this task runs.
157    #[serde(default)]
158    pub act_id: Option<String>,
159    /// ID of the user who owns the task.
160    #[serde(default)]
161    pub user_id: Option<String>,
162    /// Technical name of the task.
163    #[serde(default)]
164    pub name: Option<String>,
165    /// Human-readable title.
166    #[serde(default)]
167    pub title: Option<String>,
168    /// Human-readable description shown on the task's public landing page. Required (up to 400
169    /// characters), alongside `title` (3 to 63 characters), to [`publish`](crate::clients::task::TaskClient::publish)
170    /// the task.
171    #[serde(default)]
172    pub description: Option<String>,
173    /// When the task was created.
174    #[serde(default)]
175    pub created_at: Option<DateTime<Utc>>,
176    /// When the task was last modified.
177    #[serde(default)]
178    pub modified_at: Option<DateTime<Utc>>,
179    /// Whether the task is published on its public landing page. Derived from
180    /// `public_config.published_at`; set it via [`TaskClient::update`](crate::clients::task::TaskClient::update)
181    /// (or the [`publish`](crate::clients::task::TaskClient::publish)/
182    /// [`unpublish`](crate::clients::task::TaskClient::unpublish) wrappers) to change it.
183    #[serde(default)]
184    pub is_public: Option<bool>,
185    /// The task's public landing page display configuration, or `None` if never configured.
186    #[serde(default)]
187    pub public_config: Option<TaskPublicConfig>,
188    /// Any other fields returned by the API.
189    #[serde(flatten)]
190    pub extra: Extra,
191}
192
193/// Public-facing display configuration of a task's public landing page.
194///
195/// The task is published when `published_at` is set and unpublished when it is `None`.
196/// `published_at` is server-controlled (read-only) - use
197/// [`TaskClient::publish`](crate::clients::task::TaskClient::publish) /
198/// [`TaskClient::unpublish`](crate::clients::task::TaskClient::unpublish) to change the
199/// publication state.
200#[derive(Debug, Clone, Default, Deserialize, Serialize)]
201#[serde(rename_all = "camelCase")]
202pub struct TaskPublicConfig {
203    /// When the task was published, or `None` if it isn't published. Read-only.
204    #[serde(default)]
205    pub published_at: Option<DateTime<Utc>>,
206    /// Name shown by search engines. Defaults to the task title when unset.
207    #[serde(default)]
208    pub seo_title: Option<String>,
209    /// Description shown by search engines. Defaults to the task description when unset.
210    #[serde(default)]
211    pub seo_description: Option<String>,
212    /// Names of the task input fields displayed on the public task page.
213    #[serde(default)]
214    pub input_schema_fields: Option<Vec<String>>,
215    /// Name of the Actor dataset schema entry whose results are displayed. `None` uses the
216    /// Actor's default dataset.
217    #[serde(default)]
218    pub dataset_name: Option<String>,
219    /// Key of the dataset view (from the Actor's dataset schema) used to display results.
220    /// Required to publish the task.
221    #[serde(default)]
222    pub dataset_view: Option<String>,
223}
224
225/// A dataset storage.
226#[derive(Debug, Clone, Deserialize, Serialize)]
227#[serde(rename_all = "camelCase")]
228pub struct Dataset {
229    /// Unique dataset ID.
230    pub id: String,
231    /// Technical name of the dataset, if named.
232    #[serde(default)]
233    pub name: Option<String>,
234    /// ID of the owner.
235    #[serde(default)]
236    pub user_id: Option<String>,
237    /// When the dataset was created.
238    #[serde(default)]
239    pub created_at: Option<DateTime<Utc>>,
240    /// When the dataset was last modified.
241    #[serde(default)]
242    pub modified_at: Option<DateTime<Utc>>,
243    /// Total number of items in the dataset.
244    #[serde(default)]
245    pub item_count: Option<i64>,
246    /// Any other fields returned by the API.
247    #[serde(flatten)]
248    pub extra: Extra,
249}
250
251/// A key-value store storage.
252#[derive(Debug, Clone, Deserialize, Serialize)]
253#[serde(rename_all = "camelCase")]
254pub struct KeyValueStore {
255    /// Unique store ID.
256    pub id: String,
257    /// Technical name of the store, if named.
258    #[serde(default)]
259    pub name: Option<String>,
260    /// ID of the owner.
261    #[serde(default)]
262    pub user_id: Option<String>,
263    /// When the store was created.
264    #[serde(default)]
265    pub created_at: Option<DateTime<Utc>>,
266    /// When the store was last modified.
267    #[serde(default)]
268    pub modified_at: Option<DateTime<Utc>>,
269    /// Any other fields returned by the API.
270    #[serde(flatten)]
271    pub extra: Extra,
272}
273
274/// Metadata about a single key in a key-value store.
275#[derive(Debug, Clone, Deserialize, Serialize)]
276#[serde(rename_all = "camelCase")]
277pub struct KeyValueStoreKey {
278    /// The record key.
279    pub key: String,
280    /// Size of the record value in bytes.
281    #[serde(default)]
282    pub size: Option<i64>,
283    /// Any other fields returned by the API.
284    #[serde(flatten)]
285    pub extra: Extra,
286}
287
288/// Result of listing keys in a key-value store (key-based pagination).
289#[derive(Debug, Clone, Deserialize, Serialize)]
290#[serde(rename_all = "camelCase")]
291pub struct KeyValueStoreKeysPage {
292    /// Maximum number of keys returned for this request.
293    #[serde(default)]
294    pub limit: i64,
295    /// Whether there are more keys to fetch.
296    #[serde(default)]
297    pub is_truncated: bool,
298    /// The key the listing started after.
299    #[serde(default)]
300    pub exclusive_start_key: Option<String>,
301    /// The value to use as `exclusive_start_key` for the next page.
302    #[serde(default)]
303    pub next_exclusive_start_key: Option<String>,
304    /// The keys of this page.
305    #[serde(default)]
306    pub items: Vec<KeyValueStoreKey>,
307}
308
309/// A record (key + value + content type) in a key-value store.
310#[derive(Debug, Clone)]
311pub struct KeyValueStoreRecord {
312    /// The record key.
313    pub key: String,
314    /// The raw value bytes.
315    pub value: Vec<u8>,
316    /// The MIME content type of the value, if reported by the API.
317    pub content_type: Option<String>,
318}
319
320impl KeyValueStoreRecord {
321    /// Interprets the value as UTF-8 text.
322    pub fn as_text(&self) -> Result<String, std::string::FromUtf8Error> {
323        String::from_utf8(self.value.clone())
324    }
325
326    /// Deserializes the value as JSON into `T`.
327    pub fn json<T: serde::de::DeserializeOwned>(&self) -> Result<T, serde_json::Error> {
328        serde_json::from_slice(&self.value)
329    }
330}
331
332/// A request queue storage.
333#[derive(Debug, Clone, Deserialize, Serialize)]
334#[serde(rename_all = "camelCase")]
335pub struct RequestQueue {
336    /// Unique queue ID.
337    pub id: String,
338    /// Technical name of the queue, if named.
339    #[serde(default)]
340    pub name: Option<String>,
341    /// ID of the owner.
342    #[serde(default)]
343    pub user_id: Option<String>,
344    /// When the queue was created.
345    #[serde(default)]
346    pub created_at: Option<DateTime<Utc>>,
347    /// When the queue was last modified.
348    #[serde(default)]
349    pub modified_at: Option<DateTime<Utc>>,
350    /// Total number of requests ever added.
351    #[serde(default)]
352    pub total_request_count: Option<i64>,
353    /// Any other fields returned by the API.
354    #[serde(flatten)]
355    pub extra: Extra,
356}
357
358/// A single request stored in a request queue.
359#[derive(Debug, Clone, Deserialize, Serialize)]
360#[serde(rename_all = "camelCase")]
361pub struct RequestQueueRequest {
362    /// Unique request ID (assigned by the API; omit when adding a new request).
363    #[serde(default, skip_serializing_if = "Option::is_none")]
364    pub id: Option<String>,
365    /// The URL to be processed.
366    pub url: String,
367    /// Unique key used for deduplication (defaults to `url`).
368    #[serde(default, skip_serializing_if = "Option::is_none")]
369    pub unique_key: Option<String>,
370    /// HTTP method, defaults to `GET`.
371    #[serde(default, skip_serializing_if = "Option::is_none")]
372    pub method: Option<String>,
373    /// Arbitrary user data attached to the request.
374    #[serde(default, skip_serializing_if = "Option::is_none")]
375    pub user_data: Option<Value>,
376    /// Any other fields returned by the API.
377    #[serde(flatten)]
378    pub extra: Extra,
379}
380
381/// Result of adding (or updating) a request in a queue.
382#[derive(Debug, Clone, Deserialize, Serialize)]
383#[serde(rename_all = "camelCase")]
384pub struct RequestQueueOperationInfo {
385    /// ID of the request that was added or updated.
386    pub request_id: String,
387    /// Whether the request was already present in the queue.
388    #[serde(default)]
389    pub was_already_present: bool,
390    /// Whether the request had already been handled.
391    #[serde(default)]
392    pub was_already_handled: bool,
393}
394
395/// The head of a request queue (requests waiting to be processed).
396#[derive(Debug, Clone, Deserialize, Serialize)]
397#[serde(rename_all = "camelCase")]
398pub struct RequestQueueHead {
399    /// Maximum number of requests returned.
400    #[serde(default)]
401    pub limit: i64,
402    /// Whether more than one client has accessed the queue.
403    #[serde(default)]
404    pub had_multiple_clients: bool,
405    /// The requests at the head of the queue.
406    #[serde(default)]
407    pub items: Vec<RequestQueueRequest>,
408    /// Any other fields returned by the API.
409    #[serde(flatten)]
410    pub extra: Extra,
411}
412
413/// The head of a request queue with a server-side lock applied (`POST .../head/lock`).
414///
415/// Same shape as [`RequestQueueHead`] plus the lock metadata the API returns alongside it.
416#[derive(Debug, Clone, Deserialize, Serialize)]
417#[serde(rename_all = "camelCase")]
418pub struct LockedRequestQueueHead {
419    /// Maximum number of requests returned.
420    #[serde(default)]
421    pub limit: i64,
422    /// Whether more than one client has accessed the queue.
423    #[serde(default)]
424    pub had_multiple_clients: bool,
425    /// Number of seconds the returned requests were locked for.
426    #[serde(default)]
427    pub lock_secs: i64,
428    /// Whether the queue has any requests locked, by this or another client.
429    #[serde(default)]
430    pub queue_has_locked_requests: Option<bool>,
431    /// The client key the lock was acquired with.
432    #[serde(default)]
433    pub client_key: Option<String>,
434    /// The locked requests from the head of the queue.
435    #[serde(default)]
436    pub items: Vec<RequestQueueRequest>,
437    /// Any other fields returned by the API.
438    #[serde(flatten)]
439    pub extra: Extra,
440}
441
442/// A page of requests returned by `GET /v2/request-queues/{queueId}/requests` (cursor-based
443/// pagination over every request in the queue, as opposed to [`RequestQueueHead`]'s unlocked
444/// peek at the head).
445#[derive(Debug, Clone, Default, Deserialize, Serialize)]
446#[serde(rename_all = "camelCase")]
447pub struct RequestQueueRequestsPage {
448    /// Maximum number of requests returned for this request.
449    #[serde(default)]
450    pub limit: i64,
451    /// ID of the last request of the previous page. Deprecated by the API in favour of `cursor`.
452    #[serde(default)]
453    pub exclusive_start_id: Option<String>,
454    /// Cursor identifying the current page.
455    #[serde(default)]
456    pub cursor: Option<String>,
457    /// Cursor to pass as `cursor` to fetch the next page; absent on the last page.
458    #[serde(default)]
459    pub next_cursor: Option<String>,
460    /// The requests of this page.
461    #[serde(default)]
462    pub items: Vec<RequestQueueRequest>,
463}
464
465/// Result of prolonging a request's lock (`PUT .../requests/{requestId}/lock`).
466#[derive(Debug, Clone, Deserialize, Serialize)]
467#[serde(rename_all = "camelCase")]
468pub struct RequestLockInfo {
469    /// When the (prolonged) lock expires.
470    pub lock_expires_at: DateTime<Utc>,
471}
472
473/// Result of `POST /v2/request-queues/{queueId}/requests/unlock`.
474#[derive(Debug, Clone, Deserialize, Serialize)]
475#[serde(rename_all = "camelCase")]
476pub struct UnlockRequestsResult {
477    /// Number of requests that were unlocked.
478    pub unlocked_count: i64,
479}
480
481/// A request successfully processed by a request-queue batch add or batch delete operation.
482///
483/// The populated fields depend on the operation: a batch **add** always sets `unique_key`,
484/// `request_id`, `was_already_present` and `was_already_handled` (the API's `AddedRequest`); a
485/// batch **delete** sets `id` and/or `unique_key`, whichever the request was identified by (the
486/// API's `DeletedRequest`).
487#[derive(Debug, Clone, Default, Deserialize, Serialize)]
488#[serde(rename_all = "camelCase")]
489pub struct ProcessedRequest {
490    /// The request's ID, when the operation identifies requests by ID (batch delete).
491    #[serde(default, skip_serializing_if = "Option::is_none")]
492    pub id: Option<String>,
493    /// The request's unique key.
494    #[serde(default, skip_serializing_if = "Option::is_none")]
495    pub unique_key: Option<String>,
496    /// The request's ID, as returned by a batch **add** (mirrors the API's `requestId`).
497    #[serde(default, skip_serializing_if = "Option::is_none")]
498    pub request_id: Option<String>,
499    /// Whether the request was already present in the queue (batch add only).
500    #[serde(default, skip_serializing_if = "Option::is_none")]
501    pub was_already_present: Option<bool>,
502    /// Whether the request had already been handled (batch add only).
503    #[serde(default, skip_serializing_if = "Option::is_none")]
504    pub was_already_handled: Option<bool>,
505}
506
507/// A request that a request-queue batch add operation did not process (typically due to rate
508/// limiting), and which [`crate::clients::request_queue::RequestQueueClient::batch_add_requests`]
509/// retries automatically.
510#[derive(Debug, Clone, Deserialize, Serialize)]
511#[serde(rename_all = "camelCase")]
512pub struct UnprocessedRequest {
513    /// The request's unique key.
514    pub unique_key: String,
515    /// The request's URL.
516    pub url: String,
517    /// The request's HTTP method.
518    #[serde(default, skip_serializing_if = "Option::is_none")]
519    pub method: Option<String>,
520}
521
522/// Result of a request-queue batch add or batch delete operation.
523#[derive(Debug, Clone, Default, Deserialize, Serialize)]
524#[serde(rename_all = "camelCase")]
525pub struct BatchRequestsOperationResult {
526    /// Requests that were successfully processed.
527    #[serde(default)]
528    pub processed_requests: Vec<ProcessedRequest>,
529    /// Requests that were not processed and can be retried.
530    #[serde(default)]
531    pub unprocessed_requests: Vec<UnprocessedRequest>,
532}
533
534/// A schedule that triggers Actor or task runs on a cron expression.
535#[derive(Debug, Clone, Deserialize, Serialize)]
536#[serde(rename_all = "camelCase")]
537pub struct Schedule {
538    /// Unique schedule ID.
539    pub id: String,
540    /// ID of the owner.
541    #[serde(default)]
542    pub user_id: Option<String>,
543    /// Technical name of the schedule.
544    #[serde(default)]
545    pub name: Option<String>,
546    /// The cron expression that determines when the schedule fires.
547    #[serde(default)]
548    pub cron_expression: Option<String>,
549    /// Whether the schedule is currently enabled.
550    #[serde(default)]
551    pub is_enabled: Option<bool>,
552    /// Any other fields returned by the API.
553    #[serde(flatten)]
554    pub extra: Extra,
555}
556
557/// A webhook that notifies an external URL on Actor events.
558#[derive(Debug, Clone, Deserialize, Serialize)]
559#[serde(rename_all = "camelCase")]
560pub struct Webhook {
561    /// Unique webhook ID.
562    pub id: String,
563    /// ID of the owner.
564    #[serde(default)]
565    pub user_id: Option<String>,
566    /// The URL that receives the webhook POST request.
567    #[serde(default)]
568    pub request_url: Option<String>,
569    /// Event types that trigger this webhook.
570    #[serde(default)]
571    pub event_types: Vec<String>,
572    /// Any other fields returned by the API.
573    #[serde(flatten)]
574    pub extra: Extra,
575}
576
577/// A single dispatch (invocation) of a webhook.
578#[derive(Debug, Clone, Deserialize, Serialize)]
579#[serde(rename_all = "camelCase")]
580pub struct WebhookDispatch {
581    /// Unique dispatch ID.
582    pub id: String,
583    /// ID of the webhook that produced this dispatch.
584    #[serde(default)]
585    pub webhook_id: Option<String>,
586    /// Any other fields returned by the API.
587    #[serde(flatten)]
588    pub extra: Extra,
589}
590
591/// Account information about a user.
592#[derive(Debug, Clone, Deserialize, Serialize)]
593#[serde(rename_all = "camelCase")]
594pub struct User {
595    /// Unique user ID.
596    pub id: String,
597    /// Username.
598    #[serde(default)]
599    pub username: Option<String>,
600    /// Any other fields returned by the API (public or private depending on the call).
601    #[serde(flatten)]
602    pub extra: Extra,
603}
604
605/// A single Actor entry as returned by the Apify Store listing.
606#[derive(Debug, Clone, Deserialize, Serialize)]
607#[serde(rename_all = "camelCase")]
608pub struct ActorStoreListItem {
609    /// Unique Actor ID.
610    pub id: String,
611    /// Technical name of the Actor.
612    #[serde(default)]
613    pub name: Option<String>,
614    /// Username of the Actor's owner.
615    #[serde(default)]
616    pub username: Option<String>,
617    /// Human-readable title.
618    #[serde(default)]
619    pub title: Option<String>,
620    /// Any other fields returned by the API.
621    #[serde(flatten)]
622    pub extra: Extra,
623}
624
625/// An Actor version.
626#[derive(Debug, Clone, Deserialize, Serialize)]
627#[serde(rename_all = "camelCase")]
628pub struct ActorVersion {
629    /// The version number, e.g. `0.1`.
630    pub version_number: String,
631    /// The source type of the version, e.g. `SOURCE_FILES`, `GIT_REPO`, `TARBALL`, `GITHUB_GIST`.
632    #[serde(default)]
633    pub source_type: Option<String>,
634    /// Any other fields returned by the API.
635    #[serde(flatten)]
636    pub extra: Extra,
637}
638
639/// An environment variable attached to an Actor version.
640#[derive(Debug, Clone, Deserialize, Serialize)]
641#[serde(rename_all = "camelCase")]
642pub struct ActorEnvVar {
643    /// The environment variable name.
644    pub name: String,
645    /// The value (may be omitted for secret variables in responses).
646    #[serde(default, skip_serializing_if = "Option::is_none")]
647    pub value: Option<String>,
648    /// Whether the variable is a secret.
649    #[serde(default, skip_serializing_if = "Option::is_none")]
650    pub is_secret: Option<bool>,
651    /// Any other fields returned by the API.
652    #[serde(flatten)]
653    pub extra: Extra,
654}