Skip to content

Commit 7320872

Browse files
authored
Merge pull request #25 from programmatordev/PAS-17-add-memoized-response-resolver-for-linked-resources-and-pagination
Add memoized response resolver for linked resources and pagination
2 parents f1a1bf9 + 69d4aa4 commit 7320872

28 files changed

Lines changed: 1057 additions & 59 deletions

‎AGENTS.md‎

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,16 @@ Keep the architecture centered on a small set of clear responsibilities:
2424
- `Setup`: the explicit SDK-user setup and hackability surface exposed through
2525
`Api::setup()`.
2626
- `Runtime`: the internal configured runtime used by resources for configuration
27-
access and request execution.
27+
access, request identity, and request execution.
2828
- `Resource`: an immutable endpoint group and the primary SDK-author workflow.
2929
- `Endpoint`: an immutable builder for request-local query, header, and body
3030
options.
3131
- `RequestOptions`: the request-local query, header, and body state carried by an
3232
endpoint.
33+
- `Context`: the effective SDK config and response-graph capabilities passed
34+
through response mapping and hydration.
35+
- `Resolver`: the explicit, response-graph-scoped API for following linked
36+
resources and pagination while reusing the originating runtime.
3337
- `Response`: the decoded/raw response wrapper and mapping surface.
3438
- `Entity`: the optional contract for typed response data objects.
3539

@@ -94,8 +98,20 @@ cache, hooks, decoding, and error handling.
9498
options merge, before serialization.
9599
- Authentication strategies must be explicit. Multiple strategies compose
96100
through `auth()->chain(...)` rather than relying on implicit precedence.
97-
- Keep entities as response data/value objects by default. Do not introduce
98-
hidden network calls, lazy loading, or transparent proxy behavior.
101+
- Keep entities as response data/value objects by default. SDK authors may add
102+
purpose-built relationship or pagination methods that explicitly defer a
103+
request through the context resolver. Do not introduce transparent proxy
104+
behavior, automatic property loading, or network calls from ordinary value
105+
accessors.
106+
- Resolver requests must reuse the originating runtime pipeline, including
107+
current setup, config overrides, authentication, plugins, API-level cache,
108+
hooks, decoding, and error handling. Request-local endpoint modifiers are not
109+
inherited by followed links.
110+
- Resolver memoization is scoped to one response graph. Memoize SDK responses by
111+
request identity rather than sharing mapped entities or leaking state across
112+
independent top-level requests.
113+
- Treat query parameters already present in API-provided links as authoritative.
114+
Apply missing API defaults without replacing or reparsing link queries.
99115
- Keep API-specific vocabulary in concrete SDK packages. Concepts such as
100116
includes, selects, filters, and pagination should build on generic resource
101117
primitives rather than enter the base package without broad applicability.
@@ -128,6 +144,7 @@ Maintain support for the package's core capabilities:
128144
- Query and header defaults.
129145
- Base URL and path construction.
130146
- Response decoding and transformation.
147+
- Explicit linked-response resolution and response-graph memoization.
131148
- Error handling.
132149
- Test utilities for SDK authors where they provide clear value.
133150

@@ -154,6 +171,8 @@ Documentation should explain:
154171
- How to create and configure a simple SDK.
155172
- How to author resources and request options.
156173
- How to map responses to entities, collections, and envelopes.
174+
- How entities and envelopes can explicitly resolve linked resources and
175+
pagination through their hydration context.
157176
- How to configure authentication, clients, factories, cache, logging, plugins,
158177
hooks, and errors.
159178
- How to create API-specific fluent helpers on top of generic primitives.
@@ -186,6 +205,11 @@ For scoped or pipeline behavior, verify isolation and propagation explicitly:
186205
- Hooks, errors, responses, and hydration observe the same effective context.
187206
- Cache behavior does not leak request-local state.
188207
- Independent fluent modifiers compose correctly.
208+
- Resolver requests use the same effective runtime pipeline as their originating
209+
response.
210+
- Resolver memoization is isolated by response graph and avoids duplicate
211+
requests without sharing mapped objects.
212+
- Linked URL query precedence and request identity match documented behavior.
189213

190214
## Downstream Validation
191215

