Last update: 04 Mar 2024

HTTP Message

Lightweight and strict implementation of PSR-7 HTTP Message including PSR-17 HTTP Factories.

Installation

To get started, install the http-message repository via the Composer package manager:

composer require zaphyr-org/http-message

Basic usage

The http-message repository is committed to maintaining a strict adherence to the PSR 7 specification, and as such, it will always remain focused solely on fulfilling the requirements outlined in this standard. We firmly believe in the principle of simplicity and purity in design, which means that we are committed to not including any additional features or helper methods in the repository.

The approach to utilizing this package varies depending on whether you are working on an HTTP client or a server-side application. To streamline the process for each scenario, specific steps need to be followed.

When developing an HTTP client, the first step is to create and populate a Zaphyr\HttpMessage\Request instance. This involves crafting the request with the necessary HTTP method, headers, and payload data as required by the target server. Once the request is prepared, it is then dispatched to the server, and the client should expect to receive a response in return. The response will be in the form of a Zaphyr\HttpMessage\Response instance, containing valuable information such as the server's HTTP status code, response headers, and response body.

On the other hand, for server-side applications, the process slightly differs. Here, you need to handle incoming requests from clients. To do this, you create a Zaphyr\HttpMessage\ServerRequest instance, which encapsulates the incoming request data received from the client. The server request object contains details such as the request method, headers, and payload data sent by the client. Once you've processed the incoming request and performed the necessary operations or computations, it's time to construct and populate a Zaphyr\HttpMessage\Response instance. This response object will hold the data you wish to send back to the client as the HTTP response. It includes the desired HTTP status code, response headers, and the response body containing the information or data generated by the server-side application.

Request

When working with the HTTP Message service, you, as a developer, will handle the interaction between the client and the server. The client initiates the process by sending a request to the server, and in return, it expects to receive a response from the server. The Zaphyr\HttpMessage\Request implements the PSR-7 RequestInterface:

$request = new Zaphyr\HttpMessage\Request(
    method: 'GET',
    uri: 'https://example.com',
    body: 'ph://temp',
    headers: ['Content-Type' => 'text/html'],
    protocol: '1.1'
);

Both requests and responses are designed to be immutable, meaning they cannot be modified directly once created. If you need to make changes to a request or response, such as updating headers or request parameters, you should utilize the appropriate with*() methods. However, it is crucial to note that when using these with*() methods, you must capture the return value, as it will yield a new instance with the updated changes rather than modifying the original instance:

$request = $request->withHeader('Content-Type', 'application/json');

After sending the request, you will then examine and analyze the received response:

$request->getBody()->write(json_encode($data));

$response = $client->sendRequest($request);

echo $response->getBody();
Note

This repository does NOT come with a PSR-18 implementation out of the box. For a PSR-18 implementation, check out the HTTP Client repository.

ServerRequest

The Zaphyr\HttpMessage\ServerRequest object represents an HTTP request received by the server. It encapsulates the incoming request data received from the client. The server request object contains details such as the request method, headers, and payload data sent by the client. The ServerRequest implements the PSR-7 ServerRequestInterface:

$serverRequest = new Zaphyr\HttpMessage\ServerRequest(
    method:'GET',
    uri: 'https://example.com',
    body: 'php://input',
    headers: getallheaders(),
    protocol: '1.1',
    serverParams: $_SERVER,
    cookieParams: $_COOKIE,
    queryParams: $_GET,
    uploadedFiles: $_FILES,
);

Response

The Zaphyr\HttpMessage\Response object serves as a concrete implementation of the PSR-7 ResponseInterface. It functions as a versatile object that consolidates response information for both HTTP clients and server-side applications. This includes essential details such as response headers and the content of the message body.

Writing to the body does not create a state change in the response, so it can be done without capturing the return value. Manipulating headers does, however:

$response = new Zaphyr\HttpMessage\Response(
    body: 'php://memory',
    status: 200,
    headers: ['Content-Type' => 'text/html'],
);

$response->getBody()->write("Hello World");

$response = $response->withHeader('Content-Type', 'text/plain');
Note

Headers do not need to be added before data is written to the body!

Stream

The Zaphyr\HttpMessage\Stream class is a wrapper around PHP streams implementing the PSR-7 StreamInterface. The constructor accepts a stream, which may be either:

a string stream identifier; e.g., php://input or a filename:

$stream = new Zaphyr\HttpMessage\Stream('php://input');

or a PHP stream resource:

$resource = fopen('php://memory', 'r+');
$stream = new Zaphyr\HttpMessage\Stream($resource);

If a string stream identifier is provided, an optional second parameter may be provided, the file mode by which to fopen the stream:

$stream = new Zaphyr\HttpMessage\Stream('php://memory', 'wb+');
  • Zaphyr\HttpMessage\ServerRequest objects by default use a php://input stream set to read-only.
  • Zaphyr\HttpMessage\Response objects by default use a php://memory with a mode of wb+, allowing binary read/write access.

URI

The Zaphyr\HttpMessage\Uri class is meant to represent URIs according to RFC 3986. It allows you to get and change any specific part of an URI. For the full documentation about the Zaphyr\HttpMessage\Uri class, please see PSR-7 UriInterface.

The Zaphyr\HttpMessage\Uri object only supports the http and https schemes:

$uri = new Zaphyr\HttpMessage\Uri("http://www.example.com/foo");

UploadedFile

The Zaphyr\HttpMessage\UploadedFile is an implementation of the PSR-7 UploadedFileInterface and represents a single uploaded file within an HTTP request. It encapsulates the file's metadata and provides methods to interact with the uploaded file as a stream or moving it to a filesystem location:

$uploadedFile = new Zaphyr\HttpMessage\UploadedFile(
    streamOrFile: new Zaphyr\HttpMessage\Stream(fopen('php://temp', 'wb+')),
    size: 0,
    error: UPLOAD_ERR_OK,
    clientFilename: 'foo.txt',
    clientMediaType: 'text/plain'
);

Factories

The primary purpose of the PSR-17 HTTP Factories is to abstract the creation of HTTP message objects, such as requests and responses, from their implementations. This allows you to write code that works with any compliant PSR-17 implementation, promoting flexibility and code reuse across different PHP projects. The HTTP Message service supplies implementations of each as follows:

  • Zaphyr\HttpMessage\Factories\RequestFactory
  • Zaphyr\HttpMessage\Factories\ResponseFactory
  • Zaphyr\HttpMessage\Factories\ServerRequestFactory
  • Zaphyr\HttpMessage\Factories\StreamFactory
  • Zaphyr\HttpMessage\Factories\UploadedFileFactory
  • Zaphyr\HttpMessage\Factories\UriFactory

Example

Here's a simple example using the HTTP Message service to create a PSR-7 compliant HTTP request:

$requestFactory = new Zaphyr\HttpMessage\Factories\RequestFactory();
$request = $requestFactory->createRequest('GET', 'https://example.com');

$response = $client->sendRequest($request);

echo $response->getBody();
Note

This repository does NOT come with a PSR-18 implementation out of the box. For a PSR-18 implementation, check out the HTTP Client repository.