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
5//! to the API, every model captures any unknown fields in an `extra` map via
6//! `#[serde(flatten)]`, so new API fields never break deserialization.
7
8use std::collections::HashMap;
9
10use chrono::{DateTime, Utc};
11use serde::{Deserialize, Serialize};
12use serde_json::Value;
13
14/// Convenience alias for the catch-all map of unmodelled JSON fields.
15pub type Extra = HashMap<String, Value>;
16
17/// An Actor on the Apify platform.
18#[derive(Debug, Clone, Deserialize, Serialize)]
19#[serde(rename_all = "camelCase")]
20pub struct Actor {
21    /// Unique Actor ID.
22    pub id: String,
23    /// ID of the user who owns the Actor.
24    #[serde(default)]
25    pub user_id: Option<String>,
26    /// Technical name of the Actor (used in API paths).
27    #[serde(default)]
28    pub name: Option<String>,
29    /// Username of the Actor's owner.
30    #[serde(default)]
31    pub username: Option<String>,
32    /// Human-readable title shown in the UI.
33    #[serde(default)]
34    pub title: Option<String>,
35    /// Description of what the Actor does.
36    #[serde(default)]
37    pub description: Option<String>,
38    /// Whether the Actor is publicly available in Apify Store.
39    #[serde(default)]
40    pub is_public: Option<bool>,
41    /// When the Actor was created.
42    #[serde(default)]
43    pub created_at: Option<DateTime<Utc>>,
44    /// When the Actor was last modified.
45    #[serde(default)]
46    pub modified_at: Option<DateTime<Utc>>,
47    /// Any other fields returned by the API.
48    #[serde(flatten)]
49    pub extra: Extra,
50}
51
52/// A single execution of an Actor (an Actor run).
53#[derive(Debug, Clone, Deserialize, Serialize)]
54#[serde(rename_all = "camelCase")]
55pub struct ActorRun {
56    /// Unique run ID.
57    pub id: String,
58    /// ID of the Actor that produced this run.
59    #[serde(default)]
60    pub act_id: Option<String>,
61    /// ID of the task that started this run, if any.
62    #[serde(default)]
63    pub actor_task_id: Option<String>,
64    /// ID of the user who owns the run.
65    #[serde(default)]
66    pub user_id: Option<String>,
67    /// Current run status, e.g. `READY`, `RUNNING`, `SUCCEEDED`, `FAILED`, `ABORTED`, `TIMED-OUT`.
68    #[serde(default)]
69    pub status: Option<String>,
70    /// Optional human-readable status message.
71    #[serde(default)]
72    pub status_message: Option<String>,
73    /// When the run started.
74    #[serde(default)]
75    pub started_at: Option<DateTime<Utc>>,
76    /// When the run finished (absent while still running).
77    #[serde(default)]
78    pub finished_at: Option<DateTime<Utc>>,
79    /// ID of the build used for the run.
80    #[serde(default)]
81    pub build_id: Option<String>,
82    /// Default dataset ID associated with the run.
83    #[serde(default)]
84    pub default_dataset_id: Option<String>,
85    /// Default key-value store ID associated with the run.
86    #[serde(default)]
87    pub default_key_value_store_id: Option<String>,
88    /// Default request queue ID associated with the run.
89    #[serde(default)]
90    pub default_request_queue_id: Option<String>,
91    /// URL of the run's container, if running.
92    #[serde(default)]
93    pub container_url: Option<String>,
94    /// Any other fields returned by the API.
95    #[serde(flatten)]
96    pub extra: Extra,
97}
98
99/// Terminal run/build statuses, used by wait-for-finish helpers.
100pub(crate) const TERMINAL_STATUSES: &[&str] =
101    &["SUCCEEDED", "FAILED", "ABORTED", "TIMED-OUT", "TIMED_OUT"];
102
103impl ActorRun {
104    /// Returns `true` if the run has reached a terminal state.
105    pub fn is_terminal(&self) -> bool {
106        self.status
107            .as_deref()
108            .map(|s| TERMINAL_STATUSES.contains(&s))
109            .unwrap_or(false)
110    }
111}
112
113/// A build of an Actor.
114#[derive(Debug, Clone, Deserialize, Serialize)]
115#[serde(rename_all = "camelCase")]
116pub struct Build {
117    /// Unique build ID.
118    pub id: String,
119    /// ID of the Actor that was built.
120    #[serde(default)]
121    pub act_id: Option<String>,
122    /// Current build status.
123    #[serde(default)]
124    pub status: Option<String>,
125    /// When the build started.
126    #[serde(default)]
127    pub started_at: Option<DateTime<Utc>>,
128    /// When the build finished.
129    #[serde(default)]
130    pub finished_at: Option<DateTime<Utc>>,
131    /// Build number, e.g. `0.1.2`.
132    #[serde(default)]
133    pub build_number: Option<String>,
134    /// Any other fields returned by the API.
135    #[serde(flatten)]
136    pub extra: Extra,
137}
138
139impl Build {
140    /// Returns `true` if the build has reached a terminal state.
141    pub fn is_terminal(&self) -> bool {
142        self.status
143            .as_deref()
144            .map(|s| TERMINAL_STATUSES.contains(&s))
145            .unwrap_or(false)
146    }
147}
148
149/// An Actor task (a saved, reusable Actor configuration).
150#[derive(Debug, Clone, Deserialize, Serialize)]
151#[serde(rename_all = "camelCase")]
152pub struct Task {
153    /// Unique task ID.
154    pub id: String,
155    /// ID of the Actor this task runs.
156    #[serde(default)]
157    pub act_id: Option<String>,
158    /// ID of the user who owns the task.
159    #[serde(default)]
160    pub user_id: Option<String>,
161    /// Technical name of the task.
162    #[serde(default)]
163    pub name: Option<String>,
164    /// Human-readable title.
165    #[serde(default)]
166    pub title: Option<String>,
167    /// When the task was created.
168    #[serde(default)]
169    pub created_at: Option<DateTime<Utc>>,
170    /// When the task was last modified.
171    #[serde(default)]
172    pub modified_at: Option<DateTime<Utc>>,
173    /// Any other fields returned by the API.
174    #[serde(flatten)]
175    pub extra: Extra,
176}
177
178/// A dataset storage.
179#[derive(Debug, Clone, Deserialize, Serialize)]
180#[serde(rename_all = "camelCase")]
181pub struct Dataset {
182    /// Unique dataset ID.
183    pub id: String,
184    /// Technical name of the dataset, if named.
185    #[serde(default)]
186    pub name: Option<String>,
187    /// ID of the owner.
188    #[serde(default)]
189    pub user_id: Option<String>,
190    /// When the dataset was created.
191    #[serde(default)]
192    pub created_at: Option<DateTime<Utc>>,
193    /// When the dataset was last modified.
194    #[serde(default)]
195    pub modified_at: Option<DateTime<Utc>>,
196    /// Total number of items in the dataset.
197    #[serde(default)]
198    pub item_count: Option<i64>,
199    /// Any other fields returned by the API.
200    #[serde(flatten)]
201    pub extra: Extra,
202}
203
204/// A key-value store storage.
205#[derive(Debug, Clone, Deserialize, Serialize)]
206#[serde(rename_all = "camelCase")]
207pub struct KeyValueStore {
208    /// Unique store ID.
209    pub id: String,
210    /// Technical name of the store, if named.
211    #[serde(default)]
212    pub name: Option<String>,
213    /// ID of the owner.
214    #[serde(default)]
215    pub user_id: Option<String>,
216    /// When the store was created.
217    #[serde(default)]
218    pub created_at: Option<DateTime<Utc>>,
219    /// When the store was last modified.
220    #[serde(default)]
221    pub modified_at: Option<DateTime<Utc>>,
222    /// Any other fields returned by the API.
223    #[serde(flatten)]
224    pub extra: Extra,
225}
226
227/// Metadata about a single key in a key-value store.
228#[derive(Debug, Clone, Deserialize, Serialize)]
229#[serde(rename_all = "camelCase")]
230pub struct KeyValueStoreKey {
231    /// The record key.
232    pub key: String,
233    /// Size of the record value in bytes.
234    #[serde(default)]
235    pub size: Option<i64>,
236    /// Any other fields returned by the API.
237    #[serde(flatten)]
238    pub extra: Extra,
239}
240
241/// Result of listing keys in a key-value store (key-based pagination).
242#[derive(Debug, Clone, Deserialize, Serialize)]
243#[serde(rename_all = "camelCase")]
244pub struct KeyValueStoreKeysPage {
245    /// Maximum number of keys returned for this request.
246    #[serde(default)]
247    pub limit: i64,
248    /// Whether there are more keys to fetch.
249    #[serde(default)]
250    pub is_truncated: bool,
251    /// The key the listing started after.
252    #[serde(default)]
253    pub exclusive_start_key: Option<String>,
254    /// The value to use as `exclusive_start_key` for the next page.
255    #[serde(default)]
256    pub next_exclusive_start_key: Option<String>,
257    /// The keys of this page.
258    #[serde(default)]
259    pub items: Vec<KeyValueStoreKey>,
260}
261
262/// A record (key + value + content type) in a key-value store.
263#[derive(Debug, Clone)]
264pub struct KeyValueStoreRecord {
265    /// The record key.
266    pub key: String,
267    /// The raw value bytes.
268    pub value: Vec<u8>,
269    /// The MIME content type of the value, if reported by the API.
270    pub content_type: Option<String>,
271}
272
273impl KeyValueStoreRecord {
274    /// Interprets the value as UTF-8 text.
275    pub fn as_text(&self) -> Result<String, std::string::FromUtf8Error> {
276        String::from_utf8(self.value.clone())
277    }
278
279    /// Deserializes the value as JSON into `T`.
280    pub fn json<T: serde::de::DeserializeOwned>(&self) -> Result<T, serde_json::Error> {
281        serde_json::from_slice(&self.value)
282    }
283}
284
285/// A request queue storage.
286#[derive(Debug, Clone, Deserialize, Serialize)]
287#[serde(rename_all = "camelCase")]
288pub struct RequestQueue {
289    /// Unique queue ID.
290    pub id: String,
291    /// Technical name of the queue, if named.
292    #[serde(default)]
293    pub name: Option<String>,
294    /// ID of the owner.
295    #[serde(default)]
296    pub user_id: Option<String>,
297    /// When the queue was created.
298    #[serde(default)]
299    pub created_at: Option<DateTime<Utc>>,
300    /// When the queue was last modified.
301    #[serde(default)]
302    pub modified_at: Option<DateTime<Utc>>,
303    /// Total number of requests ever added.
304    #[serde(default)]
305    pub total_request_count: Option<i64>,
306    /// Any other fields returned by the API.
307    #[serde(flatten)]
308    pub extra: Extra,
309}
310
311/// A single request stored in a request queue.
312#[derive(Debug, Clone, Deserialize, Serialize)]
313#[serde(rename_all = "camelCase")]
314pub struct RequestQueueRequest {
315    /// Unique request ID (assigned by the API; omit when adding a new request).
316    #[serde(default, skip_serializing_if = "Option::is_none")]
317    pub id: Option<String>,
318    /// The URL to be processed.
319    pub url: String,
320    /// Unique key used for deduplication (defaults to `url`).
321    #[serde(default, skip_serializing_if = "Option::is_none")]
322    pub unique_key: Option<String>,
323    /// HTTP method, defaults to `GET`.
324    #[serde(default, skip_serializing_if = "Option::is_none")]
325    pub method: Option<String>,
326    /// Arbitrary user data attached to the request.
327    #[serde(default, skip_serializing_if = "Option::is_none")]
328    pub user_data: Option<Value>,
329    /// Any other fields returned by the API.
330    #[serde(flatten)]
331    pub extra: Extra,
332}
333
334/// Result of adding (or updating) a request in a queue.
335#[derive(Debug, Clone, Deserialize, Serialize)]
336#[serde(rename_all = "camelCase")]
337pub struct RequestQueueOperationInfo {
338    /// ID of the request that was added or updated.
339    pub request_id: String,
340    /// Whether the request was already present in the queue.
341    #[serde(default)]
342    pub was_already_present: bool,
343    /// Whether the request had already been handled.
344    #[serde(default)]
345    pub was_already_handled: bool,
346}
347
348/// The head of a request queue (requests waiting to be processed).
349#[derive(Debug, Clone, Deserialize, Serialize)]
350#[serde(rename_all = "camelCase")]
351pub struct RequestQueueHead {
352    /// Maximum number of requests returned.
353    #[serde(default)]
354    pub limit: i64,
355    /// Whether more than one client has accessed the queue.
356    #[serde(default)]
357    pub had_multiple_clients: bool,
358    /// The requests at the head of the queue.
359    #[serde(default)]
360    pub items: Vec<RequestQueueRequest>,
361    /// Any other fields returned by the API.
362    #[serde(flatten)]
363    pub extra: Extra,
364}
365
366/// A schedule that triggers Actor or task runs on a cron expression.
367#[derive(Debug, Clone, Deserialize, Serialize)]
368#[serde(rename_all = "camelCase")]
369pub struct Schedule {
370    /// Unique schedule ID.
371    pub id: String,
372    /// ID of the owner.
373    #[serde(default)]
374    pub user_id: Option<String>,
375    /// Technical name of the schedule.
376    #[serde(default)]
377    pub name: Option<String>,
378    /// The cron expression that determines when the schedule fires.
379    #[serde(default)]
380    pub cron_expression: Option<String>,
381    /// Whether the schedule is currently enabled.
382    #[serde(default)]
383    pub is_enabled: Option<bool>,
384    /// Any other fields returned by the API.
385    #[serde(flatten)]
386    pub extra: Extra,
387}
388
389/// A webhook that notifies an external URL on Actor events.
390#[derive(Debug, Clone, Deserialize, Serialize)]
391#[serde(rename_all = "camelCase")]
392pub struct Webhook {
393    /// Unique webhook ID.
394    pub id: String,
395    /// ID of the owner.
396    #[serde(default)]
397    pub user_id: Option<String>,
398    /// The URL that receives the webhook POST request.
399    #[serde(default)]
400    pub request_url: Option<String>,
401    /// Event types that trigger this webhook.
402    #[serde(default)]
403    pub event_types: Vec<String>,
404    /// Any other fields returned by the API.
405    #[serde(flatten)]
406    pub extra: Extra,
407}
408
409/// A single dispatch (invocation) of a webhook.
410#[derive(Debug, Clone, Deserialize, Serialize)]
411#[serde(rename_all = "camelCase")]
412pub struct WebhookDispatch {
413    /// Unique dispatch ID.
414    pub id: String,
415    /// ID of the webhook that produced this dispatch.
416    #[serde(default)]
417    pub webhook_id: Option<String>,
418    /// Any other fields returned by the API.
419    #[serde(flatten)]
420    pub extra: Extra,
421}
422
423/// Account information about a user.
424#[derive(Debug, Clone, Deserialize, Serialize)]
425#[serde(rename_all = "camelCase")]
426pub struct User {
427    /// Unique user ID.
428    pub id: String,
429    /// Username.
430    #[serde(default)]
431    pub username: Option<String>,
432    /// Any other fields returned by the API (public or private depending on the call).
433    #[serde(flatten)]
434    pub extra: Extra,
435}
436
437/// A single Actor entry as returned by the Apify Store listing.
438#[derive(Debug, Clone, Deserialize, Serialize)]
439#[serde(rename_all = "camelCase")]
440pub struct ActorStoreListItem {
441    /// Unique Actor ID.
442    pub id: String,
443    /// Technical name of the Actor.
444    #[serde(default)]
445    pub name: Option<String>,
446    /// Username of the Actor's owner.
447    #[serde(default)]
448    pub username: Option<String>,
449    /// Human-readable title.
450    #[serde(default)]
451    pub title: Option<String>,
452    /// Any other fields returned by the API.
453    #[serde(flatten)]
454    pub extra: Extra,
455}
456
457/// An Actor version.
458#[derive(Debug, Clone, Deserialize, Serialize)]
459#[serde(rename_all = "camelCase")]
460pub struct ActorVersion {
461    /// The version number, e.g. `0.1`.
462    pub version_number: String,
463    /// The source type of the version, e.g. `SOURCE_FILES`, `GIT_REPO`, `TARBALL`, `GITHUB_GIST`.
464    #[serde(default)]
465    pub source_type: Option<String>,
466    /// Any other fields returned by the API.
467    #[serde(flatten)]
468    pub extra: Extra,
469}
470
471/// An environment variable attached to an Actor version.
472#[derive(Debug, Clone, Deserialize, Serialize)]
473#[serde(rename_all = "camelCase")]
474pub struct ActorEnvVar {
475    /// The environment variable name.
476    pub name: String,
477    /// The value (may be omitted for secret variables in responses).
478    #[serde(default, skip_serializing_if = "Option::is_none")]
479    pub value: Option<String>,
480    /// Whether the variable is a secret.
481    #[serde(default, skip_serializing_if = "Option::is_none")]
482    pub is_secret: Option<bool>,
483    /// Any other fields returned by the API.
484    #[serde(flatten)]
485    pub extra: Extra,
486}