Skip to content
Closed
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
43 changes: 35 additions & 8 deletions .github/workflows/rust-integration-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ on:
- 'src/**'
- 'tests/**'
- 'examples/**'
- 'README.md'
- 'docs/**'
- 'build.rs'
- 'Cargo.toml'
- 'Cargo.lock'
- '.github/workflows/rust-integration-tests.yml'
workflow_dispatch:

Expand Down Expand Up @@ -69,20 +71,45 @@ jobs:
# programs in `tests/examples.rs` (test names prefixed `example_`) are exercised by the
# standalone `Test examples` step below, so they are skipped here to keep the two
# concerns separate.
run: cargo test --lib --tests --verbose -- --skip example_ --test-threads=4
#
# Defense-in-depth beyond the `APIFY_TOKEN` guard above: `set -o pipefail` plus the
# trailing grep make the step fail if cargo reports zero executed tests (e.g. a filter
# typo silently matching nothing), not just if a test fails outright.
run: |
set -o pipefail
cargo test --lib --tests --verbose -- --skip example_ --test-threads=4 | tee test_output.log
if ! grep -qE '[1-9][0-9]* passed' test_output.log; then
echo "::error::No tests were reported as passed; expected at least one 'N passed' summary line."
exit 1
fi

# Standalone CI step that verifies the documentation examples actually work. It runs the
# example programs from `examples/` end-to-end against the live API (via the `example_*`
# smoke tests in `tests/examples.rs`, each of which executes `cargo run --example <name>`)
# and runs the in-documentation code snippets as doctests (`cargo test --doc`, which
# compiles every fenced `rust` block in the README and the `docs/` pages and runs the
# runnable ones). Both are required by the documentation requirements: each documentation
# example has a CI test that actually runs the code.
# — this is the real runtime guard for the 7 documented examples. `cargo test --doc`
# compiles every fenced `rust`/`rust,no_run` block in the README and the `docs/` pages;
# almost all are `no_run`, so this is primarily a compile-check (it also executes the one
# genuinely runnable snippet, `README.md`'s Versioning example). Both are required by the
# documentation requirements: each documentation example has a CI test that exercises it.
- name: Test examples
env:
APIFY_TOKEN: ${{ secrets.APIFY_TOKEN }}
# Match the integration-test thread cap so the example programs and any doctests that hit
# the live API stay gentle on the shared account.
#
# Same defense-in-depth as the "Run integration tests" step above: `set -o pipefail` plus
# a trailing grep make the step fail if either command reports zero executed tests (e.g.
# a filter typo, or every example/doctest silently being skipped), not just on an outright
# test failure.
run: |
cargo test --test examples --verbose -- --test-threads=4
cargo test --doc --verbose -- --test-threads=4
set -o pipefail
cargo test --test examples --verbose -- --test-threads=4 | tee examples_output.log
if ! grep -qE '[1-9][0-9]* passed' examples_output.log; then
echo "::error::No example tests were reported as passed; expected at least one 'N passed' summary line."
exit 1
fi
cargo test --doc --verbose -- --test-threads=4 | tee doctest_output.log
if ! grep -qE '[1-9][0-9]* passed' doctest_output.log; then
echo "::error::No doctests were reported as passed; expected at least one 'N passed' summary line."
exit 1
fi
72 changes: 65 additions & 7 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,68 @@ 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-07-25

### Added
- `RunClient::get_with_options`/`RunGetOptions` and `BuildClient::get_with_options`/`BuildGetOptions` for the `waitForFinish` server-side wait, also usable via `actor.last_run()`/`task.last_run()`.
- `DatasetCollectionClient::get_or_create_with_options`/`DatasetGetOrCreateOptions` and the key-value-store equivalent, adding the JS-reference-only `schema` body field.
- `RequestQueueClient::batch_add_requests_with_options`/`BatchAddRequestsOptions`: byte-size chunk slicing, concurrent chunk calls, and retried `unprocessedRequests`, matching the JS reference. `batch_add_requests` now delegates to it.
- `examples/tasks_schedules_webhooks.rs`.
- `tests/actor_run.rs::run_scoped_storage_update_and_delete`, covering run-scoped storage PUT/DELETE (previously GET-only).

