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}