‎README.md‎

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,13 @@ SDK packages may still require or suggest concrete PSR-18 and PSR-17 implementat
3939
- [Resource Authoring](docs/04-resource-authoring.md): deeper guide for resource methods, query/header options, request bodies, entity mapping, collections, envelopes, and API-specific resource chains.
4040
- [Resources](docs/05-resources.md): resource classes and endpoint request helpers.
4141
- [Responses](docs/06-responses.md): decoded data, raw responses, entities, collections, envelopes, and context.
42-
- [Authentication](docs/07-authentication.md): configure bearer, basic, header, query, HTTPlug, and custom authentication.
43-
- [HTTP Client](docs/08-http-client.md): configure PSR-18 clients and PSR-17 factories.
44-
- [Cache](docs/09-cache.md): configure PSR-6 HTTP response caching.
45-
- [Logging](docs/10-logging.md): configure PSR-3 logging and HTTP/cache log output.
46-
- [Plugins](docs/11-plugins.md): configure HTTPlug middleware and priority ordering.
47-
- [Hooks](docs/12-hooks.md): run SDK-author callbacks around requests and responses.
42+
- [Resolver](docs/07-resolver.md): follow linked entities, collections, and pagination through the configured SDK runtime.
43+
- [Authentication](docs/08-authentication.md): configure bearer, basic, header, query, HTTPlug, and custom authentication.
44+
- [HTTP Client](docs/09-http-client.md): configure PSR-18 clients and PSR-17 factories.
45+
- [Cache](docs/10-cache.md): configure PSR-6 HTTP response caching.
46+
- [Logging](docs/11-logging.md): configure PSR-3 logging and HTTP/cache log output.
47+
- [Plugins](docs/12-plugins.md): configure HTTPlug middleware and priority ordering.
48+
- [Hooks](docs/13-hooks.md): run SDK-author callbacks around requests and responses.
4849

4950
## Upgrading
5051

‎UPGRADE-3.0.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ $this->auth()->bearer($token);
103103

104104
Use `chain()` only when an API requires multiple authentication rules on the same request.
105105

106-
See [Authentication](docs/07-authentication.md), [HTTP Client](docs/08-http-client.md), [Cache](docs/09-cache.md), [Logging](docs/10-logging.md), [Plugins](docs/11-plugins.md), and [Hooks](docs/12-hooks.md) for details.
106+
See [Authentication](docs/08-authentication.md), [HTTP Client](docs/09-http-client.md), [Cache](docs/10-cache.md), [Logging](docs/11-logging.md), [Plugins](docs/12-plugins.md), and [Hooks](docs/13-hooks.md) for details.
107107

108108
## Defaults And Endpoint Overrides
109109

@@ -143,7 +143,7 @@ API cache config < endpoint cache defaults < resource withCache override
143143

144144
The base package provides the generic override mechanism. API-specific fluent helpers, such as `withIncludes()` or `withStatus()`, should live in the concrete SDK.
145145

