Skip to content

Commit 69b3a0f

Browse files
committed
refactor!: type RequestQueueClient's remaining raw-array methods
listAndLockHead, listRequests, prolongRequestLock, unlockRequests and batchDeleteRequests returned/took a raw array<string,mixed> even though the reference JS client types each as a first-class interface and the OpenAPI spec documents a static response shape for all of them. Adds LockedRequestQueueHead, RequestQueueRequestsPage, RequestLockInfo, UnlockRequestsResult and BatchDeleteResult, and fixes RequestQueueHead (and the new LockedRequestQueueHead) to expose the previously-missing queueModifiedAt field. Breaking change explicitly requested by the human operator; bumps CLIENT_VERSION 0.4.0 -> 0.5.0.
1 parent 49a6e4d commit 69b3a0f

14 files changed

Lines changed: 580 additions & 48 deletions

CHANGELOG.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,21 @@
11
# Changelog
22

3+
## 0.5.0
4+
5+
Breaking: `RequestQueueClient` methods that previously returned a raw `array<string,mixed>` (or, for
6+
`batchDeleteRequests`, accepted an untyped `mixed` argument) now use typed models, matching the
7+
OpenAPI-documented response schemas and the reference client's typed result interfaces:
8+
9+
- `listAndLockHead()` now returns `LockedRequestQueueHead` (was `array`).
10+
- `prolongRequestLock()` now returns `RequestLockInfo` (was `array`).
11+
- `unlockRequests()` now returns `UnlockRequestsResult` (was `array`).
12+
- `listRequests()` now returns `RequestQueueRequestsPage` (was `array`).
13+
- `batchDeleteRequests()` now takes `list<RequestQueueRequest>` and returns `BatchDeleteResult` (was
14+
`mixed $requests` / `array`).
15+
- `RequestQueueHead` and the new `LockedRequestQueueHead` gained the previously-missing
16+
`getQueueModifiedAt()` getter (the field is present in the OpenAPI spec and the reference client,
17+
but was not yet exposed by this client).
18+
319
## 0.4.0
420