### Changed
- Bumped `API_SPEC_VERSION` to `v2-2026-07-23T070817Z` and crate version to `0.7.0`.
- Removed the duplicated AI-generated/maintained notice; stated once in `README.md`.
- **Behavior change:** `batch_add_requests` folds a failed chunk's requests into `unprocessedRequests` instead of returning `Err`.
- **Behavior/API change:** `TaskClient::start`/`call` take new `TaskStartOptions`/`TaskCallOptions` instead of `ActorStartOptions`, matching the JS reference's narrower type and fixing a stray `forcePermissionLevel` param plus a dropped `content_type`.
- **Behavior/API change:** `ActorClient::call` takes new `ActorCallOptions` (drops `wait_for_finish`), fixing a footgun where it could block server-side before `call`'s own polling began.
- **Behavior/API change:** `ActorClient::validate_input`/`validate_input_for_build` return `bool` instead of the raw response envelope.
- **Behavior/API change:** `WebhookClient::test` returns `Option<WebhookDispatch>` (`None` on 404).
- **Behavior/API change:** `LogClient::stream`/`stream_with_options` and `RunClient::get_streamed_log*` return `Option<impl Stream<..>>` (`None` on 404).
- **Behavior/API change:** `UserClient::monthly_usage`/`monthly_usage_for_date`/`limits` return `Option<serde_json::Value>`.
- `ActorVersionCollectionClient::list` no longer sends `offset`/`limit`/`desc` (the endpoint defines none).
- `request_queue.rs::random_fraction` now reuses the shared `http_client::next_jitter` generator instead of a second `SystemTime`-seeded source.

### Fixed
- `RequestQueueClient` per-method timeouts now match the JS reference (5s/30s) instead of the 360s default.
- `RequestQueueClient::get_request` no longer sends `clientKey`, matching the JS reference.
- `common::short_unique_name` truncates the prefix (not the random suffix), fixing a name collision across concurrent suite runs.
- `rust-integration-tests.yml`'s `Test examples` step now fails on zero executed tests, matching the main test step.
- `rust-integration-tests.yml`'s path filter now includes `README.md`, `docs/**`, `build.rs`, and drops the inert (gitignored) `Cargo.lock` entry.
- `tests/config.rs::make_client_honors_apify_api_url_env` no longer mutates the real `APIFY_TOKEN`/`APIFY_API_URL` env vars, avoiding a race with concurrent tests.
- Batch-add's error-path `unprocessedRequests` entries omit `method` when absent instead of serializing `"method": null`.
- `validate_input`/`validate_input_for_build` default a missing `valid` field to `false` instead of erroring, matching the JS reference's falsy-on-`undefined` behavior.

### Documentation
- Documented `batch_add_requests_with_options`/`BatchAddRequestsOptions`, `ActorVersionClient`/`ActorEnvVarClient` (+ collections), `with_client_key`, and "Creating a …" sections for tasks/schedules/webhooks/Actors.
- Fixed a self-contradictory `docs/README.md` error-handling example.
- Added `BatchAddRequestsOptions`/`TaskStartOptions`/`TaskCallOptions`/`ActorVersion`/`ActorEnvVar` to `docs/README.md`'s Imports/model lists.
- Filled in previously-undocumented field types across `ActorListOptions.sort_by`, `LastRunOptions`, `StoreListOptions`, `ListKeysOptions`, `GetRecordOptions`, `ListRequestsOptions`, `DatasetListItemsOptions`, `DatasetDownloadOptions`, `ActorBuildOptions`, `RunResurrectOptions`, `RunMetamorphOptions`, `RunChargeOptions`, and `docs/schedules.md`'s create fields.
- Corrected `with_client_key`'s scope description and the request-lock example in `docs/storages.md`.
- Corrected three doc comments that overstated JS-parity (`KeyValueStoreKeysIterator`, `get_streamed_log`, the compress-once rationale in `src/http_client.rs`); the last was also consolidated into one explanation with a one-line pointer.
- `src/lib.rs`/`src/http_client.rs`/`README.md` no longer claim parity with a non-JS reference client.
- Tightened the `ACTOR_RUN_ID` justification comment in `tests/actor_run.rs` and dropped review-round provenance from `tests/unit_http.rs` doc comments.
- Documented `RunClient`/`BuildClient::get_with_options` and `DatasetCollectionClient`/`KeyValueStoreCollectionClient::get_or_create_with_options` (and their option types) in `docs/runs.md`/`docs/builds.md`/`docs/storages.md`/`docs/README.md`.
- Corrected the `start`/`call` argument-type notation in `docs/actors.md`/`docs/tasks.md` (generic `<T: Serialize>`, not argument-position `impl Trait`), matching the turbofish usage in every example.
- Qualified `paginate_requests`'s doc to not oversell an `exclusiveStartId` capability the method doesn't expose.
- Corrected `rust-integration-tests.yml`'s `Test examples` step comment to say it compile-checks the doc examples (only one is genuinely runnable), rather than implying broad runtime execution.

### Internal
- Extracted shared helpers (`last_run_client`, `is_terminal_status`, `encode_webhooks`) to remove near-duplicate code; removed `WebhookCollectionClient::with_base` (identical to `new`).
- Removed the unused `_root: ApifyClient` parameter from `RunClient::new`.
- Named the SplitMix64 mixing constants in `http_client.rs::next_jitter` (now `pub(crate)`, reused by `request_queue.rs`).
- Reused `common::NOT_FOUND_STATUS_CODE` in `log.rs`'s stream 404 check instead of a raw literal; named the `request_queue.rs` empty-array byte constant; promoted the `Content-Encoding` header literals in `http_client.rs` to a `HEADER_CONTENT_ENCODING` const.

