Repository navigation
HttpCache
Pair\Http\HttpCache provides explicit helpers for HTTP cache validators on read responses.
Use it for endpoints where clients, browsers, or proxies can safely reuse a representation until its validator changes.
HttpCache::etag(mixed $value, bool $weak = false): stringHttpCache::lastModified(DateTimeInterface|int|string $time): stringHttpCache::cacheControl(int $maxAge, string $visibility = 'public', bool $mustRevalidate = false): stringHttpCache::headers(?string $etag = null, DateTimeInterface|int|string|null $lastModified = null, ?string $cacheControl = null): arrayHttpCache::isNotModified(?string $etag = null, DateTimeInterface|int|string|null $lastModified = null, ?array $server = null): boolHttpCache::json(mixed $payload, int $httpCode = 200, ?string $etag = null, DateTimeInterface|int|string|null $lastModified = null, ?string $cacheControl = null, ?array $server = null): ResponseInterfaceHttpCache::notModified(?string $etag = null, DateTimeInterface|int|string|null $lastModified = null, ?string $cacheControl = null): EmptyResponse
This complete controller example uses a fixed public representation. In an application, load and authorize the real data before constructing the response or checking validators. Explicit v4 API controllers do not load a $this->model implicitly.
use Pair\Api\ApiController as PairApiController;
use Pair\Http\HttpCache;
use Pair\Http\ResponseInterface;
final class ApiController extends PairApiController {
/**
* Return a public representation with explicit cache validators.
*/
public function showAction(): ResponseInterface {
$data = ['id' => 7, 'title' => 'Example article'];
$etag = HttpCache::etag($data);
return HttpCache::json(
$data,
200,
$etag,
null,
HttpCache::cacheControl(300, 'public')
);
}
}When If-None-Match or If-Modified-Since matches the supplied validators, Pair returns 304 Not Modified through EmptyResponse.
For mutable data, pass its real modification timestamp as the fourth argument when available. It must describe the selected representation; using the current time on every request prevents useful time-based revalidation.
For list responses, include every value that affects the representation in the ETag input:
$payload = [
'data' => $rows,
'meta' => [
'page' => $page,
'perPage' => $perPage,
'total' => $total,
],
];
$etag = HttpCache::etag([
'query' => $_GET,
'payload' => $payload,
]);
return HttpCache::json($payload, 200, $etag, null, HttpCache::cacheControl(60));HTTP caching should stay explicit per action or resource policy. Do not enable it globally for all CRUD responses unless the resource has stable authorization, tenant scope, filters, and serialization.
For generated JSON resources, use HttpCache::json() in custom read actions or in future resource-level cache policy hooks.
- Conditional matching is only considered for
GETandHEAD. -
If-None-Matchtakes precedence overIf-Modified-Since. -
HttpCache::etag()hashes the response representation and does not expose the payload in the header. -
Cache-Control: no-storeis available for sensitive responses. - Never cache user-specific or tenant-specific data as
publicunless the representation is safe for every recipient. - A conditional request still needs authentication and authorization before returning
304; validator matching does not establish access.
See also: JsonResponse, EmptyResponse, API, CrudController.
Home · Setup · Configuration
Build with Pair 4
- Generator
- Controllers and responses
- Read models
- ActiveRecord and queries
- Forms and validation
- PairUI.js and HTML fragments
APIs and authentication
- API guide and CRUD
- Middleware and rate limits
- Users, sessions, and ACL
- Passkeys and social login
- Native mobile setup
Integrate and operate
- Integrations
- Runtime extensions and adapter keys
- Cache and cache stores
- Logs and observability
- PWA and push
- Packages and distribution
- Upgrade to v4