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
46 changes: 46 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,52 @@ All notable changes to the Apify Java client are documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project
adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.4.0] - 2026-07-20

### Changed (breaking)

- Reorganized `com.apify.client` into resource-oriented sub-packages: `actor`, `build`, `run`,
`dataset`, `keyvalue`, `requestqueue`, `task`, `schedule`, `webhook`, `user`, `log`, `store`, and
`http` (the replaceable transport). `ApifyClient`, `ApifyClientBuilder`, `ApifyApiException`,
`ApifyTransportException`, `Version`, and the shared list/pagination types (`ListOptions`,
`StorageListOptions`, `PaginationList`) remain in the root `com.apify.client` package.
- Renamed `HttpBackend` to `HttpClient` and `DefaultHttpBackend` to `DefaultApifyHttpClient`, to
avoid confusion with the JDK's own `java.net.http.HttpClient`.
- Renamed `HttpClient.sendStreaming` to `sendStreamingResponse` (it streams the response, not the
request).
- `HttpClientCore.TransportException` is now the top-level, public `ApifyTransportException`
(previously a nested, internal-only type, despite already being thrown across the public API on
an exhausted transport-failure retry budget).
- `ApifyClientBuilder.build()` now validates its configuration (a blank base URL, a negative retry
count, or a negative duration) and throws `IllegalArgumentException`, instead of failing later
with a confusing, indirect error.

### Changed

- `DatasetClient`/`KeyValueStoreClient` are now fully immutable after construction: the
public-base-URL override is resolved in the constructor instead of by a post-construction
mutator.
- `HttpClientCore` deserializes the API's error envelope via a typed Jackson DTO instead of manual
`JsonNode` navigation, and parses the request path via `java.net.URI` instead of manual string
slicing.
- Broadened transport-timeout detection (`doNotRetryTimeouts`) to also recognize
`SocketTimeoutException`, not just the default backend's `HttpTimeoutException`, so a custom
`HttpClient` implementation gets the same retry behavior.
- Consolidated every resource's API path segment (`datasets`, `actor-builds`, `webhooks`, ...) into
a single internal `ResourcePaths` class instead of duplicating literals between `ApifyClient` and
each resource client.
- Lowered `DefaultApifyHttpClient`'s connection-establishment timeout from 30s to 10s.
- Bumped the Jackson dependency to 2.19.4.
- The brotli4j native compression codec is no longer bundled by default; gzip remains the automatic
fallback, and brotli can be opted into by adding the platform-appropriate native artifact.
- Added an SLF4J logging facade dependency (no implementation bundled); the client now logs
retry/backoff and give-up events.
- Tightened the "official, but experimental" disclaimer wording (it repeated itself) across the
README, documentation, and Javadoc.
- README: trimmed the quick-start example, clarified what `Version.API_SPEC_VERSION` means, used
`Optional.ifPresent` in the single-resource example, documented the client's synchronous and
thread-safe nature, and added a resource-to-package table.

## [0.3.1] - 2026-07-14

### Added
Expand Down
149 changes: 75 additions & 74 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
# Apify API client for Java

> **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.
> **Official, but experimental — AI-generated and AI-maintained.** Review the code before relying
> on it in production and report issues on the repository.

