-
Notifications
You must be signed in to change notification settings - Fork 2
Request
Pair\Api\Request is the HTTP wrapper used by Pair API controllers.
It covers:
- method and header access
- lazy JSON body parsing
- query parameter access
- lightweight validation rules
- request-object mapping through
RequestData - bearer token, API session, and idempotency-key extraction
- trusted-proxy-aware client IP resolution
Use these when the controller needs to inspect the request shape quickly.
$method = $this->request->method(); // GET, POST, PUT...
$auth = $this->request->header('Authorization');
$contentType = $this->request->header('Content-Type');
$page = $this->request->query('page', 1);
$allQuery = $this->request->query();all() merges $_GET and the parsed JSON body, with JSON values taking precedence when the same key exists in both places:
// GET /api/users?page=2 with JSON body {"status":"active"}
$all = $this->request->all();
// ['page' => '2', 'status' => 'active']rawBody() reads php://input lazily and caches it.
json() parses the request body as JSON and returns either the whole associative array or a single key:
$body = $this->request->json();
$email = $this->request->json('email');isJson() checks whether the content type includes application/json.
if (!$this->request->isJson()) {
return \Pair\Api\ApiResponse::errorResponse('UNSUPPORTED_MEDIA_TYPE', [
'expected' => 'application/json',
]);
}Practical note: the current implementation expects the decoded JSON body to be an array. Invalid JSON, empty bodies, or scalar JSON payloads effectively behave like null.
Supported rules:
requiredstringintnumericemailboolmin:Nmax:N
Example:
$data = $this->request->validate([
'email' => 'required|email|max:120',
'age' => 'int|min:18',
'newsletter' => 'bool',
]);If you are moving a controller to the explicit v4 flow, use validateOrResponse() and return the error object instead of terminating immediately:
$result = $this->request->validateOrResponse([
'email' => 'required|email|max:120',
'age' => 'int|min:18',
]);
if ($result instanceof \Pair\Api\ApiErrorResponse) {
return $result;
}
$data = $result;Current behavior:
-
validateOrResponse()returns only validated keys or an explicitApiErrorResponse -
validateObjectOrResponse()returns aRequestDataobject or an explicitApiErrorResponse -
validate()remains the legacy bridge and still responds immediately withINVALID_FIELDS - missing optional fields are skipped
- validated arrays are not cast automatically
That last point matters:
-
intaccepts digit strings, but you should still cast to(int)yourself -
boolacceptstrue,false,1,0,'1','0','true','false', but it does not cast the result to a PHP boolean for you - decimal
min:Nandmax:Nbounds are compared numerically when both the value and the rule parameter are numeric
Required-only shortcut:
$data = $this->request->requireFields(['email', 'password']);For custom endpoints, prefer a small RequestData object when the action needs typed, normalized input.
$payload = $this->request->validateObjectOrResponse(\App\Api\Requests\CreateOrderRequest::class, [
'customerId' => 'required|int',
'amount' => 'required|numeric|min:0.01',
'currency' => 'required|string|max:3',
]);
if ($payload instanceof \Pair\Api\ApiErrorResponse) {
return $payload;
}
// $payload is now a CreateOrderRequest instance.4) Auth and delivery helpers: bearerToken(), sessionIdentifier(), idempotencyKey(), isReplayRequest()
bearerToken() extracts Authorization: Bearer ... when present. The scheme is parsed case-insensitively and uses the same Authorization fallback keys as the OAuth bootstrap code.
sessionIdentifier() returns the legacy sid query parameter when present, otherwise it reads the X-Pair-Session header. New clients should prefer X-Pair-Session when they still need session-based API calls, because it avoids putting session IDs in URLs.
Authorization parsing is delegated to AuthorizationHeader, so API request code and OAuth bootstrap code share the same Basic and Bearer parsing behavior.
idempotencyKey() supports both:
Idempotency-KeyX-Idempotency-Key
isReplayRequest() returns true when X-Pair-Replay is 1 or true.
$token = $this->request->bearerToken();
$sessionId = $this->request->sessionIdentifier();
$key = $this->request->idempotencyKey();
if (!$token) {
return \Pair\Api\ApiResponse::errorResponse('AUTH_TOKEN_MISSING');
}Replay-aware example:
if ($this->request->isReplayRequest()) {
// optional branch for offline queue or retried mobile requests
}ip() returns the effective client IP.
Current behavior:
- uses
REMOTE_ADDRby default - trusts
ForwardedandX-Forwarded-Foronly whenREMOTE_ADDRbelongs toPAIR_TRUSTED_PROXIES - supports exact proxy IPs and CIDR ranges in
PAIR_TRUSTED_PROXIES - prefers the standardized
Forwardedheader when available
Example .env:
PAIR_TRUSTED_PROXIES=127.0.0.1,10.0.0.0/8,192.168.0.0/16Example:
$ip = $this->request->ip();
$limiterKey = 'throttle:login:' . $ip;-
rawBody()andjson()are lazy and cached. -
header()handles special server variables such asContent-TypeandContent-Length. -
all()is convenient, but remember that JSON overrides same-named query parameters.
- Assuming JSON is always present on
POST,PUT, orPATCH. - Forgetting that
all()lets JSON override same-named query keys. - Treating array validation as automatic type casting.
- Putting endpoint normalization in comments instead of in a
RequestData::fromArray()implementation. - Trusting forwarded headers without configuring
PAIR_TRUSTED_PROXIES.
See also: API, RequestData, AuthorizationHeader, ApiResponse, Idempotency, ThrottleMiddleware.