### Tests
- Added a live assertion for the standalone `ApifyClient::log(id)` accessor.
- Added hermetic coverage for `TaskStartOptions`/`ActorCallOptions` query-param mapping.
- Added `tests/actor.rs::actor_webhooks_and_default_build` (`ActorClient::webhooks()`/`default_build()`) and `tests/key_value_store.rs::keys_public_url_is_fetchable`.
- Documented why the `ACTOR_RUN_ID` mutation in `tests/actor_run.rs` is race-free.
- Added hermetic coverage for `validate_input`'s bare-body unwrap and the `WebhookClient::test`/`LogClient::stream` 404-to-`None` mappings.
- Replaced a tautological `total >= 0` assertion with a load-bearing empty-collection check in `actor_webhooks_and_default_build`.
- Strengthened ~14 further tautological `assert!(total >= 0)` list-GET assertions into load-bearing consistency (`items.len() <= limit`, checked against the same response's `limit` rather than `total` since the latter raced under `cargo test --all-targets`'s concurrent account load) or known-empty-collection checks.
- Made `tests/webhook.rs::webhook_definition` embed a unique fragment per call, matching the suite's UUID-isolation convention.

## [0.6.1] - 2026-07-14

### Changed
Expand Down Expand Up @@ -48,9 +110,8 @@ to [Semantic Versioning](https://semver.org/).
- Bumped crate version to `0.6.0`.

### Removed
- `KeyValueStoreClient::get_records` and `GetRecordsOptions`. The `GET /v2/key-value-stores/{storeId}/records`
endpoint is not implemented by the reference JS client, so it is out of scope; its removal
corrects an earlier scope violation.
- `KeyValueStoreClient::get_records` and `GetRecordsOptions`
(`GET /v2/key-value-stores/{storeId}/records`).

### Documentation
- Documented all `ActorStartOptions` fields in `docs/actors.md` (added the previously undocumented
Expand Down Expand Up @@ -102,10 +163,7 @@ to [Semantic Versioning](https://semver.org/).
## [0.4.6] - 2026-07-07

### Changed
- Rewrote earlier `CHANGELOG.md` entries to satisfy the changelog requirements: condensed
narrative prose into short change bullets and removed cross-client references to sibling
implementations, references to requirement-tracking issues, and out-of-scope / not-implemented
notes.
- Condensed earlier `CHANGELOG.md` entries into short change bullets.
- Bumped crate version to `0.4.6`.

## [0.4.5] - 2026-07-03
Expand Down
6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
[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)."
description = "Rust client for the Apify API (https://apify.com)."
license = "Apache-2.0"
edition = "2021"
repository = "https://github.com/apify/apify-client-rust"
Expand All @@ -28,7 +28,7 @@ brotli = "7"
flate2 = "1"

[dev-dependencies]
tokio = { version = "1", features = ["macros", "rt-multi-thread", "time"] }
tokio = { version = "1", features = ["macros", "rt-multi-thread", "time", "net", "io-util"] }
uuid = { version = "1", features = ["v4"] }

[features]
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@

An idiomatic Rust client for the [Apify API](https://docs.apify.com/api/v2).
It provides a resource-oriented, async interface that mirrors the official
[JavaScript](https://github.com/apify/apify-client-js) and
[Python](https://github.com/apify/apify-client-python) clients.
[JavaScript client](https://github.com/apify/apify-client-js).

- Async (Tokio-friendly), built on `reqwest`.
- Transparent authentication, retries with exponential backoff, and timeouts.
Expand All @@ -22,7 +21,7 @@ It provides a resource-oriented, async interface that mirrors the official

```toml
[dependencies]
apify-client = "0.6"
apify-client = "0.7"
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
serde_json = "1" # for the `serde_json::Value` responses used in the Quick start
```
Expand Down Expand Up @@ -50,7 +49,7 @@ project needs `serde_json`. Two more dependencies are needed only for specific f
By default the client uses the system TLS (`native-tls`). To use rustls instead:

```toml
apify-client = { version = "0.6", default-features = false, features = ["rustls"] }
apify-client = { version = "0.7", default-features = false, features = ["rustls"] }
```

## Quick start
Expand Down Expand Up @@ -220,6 +219,7 @@ run with `cargo run --example <name>`:
- `iterate_store` — lazily iterate Actors in the Apify Store.
- `log_redirection` — run a separate Actor and redirect its run log into your output live, with each line prefixed by the source Actor's name.
- `raw_log` — fetch and stream a run's raw (unprocessed) log via `LogOptions { raw: Some(true) }`.
- `tasks_schedules_webhooks` — create an Actor task, a schedule that runs it, and a webhook that watches it.

See [`docs/`](docs) for the full API documentation.

Expand Down
Loading
Loading