Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,22 @@ All notable changes to the Rust Apify API client are documented here. The format
based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project adheres
to [Semantic Versioning](https://semver.org/).

## [0.7.0] - 2026-08-10

### Added
- `TaskClient::publish()` and `TaskClient::unpublish()`, setting `isPublic` via `update` to
publish/unpublish a task on its public landing page, matching the reference client.

### Changed
- Bumped `API_SPEC_VERSION` to `v2-2026-08-05T133145Z`. The spec delta (relaxed field
nullability, e.g. `Webhook.requestUrl`/`TaggedBuildInfo.buildNumber`, and additional
documented `402`/`404`/`408`/`409` error responses) needs no other code change: response
models are forward-compatible and error responses are handled generically.
- Removed the duplicated "official, but experimental, AI-generated and AI-maintained" notice
from the crate-level rustdoc and `docs/README.md`; it now appears only once, in the
top-level `README.md`.
- Bumped crate version to `0.7.0`.

## [0.6.1] - 2026-07-14

### Changed
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "apify-client"
version = "0.6.1"
version = "0.7.0"
authors = ["Apify Technologies <support@apify.com>"]
description = "An official, but experimental, AI-generated and AI-maintained Rust client for the Apify API (https://apify.com)."
license = "Apache-2.0"
Expand Down
4 changes: 0 additions & 4 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
# Apify Rust client — documentation

> **Official, but experimental — AI-generated and AI-maintained.** This is an official Apify
> client, but it is experimental: it is generated and maintained by AI. Review the code before
> relying on it in production and report issues on the repository.

This directory documents the public API of the Apify Rust client. The same descriptions
are available as rustdoc comments and can be browsed with `cargo doc --open`.

Expand Down
2 changes: 2 additions & 0 deletions docs/tasks.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ Obtained via `client.tasks()` (collection) and `client.task(id)` (single).
|---|---|---|---|
| `get()` | — | `Option<Task>` | Fetches the task. |
| `update(fields)` | `&impl Serialize` | `Task` | Updates the task. |
| `publish()` | — | `Task` | Publishes the task on its public landing page (sets `isPublic: true`). Requires the task's Actor to be public and the task to have `publicConfig` set up. |
| `unpublish()` | — | `Task` | Unpublishes the task from its public landing page (sets `isPublic: false`), preserving `publicConfig`. |
| `delete()` | — | `()` | Deletes the task. |
| `start(input, options)` | `Option<&impl Serialize>`, `ActorStartOptions` | `ActorRun` | Starts a run. See [`ActorStartOptions`](actors.md#actorstartoptions) for the full field list. |
| `call(input, options, wait_secs)` | `Option<&impl Serialize>`, `ActorStartOptions`, `Option<i64>` | `ActorRun` | Starts a run and waits. Same [`ActorStartOptions`](actors.md#actorstartoptions) as `start`. |
Expand Down
19 changes: 19 additions & 0 deletions src/clients/task.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,25 @@ impl TaskClient {
delete_resource(&self.ctx, None).await
}

/// Publishes the task on its public landing page, by setting `isPublic: true` through
/// [`TaskClient::update`].
///
/// The task's Actor must be public and the task must already have its public display
/// configuration (`publicConfig`) set up. Publishing an already-published task does nothing.
pub async fn publish(&self) -> ApifyClientResult<Task> {
self.update(&serde_json::json!({ "isPublic": true })).await
}

/// Unpublishes the task from its public landing page, by setting `isPublic: false` through
/// [`TaskClient::update`].
///
/// The public display configuration (`publicConfig`) is preserved, so the task can be
/// published again later without re-entering it. Unpublishing a task that is not published
/// does nothing.
pub async fn unpublish(&self) -> ApifyClientResult<Task> {
self.update(&serde_json::json!({ "isPublic": false })).await
}

/// Starts the task and returns immediately with the created run.
///
/// `input` overrides the task's saved input (or `None` to use the saved input).
Expand Down
4 changes: 0 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
//! # apify-client
//!
//! **Official, but experimental — AI-generated and AI-maintained.** This is an official Apify
//! client, but it is experimental: it is generated and maintained by AI. Review the code before
//! relying on it in production and report issues on the repository.
//!
//! An idiomatic Rust client for the [Apify API](https://docs.apify.com/api/v2).
//!
//! It provides a resource-oriented interface that mirrors the official
Expand Down
2 changes: 1 addition & 1 deletion src/version.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ pub const CLIENT_VERSION: &str = env!("CARGO_PKG_VERSION");
/// and verified against.
///
/// This corresponds to the `info.version` field of the Apify OpenAPI document.
pub const API_SPEC_VERSION: &str = "v2-2026-07-13T092445Z";
pub const API_SPEC_VERSION: &str = "v2-2026-08-05T133145Z";
43 changes: 43 additions & 0 deletions tests/task.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,49 @@ async fn iterate_tasks() {
);
}

/// `publish`/`unpublish` are thin wrappers around `update` that flip `isPublic`. Unpublishing an
/// already-unpublished task is a documented no-op, so it round-trips cleanly; publishing a task
/// requires write permission over its Actor (here the shared, Apify-owned `apify/hello-world`,
/// per [`task_definition`]), so the API is expected to reject it with `insufficient-permissions` -
/// this exercises the same request path without needing a private Actor the test account can
/// actually publish (which would additionally require an SEO description, an input field
/// selection, and a dataset view set up on the task's public display configuration).
#[tokio::test(flavor = "multi_thread")]
async fn task_publish_unpublish() {
let client = require_client!();
let name = common::unique_name("task-publish");
let task = client
.tasks()
.create(&task_definition(&name))
.await
.expect("create task");

let cleanup_client = client.clone();
let id = task.id.clone();
let _guard = common::Cleanup::new(move || async move {
let _ = cleanup_client.task(&id).delete().await;
});

let task_client = client.task(&task.id);

let unpublished = task_client
.unpublish()
.await
.expect("unpublish an already-unpublished task should be a no-op");
assert_eq!(unpublished.extra.get("isPublic"), Some(&json!(false)));

match task_client.publish().await {
Err(apify_client::ApifyClientError::Api(err)) => {
assert_eq!(err.status_code, 403);
assert_eq!(err.error_type.as_deref(), Some("insufficient-permissions"));
}
other => panic!(
"expected publish() on a task for an Actor we don't own to fail with \
`insufficient-permissions`, got {other:?}"
),
}
}

/// Complex flow: create a task for the public hello-world Actor, get it, update its input,
/// list its runs, and delete it.
#[tokio::test(flavor = "multi_thread")]
Expand Down
Loading