Skip to main content

apify_rs/resources/
tasks.rs

1use crate::client::HttpClient;
2use crate::error::ApifyError;
3use crate::models::{
4    CreateTaskRequest, DataResponse, ListData, ListParams, Run, RunParams,
5    Task, TaskShort, UpdateTaskRequest,
6};
7use reqwest::Method;
8use serde::Serialize;
9
10/// Operations on [Tasks](crate::models::Task).
11///
12/// A Task is a saved configuration for an Actor: it stores the Actor ID,
13/// input JSON, and run options.  Once created, a Task can be invoked
14/// repeatedly without re-sending the full input.
15pub struct TaskClient<'a> {
16    client: &'a HttpClient,
17}
18
19impl<'a> TaskClient<'a> {
20    pub(crate) fn new(client: &'a HttpClient) -> Self {
21        Self { client }
22    }
23
24    /// List Tasks with optional pagination.
25    pub async fn list(&self, params: Option<ListParams>) -> Result<ListData<TaskShort>, ApifyError> {
26        let mut path = "/actor-tasks".to_string();
27        if let Some(p) = params {
28            let query = serde_qs::to_string(&p).unwrap_or_default();
29            if !query.is_empty() {
30                path = format!("{}?{}", path, query);
31            }
32        }
33        self.client.get_list(&path).await
34    }
35
36    /// Create a new Task.
37    ///
38    /// # Example
39    /// ```ignore
40    /// let input = serde_json::json!({ "usernames": ["apify"] });
41    /// let task = client.tasks().create(CreateTaskRequest {
42    ///     act_id: "apify~instagram-profile-scraper".to_string(),
43    ///     name: Some("my-instagram-task".to_string()),
44    ///     options: None,
45    ///     input: Some(input),
46    ///     title: None,
47    /// }).await?;
48    /// ```
49    pub async fn create<T: Serialize>(
50        &self,
51        request: CreateTaskRequest<T>,
52    ) -> Result<Task, ApifyError> {
53        self.client.post_data("/actor-tasks", request).await
54    }
55
56    /// Fetch a Task by ID or qualified name (`username~task-name`).
57    pub async fn get(&self, task_id: &str) -> Result<Task, ApifyError> {
58        self.client.get_data(&format!("/actor-tasks/{}", task_id)).await
59    }
60
61    /// Update a Task.  Omitted fields leave the existing value unchanged.
62    pub async fn update<T: Serialize>(
63        &self,
64        task_id: &str,
65        request: UpdateTaskRequest<T>,
66    ) -> Result<Task, ApifyError> {
67        self.client
68            .put_data(&format!("/actor-tasks/{}", task_id), request)
69            .await
70    }
71
72    /// Delete a Task permanently.
73    pub async fn delete(&self, task_id: &str) -> Result<(), ApifyError> {
74        self.client
75            .delete_request(&format!("/actor-tasks/{}", task_id))
76            .await
77    }
78
79    /// Start a Task run **asynchronously**.
80    ///
81    /// Uses the Task's stored input.  Returns a [`Run`]
82    /// immediately while the container is queued / started.
83    pub async fn run(
84        &self,
85        task_id: &str,
86        params: Option<RunParams>,
87    ) -> Result<Run, ApifyError> {
88        let mut path = format!("/actor-tasks/{}/runs", task_id);
89        if let Some(p) = params {
90            let query = serde_qs::to_string(&p).unwrap_or_default();
91            if !query.is_empty() {
92                path = format!("{}?{}", path, query);
93            }
94        }
95        let resp: DataResponse<Run> = self.client.request(Method::POST, &path, None::<()>).await?;
96        Ok(resp.data)
97    }
98
99    /// Start a Task run **synchronously** (blocks up to 300 s).
100    ///
101    /// The HTTP response returns the finished [`Run`]
102    /// if it completes in time, otherwise a timeout error.
103    pub async fn run_sync(
104        &self,
105        task_id: &str,
106        params: Option<RunParams>,
107    ) -> Result<Run, ApifyError> {
108        let mut path = format!("/actor-tasks/{}/run-sync", task_id);
109        if let Some(p) = params {
110            let query = serde_qs::to_string(&p).unwrap_or_default();
111            if !query.is_empty() {
112                path = format!("{}?{}", path, query);
113            }
114        }
115        self.client.get_data(&path).await
116    }
117
118    /// Start a Task run synchronously and return the default Dataset items directly.
119    ///
120    /// This is the shortest path from "invoke Task" to "get typed results".
121    /// The request times out after 300 s if the run does not finish.
122    pub async fn run_sync_get_dataset_items<T: serde::de::DeserializeOwned>(
123        &self,
124        task_id: &str,
125        params: Option<RunParams>,
126    ) -> Result<Vec<T>, ApifyError> {
127        let mut path = format!("/actor-tasks/{}/run-sync-get-dataset-items", task_id);
128        if let Some(p) = params {
129            let query = serde_qs::to_string(&p).unwrap_or_default();
130            if !query.is_empty() {
131                path = format!("{}?{}", path, query);
132            }
133        }
134        let resp: DataResponse<Vec<T>> = self.client.request(Method::GET, &path, None::<()>).await?;
135        Ok(resp.data)
136    }
137
138    /// Retrieve the most recent Run of a Task.
139    pub async fn get_last_run(&self, task_id: &str) -> Result<Run, ApifyError> {
140        self.client
141            .get_data(&format!("/actor-tasks/{}/runs/last", task_id))
142            .await
143    }
144}