146-
See [Resource Authoring: API-Specific Resource Chains](docs/04-resource-authoring.md#api-specific-resource-chains), [Resources: Resource Cache Overrides](docs/05-resources.md#resource-cache-overrides), [Cache: Endpoint Defaults](docs/09-cache.md#endpoint-defaults), and [Cache: Resource Overrides](docs/09-cache.md#resource-overrides) for details.
146+
See [Resource Authoring: API-Specific Resource Chains](docs/04-resource-authoring.md#api-specific-resource-chains), [Resources: Resource Cache Overrides](docs/05-resources.md#resource-cache-overrides), [Cache: Endpoint Defaults](docs/10-cache.md#endpoint-defaults), and [Cache: Resource Overrides](docs/10-cache.md#resource-overrides) for details.
147147

148148
## Setup Is The Escape Hatch
149149

@@ -177,7 +177,7 @@ The package uses PHP-HTTP discovery for PSR-18 clients and PSR-17 factories. Whe
177177

178178
SDK authors may still require or suggest concrete implementations when they want control over the default HTTP stack.
179179

180-
See [HTTP Client: SDK Author Defaults](docs/08-http-client.md#sdk-author-defaults) and [HTTP Client: SDK User Overrides](docs/08-http-client.md#sdk-user-overrides) for details.
180+
See [HTTP Client: SDK Author Defaults](docs/09-http-client.md#sdk-author-defaults) and [HTTP Client: SDK User Overrides](docs/09-http-client.md#sdk-user-overrides) for details.
181181

182182
## API-Specific Behavior Belongs In SDKs
183183

‎docs/00-index.md‎

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,13 @@ SDK packages may still require or suggest concrete PSR-18 and PSR-17 implementat
3535
- [Resource Authoring](04-resource-authoring.md): deeper guide for resource methods, query/header options, request bodies, entity mapping, collections, envelopes, and API-specific resource chains.
3636
- [Resources](05-resources.md): resource classes and endpoint request helpers.
3737
- [Responses](06-responses.md): decoded data, raw responses, entities, collections, envelopes, and context.
38-
- [Authentication](07-authentication.md): configure bearer, basic, header, query, HTTPlug, and custom authentication.
39-
- [HTTP Client](08-http-client.md): configure PSR-18 clients and PSR-17 factories.
40-
- [Cache](09-cache.md): configure PSR-6 HTTP response caching.
41-
- [Logging](10-logging.md): configure PSR-3 logging and HTTP/cache log output.
42-
- [Plugins](11-plugins.md): configure HTTPlug middleware and priority ordering.
43-
- [Hooks](12-hooks.md): run SDK-author callbacks around requests and responses.
38+
- [Resolver](07-resolver.md): follow linked entities, collections, and pagination through the configured SDK runtime.
39+
- [Authentication](08-authentication.md): configure bearer, basic, header, query, HTTPlug, and custom authentication.
40+
- [HTTP Client](09-http-client.md): configure PSR-18 clients and PSR-17 factories.
41+
- [Cache](10-cache.md): configure PSR-6 HTTP response caching.
42+
- [Logging](11-logging.md): configure PSR-3 logging and HTTP/cache log output.
43+
- [Plugins](12-plugins.md): configure HTTPlug middleware and priority ordering.
44+
- [Hooks](13-hooks.md): run SDK-author callbacks around requests and responses.
4445

4546
## Upgrading
4647

‎docs/03-api.md‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ Authentication is applied automatically to outgoing requests.
208208

209209
Calling another auth helper replaces the previous authentication. Use `chain()` when multiple authentication rules are required.
210210

211-
See [Authentication](07-authentication.md) for helper methods, HTTPlug authentication objects, and custom auth callbacks.
211+
See [Authentication](08-authentication.md) for helper methods, HTTPlug authentication objects, and custom auth callbacks.
212212

213213
### `hooks()`
214214

@@ -225,7 +225,7 @@ $this->hooks()->afterResponse($hook);
225225

226226
Hooks are SDK-author extension points. They run around the raw HTTP request and response, before response decoding and error handling.
227227

228-
See [Hooks](12-hooks.md) for hook context objects, return values, and priority behavior.
228+
See [Hooks](13-hooks.md) for hook context objects, return values, and priority behavior.
229229

230230
### `plugins()`
231231

@@ -241,7 +241,7 @@ $this->plugins()->add($plugin, priority: 16);
241241

242242
Higher priority plugins run earlier. Same-priority plugins are preserved in insertion order.
243243

244-
See [Plugins](11-plugins.md) for internal plugin order and priority guidance.
244+
See [Plugins](12-plugins.md) for internal plugin order and priority guidance.
245245

246246
### `cache()`
247247

@@ -258,7 +258,7 @@ $this
258258
->methods(['GET', 'HEAD']);
259259
```
260260

261-
See [Cache](09-cache.md) for cache options and plugin order.
261+
See [Cache](10-cache.md) for cache options and plugin order.
262262

263263
### `client()`
264264

@@ -281,7 +281,7 @@ $this
281281
->streamFactory($streamFactory);
282282
```
283283

284-
See [HTTP Client](08-http-client.md) for client and factory configuration.
284+
See [HTTP Client](09-http-client.md) for client and factory configuration.
285285

286286
### `logger()`
287287

@@ -297,7 +297,7 @@ $this
297297
->formatter($formatter);
298298
```
299299

300-
See [Logging](10-logging.md) for logger formatting and cache logging.
300+
See [Logging](11-logging.md) for logger formatting and cache logging.
301301

302302
## Response Handling
303303

‎docs/04-resource-authoring.md‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,10 @@ final class UserEnvelope implements EnvelopeInterface
367367

368368
Keep context usage focused on hydration decisions. Entities should still be data/value objects by default and should not perform hidden network calls.
369369

370+
When an API exposes relationships or pagination as links, an SDK author can opt
371+
into explicit request-backed methods through the context resolver. See
372+
[Resolver](07-resolver.md).
373+
370374
## Resource-Local Configuration
371375

372376
> **Available since version 3.1.0.**

‎docs/05-resources.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ $users = $api
260260

261261
This override is immutable and applies only to the chained resource instance. It requires API-level cache configuration because the global cache setup provides the PSR-6 pool.
262262

263-
See [Cache](09-cache.md) for endpoint cache defaults, merge order, and the API-level cache requirement.
263+
See [Cache](10-cache.md) for endpoint cache defaults, merge order, and the API-level cache requirement.
264264

265265
## Navigation
266266

‎docs/06-responses.md‎

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ public static function fromResponse(Response $response, ?Context $context = null
107107

108108
## `Context`
109109

110-
`Context` carries SDK config into response mapping.
110+
`Context` carries SDK config and response resolution into response mapping.
111111

112112
SDK users do not fetch context from `Response`. The package passes context into entity and envelope hydration methods:
113113

@@ -133,6 +133,19 @@ this returns the effective API configuration plus its resource-local overrides.
133133
The same effective configuration is available to hooks and error handlers for
134134
that request. See [Resource-Local Configuration](04-resource-authoring.md#resource-local-configuration).
135135

136+
### `resolver()`
137+
138+
```php
139+
resolver(): ResolverInterface
140+
```
141+
142+
Returns the response-graph resolver provided by the API runtime. It can follow
143+
linked entities, collections, and pagination through the configured SDK runtime.
144+
Calling it outside an API runtime request throws `RuntimeException`.
145+
146+
See [Resolver](07-resolver.md) for linked-resource authoring, request behavior,
147+
and memoization scope.
148+
136149
## `ErrorContext`
137150

138151
`ErrorContext` is passed to configured error handlers.
@@ -173,4 +186,4 @@ It exposes:
173186
## Navigation
174187

175188
- Previous: [Resources](05-resources.md)
176-
- Next: [Authentication](07-authentication.md)
189+
- Next: [Resolver](07-resolver.md)

0 commit comments

Comments
 (0)