521
- Synced to Apify OpenAPI spec `v2-2026-08-05T133145Z` (additive nullability/response/description

docs/README.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,10 +96,11 @@ JSON value — typically an associative array, though `getInput()` is typed `mix
9696
whatever JSON value was stored (or accept an arbitrary value serialized to JSON):
9797

9898
- Read: `me()->monthlyUsage(...)`, `me()->limits()`, `task($id)->getInput()`,
99-
`build($id)->getOpenApiDefinition()`, `dataset($id)->getStatistics()`, and the raw request-queue
100-
operations that return a response body (`listRequests`, `listAndLockHead`, `prolongRequestLock`,
101-
`unlockRequests`, `batchDeleteRequests`). Note that `deleteRequestLock` returns `void` (it releases
102-
a lock and has no meaningful body), so it is not in this list.
99+
`build($id)->getOpenApiDefinition()`, `dataset($id)->getStatistics()`. Note that
100+
`deleteRequestLock` returns `void` (it releases a lock and has no meaningful body), so it is not in
101+
this list. The request-queue lock/list/unlock/batch-delete operations
102+
(`listRequests`, `listAndLockHead`, `prolongRequestLock`, `unlockRequests`, `batchDeleteRequests`)
103+
return typed models (see [Models](models.md)), not raw JSON.
103104
- Write: definition/`update`/`create` arguments accept any JSON-serializable value — typically an
104105
associative array.
105106

docs/models.md

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,11 +170,47 @@ One page returned by `listKeys()`.
170170
| `getTotalRequestCount(): ?int` | Total number of requests ever added. |
171171

172172
### `RequestQueueHead`
173-
Returned by `listHead()`. (`listAndLockHead()` returns a raw `array<string,mixed>`, not this model.)
173+
Returned by `listHead()`.
174174
| Getter | Description |
175175
|---|---|
176176
| `getItems(): array` | The `RequestQueueRequest` items at the head of the queue. |
177177
| `getLimit(): ?int` | The requested head size limit. |
178+
| `hadMultipleClients(): bool` | Whether multiple clients have accessed the queue. |
179+
| `getQueueModifiedAt(): ?string` | ISO-8601 timestamp of the last modification to the queue. |
180+
181+
### `LockedRequestQueueHead`
182+
Returned by `listAndLockHead()`.
183+
| Getter | Description |
184+
|---|---|
185+
| `getItems(): array` | The locked `RequestQueueRequest` items at the head of the queue. |
186+
| `getLimit(): ?int` | The requested head size limit. |
187+
| `hadMultipleClients(): bool` | Whether multiple clients have accessed the queue. |
188+
| `getLockSecs(): int` | The lock duration applied to every returned request. |
189+
| `queueHasLockedRequests(): ?bool` | Whether the queue has any requests locked by any client. |
190+
| `getClientKey(): ?string` | The client key used to acquire the locks. |
191+
| `getQueueModifiedAt(): ?string` | ISO-8601 timestamp of the last modification to the queue. |
192+
193+
### `RequestQueueRequestsPage`
194+
Returned by `listRequests()`.
195+
| Getter | Description |
196+
|---|---|
197+
| `getItems(): array` | The `RequestQueueRequest` items in this page. |
198+
| `getLimit(): ?int` | The requested page size limit. |
199+
| `getExclusiveStartId(): ?string` | The exclusive start ID used for this page (deprecated; use the cursor). |
200+
| `getCursor(): ?string` | The cursor that produced this page. |
201+
| `getNextCursor(): ?string` | The cursor to request the next page, or `null` if this is the last page. |
202+
203+
### `RequestLockInfo`
204+
Returned by `prolongRequestLock()`.
205+
| Getter | Description |
206+
|---|---|
207+
| `getLockExpiresAt(): ?string` | ISO-8601 timestamp of when the (possibly just-extended) lock expires. |
208+
209+
### `UnlockRequestsResult`
210+
Returned by `unlockRequests()`.
211+
| Getter | Description |
212+
|---|---|
213+
| `getUnlockedCount(): int` | The number of requests that were unlocked. |
178214

179215
### `RequestQueueOperationInfo`
180216
Returned by single-request add/update operations.
@@ -190,6 +226,13 @@ Returned by `batchAddRequests()`.
190226
| `getProcessedRequests(): array` | Requests the API accepted (as `RequestQueueOperationInfo`). |
191227
| `getUnprocessedRequests(): array` | Requests that could not be processed. |
192228

229+
### `BatchDeleteResult`
230+
Returned by `batchDeleteRequests()`.
231+
| Getter | Description |
232+
|---|---|
233+
| `getProcessedRequests(): array` | Requests that were successfully deleted (as `RequestQueueRequest`). |
234+
| `getUnprocessedRequests(): array` | Requests that failed to be deleted and can be retried. |
235+
193236
## Iteration and pagination
194237

195238
### `PaginationList`

docs/storages.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -91,13 +91,13 @@ Single — `$client->requestQueue($id)`:
9191
- `addRequest(RequestQueueRequest $request, bool $forefront = false): RequestQueueOperationInfo` — adds a request to the queue; when `$forefront` is `true` it is added to the front (handled before the rest) instead of the back.
9292
- `getRequest(string $id): ?RequestQueueRequest`, `updateRequest(RequestQueueRequest $request, bool $forefront = false): RequestQueueOperationInfo` (with `$forefront` `true` the updated request is moved to the front of the queue), `deleteRequest(string $id): void`
9393
- `batchAddRequests(array $requests, bool $forefront = false, ?BatchAddRequestsOptions $options = null): BatchAddResult` — every request must have a non-empty `uniqueKey`; with `$forefront` `true` the requests are added to the front of the queue; input is split into batches of at most 25 requests that also respect the ~9 MiB payload limit.
94-
- `batchDeleteRequests(mixed $requests): array``$requests` is a list of entries that each identify a request to delete (e.g. by `id` or `uniqueKey`); returns the raw batch result as a decoded `array<string,mixed>`.
95-
- `listRequests(?ListRequestsOptions $options = null): array` — returns the raw paginated response as a decoded `array<string,mixed>`.
94+
- `batchDeleteRequests(array $requests): BatchDeleteResult``$requests` is a `list<RequestQueueRequest>` where each entry identifies a request to delete via `setId()` or `setUniqueKey()` (other fields, if set, are ignored by the API).
95+
- `listRequests(?ListRequestsOptions $options = null): RequestQueueRequestsPage`
9696
- `paginateRequests(?PaginateRequestsOptions $options = null): iterable` — lazily iterate the queue's requests, yielding `RequestQueueRequest` instances and following cursor pagination (see the options note below).
97-
- `listAndLockHead(int $lockSecs, ?int $limit = null): array` — atomically returns and locks up to `$limit` requests for `$lockSecs` seconds; returns the raw locked-head object as a decoded `array<string,mixed>`.
98-
- `prolongRequestLock(string $id, int $lockSecs, bool $forefront = false): array` — extends a request's lock by `$lockSecs`; with `$forefront` `true` the request is placed at the front of the queue once its lock expires; returns the raw response as a decoded `array<string,mixed>`.
97+
- `listAndLockHead(int $lockSecs, ?int $limit = null): LockedRequestQueueHead` — atomically returns and locks up to `$limit` requests for `$lockSecs` seconds.
98+
- `prolongRequestLock(string $id, int $lockSecs, bool $forefront = false): RequestLockInfo` — extends a request's lock by `$lockSecs`; with `$forefront` `true` the request is placed at the front of the queue once its lock expires.
9999
- `deleteRequestLock(string $id, bool $forefront = false): void` — releases the lock on a single request; with `$forefront` `true` the request is returned to the front of the queue.
100-
- `unlockRequests(): array` — releases all locks the client holds on this queue; returns the raw response as a decoded `array<string,mixed>`.
100+
- `unlockRequests(): UnlockRequestsResult` — releases all locks the client holds on this queue.
101101
- `withClientKey(string $clientKey): RequestQueueClient`
102102

103103
`paginateRequests()` accepts a `PaginateRequestsOptions` with `limit` (total across all pages),

src/Model/BatchDeleteResult.php

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Apify\Client\Model;
6+
7+
/**
8+
* The result of a batch request-delete: the requests that were successfully removed and the ones
9+
* that could not be (and can be retried). Returned by
10+
* {@see \Apify\Client\Resource\RequestQueueClient::batchDeleteRequests()}.
11+
*/
12+
final class BatchDeleteResult
13+
{
14+
/**
15+
* @param list<RequestQueueRequest> $processedRequests
16+
* @param list<RequestQueueRequest> $unprocessedRequests
17+
*/
18+
public function __construct(
19+
private array $processedRequests = [],
20+
private array $unprocessedRequests = [],
21+
) {
22+
}
23+
24+
/**
25+
* @param mixed $data the decoded response object
26+
*/
27+
public static function fromData(mixed $data): self
28+
{
29+
$data = is_array($data) ? $data : [];
30+
return new self(
31+
self::hydrateList($data['processedRequests'] ?? null),
32+
self::hydrateList($data['unprocessedRequests'] ?? null),
33+
);
34+
}
35+
36+
/**
37+
* @return list<RequestQueueRequest>
38+
*/
39+
private static function hydrateList(mixed $rawList): array
40+
{
41+
$rawList = is_array($rawList) ? array_values($rawList) : [];
42+
return array_map(
43+
static fn ($item) => RequestQueueRequest::fromArray(is_array($item) ? $item : []),
44+
$rawList
45+
);
46+
}
47+
48+
/**
49+
* The requests that were successfully deleted from the queue.
50+
*
51+
* @return list<RequestQueueRequest>
52+
*/
53+
public function getProcessedRequests(): array
54+
{
55+
return $this->processedRequests;
56+
}
57+
58+
/**
59+
* The requests that failed to be deleted and can be retried.
60+
*
61+
* @return list<RequestQueueRequest>
62+
*/
63+
public function getUnprocessedRequests(): array
64+
{
65+
return $this->unprocessedRequests;
66+
}
67+
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Apify\Client\Model;
6+
7+
/**
8+
* A batch of requests from the head of a request queue, locked for exclusive processing. Returned by
9+
* {@see \Apify\Client\Resource\RequestQueueClient::listAndLockHead()}.
10+
*/
11+
final class LockedRequestQueueHead
12+
{
13+
/**
14+
* @param list<RequestQueueRequest> $items
15+
*/
16+
public function __construct(
17+
private array $items,
18+
private int $limit,
19+
private bool $hadMultipleClients,
20+
private int $lockSecs,
21+
private ?bool $queueHasLockedRequests,
22+
private ?string $clientKey,
23+
private ?string $queueModifiedAt = null,
24+
) {
25+
}
26+
27+
/**
28+
* @param mixed $data the decoded locked-head object
29+
*/
30+
public static function fromData(mixed $data): self
31+
{
32+
$data = is_array($data) ? $data : [];
33+
$rawItems = (isset($data['items']) && is_array($data['items'])) ? array_values($data['items']) : [];
34+
$items = array_map(
35+
static fn ($item) => RequestQueueRequest::fromArray(is_array($item) ? $item : []),
36+
$rawItems
37+
);
38+
39+
return new self(
40+
$items,
41+
(int) ($data['limit'] ?? count($items)),
42+
(bool) ($data['hadMultipleClients'] ?? false),
43+
(int) ($data['lockSecs'] ?? 0),
44+
isset($data['queueHasLockedRequests']) ? (bool) $data['queueHasLockedRequests'] : null,
45+
isset($data['clientKey']) ? (string) $data['clientKey'] : null,
46+
isset($data['queueModifiedAt']) ? (string) $data['queueModifiedAt'] : null,
47+
);
48+
}
49+
50+
/**
51+
* The locked requests from the head of the queue. Each item carries its own
52+
* {@see RequestQueueRequest} lock-expiry field as reported by the API.
53+
*
54+
* @return list<RequestQueueRequest>
55+
*/
56+
public function getItems(): array
57+
{
58+
return $this->items;
59+
}
60+
61+
/** The maximum number of requests requested. */
62+
public function getLimit(): int
63+
{
64+
return $this->limit;
65+
}
66+
67+
/** Whether multiple clients have accessed the queue. */
68+
public function hadMultipleClients(): bool
69+
{
70+
return $this->hadMultipleClients;
71+
}
72+
73+
/** The lock duration applied to every returned request, in seconds. */
74+
public function getLockSecs(): int
75+
{
76+
return $this->lockSecs;
77+
}
78+
79+
/** Whether the queue has any requests locked by any client (this one or another). */
80+
public function queueHasLockedRequests(): ?bool
81+
{
82+
return $this->queueHasLockedRequests;
83+
}
84+
85+
/** The client key used to acquire the locks. */
86+
public function getClientKey(): ?string
87+
{
88+
return $this->clientKey;
89+
}
90+
91+
/** ISO 8601 timestamp of the last modification to the queue. */
92+
public function getQueueModifiedAt(): ?string
93+
{
94+
return $this->queueModifiedAt;
95+
}
96+
}

src/Model/RequestLockInfo.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Apify\Client\Model;
6+
7+
/**
8+
* The result of prolonging a request lock. Returned by
9+
* {@see \Apify\Client\Resource\RequestQueueClient::prolongRequestLock()}.
10+
*/
11+
final class RequestLockInfo
12+
{
13+
public function __construct(private ?string $lockExpiresAt)
14+
{
15+
}
16+
17+
/**
18+
* @param mixed $data the decoded response object
19+
*/
20+
public static function fromData(mixed $data): self
21+
{
22+
$data = is_array($data) ? $data : [];
23+
return new self(isset($data['lockExpiresAt']) ? (string) $data['lockExpiresAt'] : null);
24+
}
25+
26+
/** ISO 8601 timestamp of when the (possibly just-extended) lock expires. */
27+
public function getLockExpiresAt(): ?string
28+
{
29+
return $this->lockExpiresAt;
30+
}
31+
}

src/Model/RequestQueueHead.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ public function __construct(
1414
private array $items,
1515
private int $limit,
1616
private bool $hadMultipleClients,
17+
private ?string $queueModifiedAt = null,
1718
) {
1819
}
1920

@@ -33,6 +34,7 @@ public static function fromData(mixed $data): self
3334
$items,
3435
(int) ($data['limit'] ?? count($items)),
3536
(bool) ($data['hadMultipleClients'] ?? false),
37+
isset($data['queueModifiedAt']) ? (string) $data['queueModifiedAt'] : null,
3638
);
3739
}
3840

@@ -57,4 +59,10 @@ public function hadMultipleClients(): bool
5759
{
5860
return $this->hadMultipleClients;
5961
}
62+
63+
/** ISO 8601 timestamp of the last modification to the queue. */
64+
public function getQueueModifiedAt(): ?string
65+
{
66+
return $this->queueModifiedAt;
67+
}
6068
}

0 commit comments

Comments
 (0)