The HTTP layer lives at:
Zero\Lib\Http\Request— composed of concern traits atcore/libraries/Http/Concerns/Zero\Lib\Http\Response— seecore/libraries/Http/Response.php
Controllers may return strings, arrays, models, iterables, or explicit Response objects; the router normalises everything through Response::resolve().
The router calls Request::capture() once per request and injects the same instance into your controllers (where it's also available type-hinted on action signatures). You can also reach it from anywhere via Request::instance() or the global request() helper.
Snapshot the current PHP request. Called by the router; you generally don't call this yourself.
use Zero\Lib\Http\Request;
$request = Request::capture(); // singleton-like; subsequent calls return the same instanceReturn the current request without re-capturing.
$request = Request::instance();Replace the current request (mainly for tests).
Request::replace([
'method' => 'POST',
'uri' => '/users',
'input' => ['email' => 'a@b.test'],
]);All input — query + form + JSON merged.
$data = $request->all();Read a single input value.
$email = $request->input('email');
$page = $request->input('page', 1);if ($request->has('email')) { /* ... */ }JSON-decoded body (or a single key).
$payload = $request->json();
$first = $request->json('items.0');Validate input. Throws Zero\Lib\Validation\ValidationException on failure (handled by the global error handler).
$data = $request->validate([
'email' => 'required|email',
'password' => 'required|min:8',
]);Pass null to get the full header bag.
$ua = $request->header('User-Agent');
$all = $request->header(); // ['user-agent' => '...', ...]True when the client Accepts JSON.
return $request->expectsJson()
? Response::json($data)
: view('users.show', ['user' => $data]);Stricter alias of expectsJson() ignoring */*.
if ($request->wantsJson()) { /* ... */ }$theme = $request->cookie('theme', 'light');$all = $request->cookies();Returns an UploadedFile (or null).
$avatar = $request->file('avatar');
$path = $avatar?->store('avatars');$uploads = $request->files();$method = $request->method(); // 'POST'$request->path(); // '/users/42'Path + query string.
$request->uri(); // '/users/42?tab=info'Scheme + host (no path).
$request->root(); // 'https://api.example.com'$request->fullUrl(); // 'https://api.example.com/users/42?tab=info'$ip = $request->ip();Raw request body.
$raw = $request->getContent();Attributes let middleware stash work for downstream code. Backed by static state on Request.
// In middleware
Request::set('user', Auth::user());// In a controller
$user = Request::get('user');Instance-level read.
$user = $request->attribute('user');$bag = $request->attributes();Read the session via the request.
$flash = $request->session('flash.success');
$all = $request->session(); // raw $_SESSION$request->key and isset($request->key) proxy to attributes/input — convenient inside controllers:
$email = $request->email; // sugar for $request->input('email')Static factories build a Response, which the router sends. You can also return raw scalars/arrays/models from controllers — Response::resolve() wraps them.
Generic constructor.
return Response::make('OK', 200, ['X-Robots-Tag' => 'noindex']);return Response::json(['ok' => true]);
return Response::json($users, 200, ['X-Total' => count($users)]);return Response::text('pong');return Response::html('<h1>Hello</h1>');return Response::xml('<?xml version="1.0"?><root/>');Response::api(string $status, mixed $payload = null, int $statusCode = 200, array $headers = []): static
Opinionated {status, message, data} envelope.
return Response::api('success', $user);
return Response::api('error', null, 422, ['X-Error' => 'validation']);return Response::redirect('/login');Response::redirectRoute(string $name, array $parameters = [], bool $absolute = true, int $status = 302, array $headers = []): static
return Response::redirectRoute('users.show', ['id' => $user->id]);return Response::redirectBack('/dashboard');Response::stream(callable|string $stream, int $status = 200, array $headers = [], string $contentType = 'text/event-stream'): static
return Response::stream(function () {
foreach (stream_events() as $event) {
echo "data: " . json_encode($event) . "\n\n";
ob_flush(); flush();
}
});Response::file(string $path, array $headers = [], ?string $name = null, string $disposition = 'inline'): static
return Response::file(storage_path('exports/users.csv'), [], 'users.csv', 'attachment');return Response::noContent();Normalize any controller return value to a Response. Used by the router.
$response = Response::resolve($controllerReturn);These chain on a Response instance:
return Response::json($data)->status(201);return Response::json($data)->withHeaders(['X-Total' => 42]);$response->getStatus(); // 200Emit headers + body. The router calls this for you.
$response->send();These are thin wrappers around Response::* and Request::* defined in core/libraries/Support/Helper.php. See helpers.md for the full list.
return view('users.show', ['user' => $user]); // Response::html
return response($payload, 201); // auto-detects type
return redirect('/login'); // Response::redirect
return back(); // Response::redirectBack
$email = request('email'); // Request::get
$user = auth(); // current userThe framework ships an optional CORS helper at core/libraries/Http/cors_helper.php. It is not auto-loaded — require it from your front controller or a middleware when you need cross-origin support:
require_once core_path('libraries/Http/cors_helper.php');
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';
cors_emit_headers($origin, $_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS'] ?? null);cors_allowed_origins(): arrayreads theCORS_ALLOWED_ORIGINSenv var (comma-separated) and returns the allowlist.cors_emit_headers(string $origin, ?string $requestHeaders): voidemits theAccess-Control-*headers. Allowlisted origins receive credentialed CORS (the echoed origin plusAccess-Control-Allow-Credentials: true); every other origin gets a non-credentialed wildcard so public, cookie-less calls still work.
CORS_ALLOWED_ORIGINS=https://app.example.com,https://admin.example.com