A resource-oriented Java client for the [Apify API](https://docs.apify.com/api/v2), mirroring the
official [JavaScript](https://github.com/apify/apify-client-js) reference client: start from an
Expand All @@ -23,7 +22,7 @@ Maven (Maven Central is a default repository, so no extra configuration is neede
<dependency>
<groupId>com.apify</groupId>
<artifactId>apify-client</artifactId>
<version>0.3.1</version>
<version>0.4.0</version>
</dependency>
```

Expand All @@ -35,40 +34,19 @@ repositories {
}

dependencies {
implementation 'com.apify:apify-client:0.3.1'
implementation 'com.apify:apify-client:0.4.0'
}
```

## Quick start

A complete, copy-pasteable first program (save as `HelloApify.java`). First scaffold a minimal
`pom.xml` next to it so Maven can resolve the client and its runtime dependencies:

```xml
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>hello-apify</artifactId>
<version>1.0.0</version>
<properties>
<maven.compiler.release>17</maven.compiler.release>
</properties>
<dependencies>
<dependency>
<groupId>com.apify</groupId>
<artifactId>apify-client</artifactId>
<version>0.3.1</version>
</dependency>
</dependencies>
</project>
```

Create `HelloApify.java`:
A complete, copy-pasteable first program. Add the client as a dependency in your project (see
Installation above), then run this as `HelloApify.java`:

```java
import com.apify.client.ApifyClient;
import com.apify.client.ActorRun;
import com.apify.client.ActorStartOptions;
import com.apify.client.actor.ActorStartOptions;
import com.apify.client.run.ActorRun;

class HelloApify {
public static void main(String[] args) {
Expand All @@ -80,23 +58,21 @@ class HelloApify {
}
```

Then populate a `lib/` directory with the client and its runtime dependencies, and compile and run
against the JVM's `lib/*` classpath wildcard — quote it so the shell does not expand it:

```bash
# 1. Collect apify-client and its runtime dependencies (Jackson, brotli4j codecs, …) into lib/.
mvn dependency:copy-dependencies -DoutputDirectory=lib -DincludeScope=runtime

# 2. Compile and run. '.' is for the compiled HelloApify.class; lib/* is the JVM classpath wildcard.
javac -cp '.:lib/*' HelloApify.java # Windows: javac -cp ".;lib/*" HelloApify.java
java -cp '.:lib/*' HelloApify # Windows: java -cp ".;lib/*" HelloApify
```

The remaining snippets below are fragments that assume a configured `client` and these imports: all
public client types live in the `com.apify.client` package (e.g. `import com.apify.client.*;`); the
snippets also use `com.fasterxml.jackson.databind.JsonNode` (from the Jackson dependency) for untyped
data, `java.time.Duration` in the configuration examples, and standard JDK types such as
`java.util.Optional` and `java.util.Map` (`import java.util.*;`).
The client is synchronous (each call blocks until the HTTP response arrives, there is no async or
reactive variant) and, once built via [`ApifyClient.create`](#quick-start) or
[`ApifyClient.builder()`](#configuration), safe for concurrent use from multiple threads: an
`ApifyClient` and the resource clients it returns carry no mutable state after construction.

The remaining snippets below are fragments that assume a configured `client` and these imports: the
client's types are organized by resource into sub-packages of `com.apify.client` (`actor`, `build`,
`run`, `dataset`, `keyvalue`, `requestqueue`, `task`, `schedule`, `webhook`, `user`, `log`, `store`,
and `http` for the replaceable transport), with `ApifyClient`, `Version`, `ApifyApiException` and the
shared list/pagination types staying in the `com.apify.client` root package — see
[`docs/`](docs/README.md) for the exact package of each type, or import every package with one
wildcard each (`import com.apify.client.*; import com.apify.client.actor.*; …`). The snippets also
use `com.fasterxml.jackson.databind.JsonNode` (from the Jackson dependency) for untyped data,
`java.time.Duration` in the configuration examples, and standard JDK types such as `java.util.Optional`
and `java.util.Map` (`import java.util.*;`).

```java
ApifyClient client = ApifyClient.create("my-api-token");
Expand Down Expand Up @@ -137,29 +113,46 @@ ApifyClient configured =

### Replaceable HTTP transport

The transport is a replaceable component. The default is `DefaultHttpBackend` (backed by the JDK's
`java.net.http.HttpClient`); provide your own `HttpBackend` to share a connection pool or customize
proxy/TLS:
The transport is a replaceable component, defined by the `com.apify.client.http.HttpClient`
interface (distinct from the JDK's own `java.net.http.HttpClient`, which the default implementation
happens to use under the hood — always refer to the JDK one by its fully-qualified name to avoid
ambiguity, as the snippet below does). The default is `DefaultApifyHttpClient`; provide your own
`HttpClient` to share a connection pool or customize proxy/TLS:

```java
HttpBackend backend = new DefaultHttpBackend(java.net.http.HttpClient.newHttpClient());
HttpClient backend = new DefaultApifyHttpClient(java.net.http.HttpClient.newHttpClient());
ApifyClient withBackend = ApifyClient.builder().token("t").httpBackend(backend).build();
```

Cross-cutting behaviour applied to every request lives in the client, not the backend:
bearer-token authentication, the mandated `User-Agent` header, and retries with exponential
backoff and jitter on `429`, `5xx` and network errors.

### Logging

The client logs retry/backoff and give-up events through [SLF4J](https://www.slf4j.org/) (a facade
only — no logging implementation is bundled). Add an SLF4J binding of your choice (e.g. Logback) to
your own project's dependencies to see these logs; with no binding present, SLF4J silently discards
them, so this is safe to leave unconfigured.

### Request-body compression

Request bodies of 1024 bytes or more are compressed before sending, preferring
[brotli](https://github.com/hyperxpro/Brotli4j) (`Content-Encoding: br`) and falling back to gzip.
The brotli native codec is **not** bundled by default (it is platform-specific, and forcing every
consumer to pull down every OS/architecture's native binary is wasteful) — without it the client
transparently uses gzip, which is fully functional on its own. To opt into brotli, add both
`com.aayushatharva.brotli4j:brotli4j` and your platform's `com.aayushatharva.brotli4j:native-<os>-<arch>`
artifact (matching the brotli4j version this client compiles against — see `pom.xml`) as
dependencies of your own project.

## Fetching single resources

Methods that fetch a single resource return an `Optional<T>`: a missing resource is reported by an
empty `Optional` rather than an exception.

```java
Optional<Actor> maybeActor = client.actor("apify/hello-world").get();
if (maybeActor.isPresent()) {
System.out.println(maybeActor.get().getTitle());
}
client.actor("apify/hello-world").get().ifPresent(actor -> System.out.println(actor.getTitle()));
```

## Error handling
Expand Down Expand Up @@ -189,12 +182,16 @@ try {
The public `com.apify.client.Version` class (`import com.apify.client.Version;`) exposes two
constants:

- `Version.CLIENT_VERSION` — the semantic version of this client (`0.3.1`).
- `Version.API_SPEC_VERSION` — the Apify OpenAPI specification version this client was verified
against (`v2-2026-07-13T092445Z`).
- `Version.CLIENT_VERSION` — the semantic version of this client (`0.4.0`).
- `Version.API_SPEC_VERSION` — the version of the [Apify OpenAPI specification](https://docs.apify.com/api/openapi.json)
(its `info.version`, e.g. `v2-2026-07-13T092445Z`) that this release of the client was last
checked and updated against. It is a point-in-time reference for maintainers, not a compatibility
guarantee: the client also works against other spec versions, since the Apify API is additive and
backwards-compatible in practice.

Changes to the public interface other than additive ones are considered breaking changes and follow
[Semantic Versioning](https://semver.org/).
[Semantic Versioning](https://semver.org/). See [`CHANGELOG.md`](CHANGELOG.md) for the list of
changes in each release, including breaking ones (e.g. `0.4.0`'s package reorganization).

### Releasing

Expand Down Expand Up @@ -234,21 +231,25 @@ Full documentation is in the [`docs/`](docs/README.md) directory, organized by r

## Resources

| Accessor | Client | Description |
|---|---|---|
| `actors()` / `actor(id)` | `ActorCollectionClient` / `ActorClient` | Actors |
| `builds()` / `build(id)` | `BuildCollectionClient` / `BuildClient` | Actor builds |
| `runs()` / `run(id)` | `RunCollectionClient` / `RunClient` | Actor runs |
| `datasets()` / `dataset(id)` | `DatasetCollectionClient` / `DatasetClient` | Datasets |
| `keyValueStores()` / `keyValueStore(id)` | `KeyValueStoreCollectionClient` / `KeyValueStoreClient` | Key-value stores |
| `requestQueues()` / `requestQueue(id)` | `RequestQueueCollectionClient` / `RequestQueueClient` | Request queues |
| `tasks()` / `task(id)` | `TaskCollectionClient` / `TaskClient` | Actor tasks |
| `schedules()` / `schedule(id)` | `ScheduleCollectionClient` / `ScheduleClient` | Schedules |
| `webhooks()` / `webhook(id)` | `WebhookCollectionClient` / `WebhookClient` | Webhooks |
| `webhookDispatches()` / `webhookDispatch(id)` | `WebhookDispatchCollectionClient` / `WebhookDispatchClient` | Webhook dispatches |
| `store()` | `StoreCollectionClient` | Apify Store |
| `me()` / `user(id)` | `UserClient` | Users |
| `log(id)` | `LogClient` | Build/run logs |
Each resource's classes live in their own sub-package of `com.apify.client` (see the Package
column); `ApifyClient` itself, and the shared list/pagination types, stay in the root
`com.apify.client` package.

| Accessor | Client | Package | Description |
|---|---|---|---|
| `actors()` / `actor(id)` | `ActorCollectionClient` / `ActorClient` | `com.apify.client.actor` | Actors |
| `builds()` / `build(id)` | `BuildCollectionClient` / `BuildClient` | `com.apify.client.build` | Actor builds |
| `runs()` / `run(id)` | `RunCollectionClient` / `RunClient` | `com.apify.client.run` | Actor runs |
| `datasets()` / `dataset(id)` | `DatasetCollectionClient` / `DatasetClient` | `com.apify.client.dataset` | Datasets |
| `keyValueStores()` / `keyValueStore(id)` | `KeyValueStoreCollectionClient` / `KeyValueStoreClient` | `com.apify.client.keyvalue` | Key-value stores |
| `requestQueues()` / `requestQueue(id)` | `RequestQueueCollectionClient` / `RequestQueueClient` | `com.apify.client.requestqueue` | Request queues |
| `tasks()` / `task(id)` | `TaskCollectionClient` / `TaskClient` | `com.apify.client.task` | Actor tasks |
| `schedules()` / `schedule(id)` | `ScheduleCollectionClient` / `ScheduleClient` | `com.apify.client.schedule` | Schedules |
| `webhooks()` / `webhook(id)` | `WebhookCollectionClient` / `WebhookClient` | `com.apify.client.webhook` | Webhooks |
| `webhookDispatches()` / `webhookDispatch(id)` | `WebhookDispatchCollectionClient` / `WebhookDispatchClient` | `com.apify.client.webhook` | Webhook dispatches |
| `store()` | `StoreCollectionClient` | `com.apify.client.store` | Apify Store |
| `me()` / `user(id)` | `UserClient` | `com.apify.client.user` | Users |
| `log(id)` | `LogClient` | `com.apify.client.log` | Build/run logs |

## License

Expand Down
21 changes: 14 additions & 7 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
# Apify Java 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.
> **Official, but experimental — AI-generated and AI-maintained.** Review the code before relying
> on it in production and report issues on the repository.

This directory documents the public API of the Apify Java client, organized by resource. Each page
lists the available methods with their parameters and short snippets. The snippets are code
Expand Down Expand Up @@ -31,10 +30,18 @@ empty `Optional` rather than an exception. API failures are thrown as `ApifyApiE

## Imports and dependencies

Snippets in these docs assume the client types are imported from `com.apify.client` (e.g.
`import com.apify.client.*;`) plus standard-library types (`java.util.List`, `java.util.ArrayList`,
`java.util.Map`, `java.util.Optional`, `java.util.Iterator`, `java.util.function.Consumer`,
`java.time.Duration`, `java.io.InputStream`).
The client's classes are organized by resource into sub-packages of `com.apify.client`: `actor`,
`build`, `run`, `dataset`, `keyvalue`, `requestqueue`, `task`, `schedule`, `webhook`, `user`, `log`,
`store`, and `http` (the replaceable transport). `ApifyClient`, `ApifyClientBuilder`,
`ApifyApiException`, `Version`, and the shared list/pagination types (`ListOptions`,
`StorageListOptions`, `PaginationList`) stay in the `com.apify.client` root package. See each
resource page for its exact package, or import every sub-package's classes with one wildcard
per package (e.g. `import com.apify.client.*; import com.apify.client.actor.*; import
com.apify.client.dataset.*; …`).

Snippets in these docs additionally assume standard-library types (`java.util.List`,
`java.util.ArrayList`, `java.util.Map`, `java.util.Optional`, `java.util.Iterator`,
`java.util.function.Consumer`, `java.time.Duration`, `java.io.InputStream`).

Raw-JSON return values use Jackson's `com.fasterxml.jackson.databind.JsonNode`. Jackson is a
transitive dependency of this client, so it is already on your classpath.
Expand Down
5 changes: 2 additions & 3 deletions docs/actors.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
# Actors, versions & environment variables

> **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.
> **Official, but experimental — AI-generated and AI-maintained.** Review the code before relying
> on it in production and report issues on the repository.

Access the Actor collection with `client.actors()` and a single Actor with `client.actor(id)`,
where `id` is an Actor ID or `username~name` (a `/` in the id is accepted and normalized).
Expand Down
5 changes: 2 additions & 3 deletions docs/builds.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
# Builds

> **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.
> **Official, but experimental — AI-generated and AI-maintained.** Review the code before relying
> on it in production and report issues on the repository.

Access the build collection with `client.builds()` (or `client.actor(id).builds()` for an Actor's
builds) and a single build with `client.build(id)`.
Expand Down
5 changes: 2 additions & 3 deletions docs/examples.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
# Examples

> **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.
> **Official, but experimental — AI-generated and AI-maintained.** Review the code before relying
> on it in production and report issues on the repository.

Each example below is a code fragment (not a standalone `main`) that assumes a configured `client`
and the imports listed in the [documentation index](README.md#imports-and-dependencies). The
Expand Down
5 changes: 2 additions & 3 deletions docs/misc.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
# Store, users & logs

> **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.
> **Official, but experimental — AI-generated and AI-maintained.** Review the code before relying
> on it in production and report issues on the repository.

## Apify Store — `client.store()`

Expand Down
Loading
Loading