Click the Castor logo or press Ctrl Alt T to change theme.
# Requests An HTTP request is the message a client sends to a server. In its plain-text form, it contains a method, a URI, a protocol version, headers, and an optional body. The `Request` class models exactly these components — nothing more, nothing less. ## Why a minimal request? Many PHP HTTP libraries include parsed cookies, query parameters, uploaded files, and server metadata directly on the request object. Castor HTTP deliberately does not. The `Request` class contains only those things that appear in the raw HTTP wire format. Parsed data — cookies, query parameters, body payloads — is derived from the request when you need it. Network-layer information like the client IP is carried in the context, not bolted onto the request. This separation keeps the request object small and its responsibilities clear. ## Creating requests The simplest way to create a request is with the `create` factory: ```php <?php use Castor\Net\Http\Request; $request = Request::create('GET', 'https://api.example.com/users'); ``` This gives you: - **Version**: HTTP/1.1 (the default). - **Method**: `Method::Get`, resolved from the string `"GET"`. - **URI**: A fully parsed `Castor\Net\Uri` instance. - **Headers**: An empty `Headers` collection. - **Body**: A `NoBody` instance — an empty, read-once body. If you need a request with a body, pass a `Reader & Closer` as the third argument: ```php <?php use Castor\Net\Http\Request; use Castor\Io\Stream; $body = Stream\Buffer::with('{"name": "Alice"}'); $request = Request::create('POST', 'https://api.example.com/users', $body); ``` For full control over every component, use the constructor directly: ```php <?php use Castor\Net\Http\Request; use Castor\Net\Http\Method; use Castor\Net\Http\Version; use Castor\Net\Http\Headers; use Castor\Net\Http\NoBody; use Castor\Net\Uri; $request = new Request( new Version(2, 0), Method::Post, Uri::parse('https://api.example.com/users'), new Headers(), new NoBody(), ); ``` ## Accessing request components Every component is a public readonly property: ```php $request->version; // Version instance $request->method; // Method enum case $request->uri; // Castor\Net\Uri instance $request->headers; // Headers instance $request->body; // Reader & Closer instance ``` ### URI and query parameters The URI is a full `Castor\Net\Uri` object. Query parameters are available through the URI's query component: ```php $request = Request::create('GET', 'https://example.com?foo=bar&baz=qux'); $request->uri->getQuery()->lookup('foo'); // "bar" $request->uri->getQuery()->lookup('missing'); // null $request->uri->getQuery()->get('missing'); // "" $request->uri->getQuery()->values('foo'); // ["bar"] ``` ### Reading the body The body implements `Castor\Io\Reader` and `Castor\Io\Closer`. You can read it using the I/O utilities from the `castor/io` package: ```php <?php use Castor\Io; $contents = Io\readAll($request->body); ``` > [!WARNING] > A body can generally only be read once. After reading, subsequent reads will throw `EndOfFile`. If you need to read the body multiple times, buffer it first. ## Copying requests Since `Request` is a readonly class, you cannot modify it in place. Instead, use `copyWith` to create a modified copy: ```php $modified = $request->copyWith( method: 'PUT', uri: 'https://api.example.com/users/42', ); ``` The `copyWith` method accepts strings for method and URI (they are parsed automatically) or their typed equivalents. Any parameter you omit keeps the original value: ```php // Change only the method $delete = $request->copyWith(method: Method::Delete); // Change only the version $http2 = $request->copyWith(version: new Version(2, 0)); ``` ## Request info via context Information that does not belong in the raw HTTP message — like the client IP or pre-parsed cookies — is passed through the context using the `RequestInfo` enum: ```php <?php use Castor\Context; use Castor\Net\Http\RequestInfo; // In a server environment, the framework sets these: $ctx = RequestInfo::withClientIp($ctx, '192.168.1.1'); // In your handler, you retrieve them: $ip = RequestInfo::clientIp($ctx); // "192.168.1.1" $cookies = RequestInfo::parsedCookies($ctx); $body = RequestInfo::parsedBody($ctx); ``` This keeps the `Request` class focused on what HTTP actually is, while the context carries the operational metadata around it.
Castor ecosystem