DEV Community

Russell Jones
Russell Jones

Posted on • Originally published at jonesrussell.github.io on

PSR-7: HTTP Message Interfaces in PHP

PSR-7 defines common interfaces for representing HTTP messages in PHP. These interfaces enable framework-agnostic HTTP message handling, making it easier to create interoperable HTTP clients, servers, and middleware.

Core Interfaces

1. Message Interface

<?php

namespace Psr\Http\Message;

interface MessageInterface
{
    public function getProtocolVersion();
    public function withProtocolVersion($version);
    public function getHeaders();
    public function hasHeader($name);
    public function getHeader($name);
    public function getHeaderLine($name);
    public function withHeader($name, $value);
    public function withAddedHeader($name, $value);
    public function withoutHeader($name);
    public function getBody();
    public function withBody(StreamInterface $body);
}

Enter fullscreen mode Exit fullscreen mode

2. Request Interface

<?php

namespace Psr\Http\Message;

interface RequestInterface extends MessageInterface
{
    public function getRequestTarget();
    public function withRequestTarget($requestTarget);
    public function getMethod();
    public function withMethod($method);
    public function getUri();
    public function withUri(UriInterface $uri, $preserveHost = false);
}

Enter fullscreen mode Exit fullscreen mode

3. Response Interface

<?php

namespace Psr\Http\Message;

interface ResponseInterface extends MessageInterface
{
    public function getStatusCode();
    public function withStatus($code, $reasonPhrase = '');
    public function getReasonPhrase();
}

Enter fullscreen mode Exit fullscreen mode

Basic Implementation

1. Creating Requests

<?php

use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\Uri;

// Simple GET request
$request = new Request(
    'GET',
    'https://api.example.com/users'
);

// POST request with JSON body
$request = new Request(
    'POST',
    'https://api.example.com/users',
    [
        'Content-Type' => 'application/json'
    ],
    json_encode(['name' => 'John Doe'])
);

Enter fullscreen mode Exit fullscreen mode

2. Handling Responses

<?php

use GuzzleHttp\Psr7\Response;

$response = new Response(
    200,
    ['Content-Type' => 'application/json'],
    json_encode(['status' => 'success'])
);

// Working with responses
$status = $response->getStatusCode();
$body = $response->getBody()->getContents();
$contentType = $response->getHeaderLine('Content-Type');

Enter fullscreen mode Exit fullscreen mode

HTTP Client Implementation

<?php

class HttpClient
{
    public function sendRequest(RequestInterface $request): ResponseInterface
    {
        $context = stream_context_create([
            'http' => [
                'method' => $request->getMethod(),
                'header' => $this->formatHeaders($request->getHeaders()),
                'content' => (string) $request->getBody(),
                'protocol_version' => $request->getProtocolVersion(),
                'ignore_errors' => true,
            ],
        ]);

        $body = file_get_contents($request->getUri(), false, $context);
        $response = new Response(
            $this->getStatusCode($http_response_header),
            $this->parseHeaders($http_response_header),
            $body
        );

        return $response;
    }

    private function formatHeaders(array $headers): string
    {
        $lines = [];
        foreach ($headers as $name => $values) {
            $lines[] = $name . ': ' . implode(', ', $values);
        }
        return implode("\r\n", $lines);
    }

    // Additional helper methods...
}

Enter fullscreen mode Exit fullscreen mode

Middleware Pattern

<?php

interface MiddlewareInterface
{
    public function process(
        RequestInterface $request,
        RequestHandlerInterface $handler
    ): ResponseInterface;
}

class LoggingMiddleware implements MiddlewareInterface
{
    public function process(
        RequestInterface $request,
        RequestHandlerInterface $handler
    ): ResponseInterface {
        // Log request
        $response = $handler->handle($request);
        // Log response
        return $response;
    }
}

Enter fullscreen mode Exit fullscreen mode

Framework Integration

1. Laravel Example

<?php

use Illuminate\Http\Request;
use Psr\Http\Message\ServerRequestInterface;
use Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory;

class PsrBridge
{
    public function toServerRequest(Request $request): ServerRequestInterface
    {
        $psr17Factory = new Psr17Factory();
        $psrHttpFactory = new PsrHttpFactory($psr17Factory, $psr17Factory, $psr17Factory, $psr17Factory);

        return $psrHttpFactory->createRequest($request);
    }
}

Enter fullscreen mode Exit fullscreen mode

2. Symfony Example

<?php

use Symfony\Bridge\PsrHttpMessage\Factory\HttpFoundationFactory;
use Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory;

// Convert PSR-7 to Symfony
$httpFoundationFactory = new HttpFoundationFactory();
$symfonyRequest = $httpFoundationFactory->createRequest($psrRequest);

// Convert Symfony to PSR-7
$psr17Factory = new Psr17Factory();
$psrHttpFactory = new PsrHttpFactory($psr17Factory, $psr17Factory, $psr17Factory, $psr17Factory);
$psrRequest = $psrHttpFactory->createRequest($symfonyRequest);

Enter fullscreen mode Exit fullscreen mode

Best Practices

  1. Immutability
// Bad - Modifying message directly
$request->method = 'POST';

// Good - Using withers
$newRequest = $request->withMethod('POST');

Enter fullscreen mode Exit fullscreen mode
  1. Stream Handling
// Bad - Loading entire body into memory
$content = $request->getBody()->getContents();

// Good - Streaming large responses
$body = $response->getBody();
while (!$body->eof()) {
    echo $body->read(8192);
}

Enter fullscreen mode Exit fullscreen mode

Common Patterns

1. Request Builder

<?php

class RequestBuilder
{
    private $method = 'GET';
    private $uri;
    private $headers = [];
    private $body;

    public function method(string $method): self
    {
        $this->method = $method;
        return $this;
    }

    public function uri(string $uri): self
    {
        $this->uri = new Uri($uri);
        return $this;
    }

    public function build(): RequestInterface
    {
        return new Request(
            $this->method,
            $this->uri,
            $this->headers,
            $this->body
        );
    }
}

Enter fullscreen mode Exit fullscreen mode

2. Response Factory

<?php

class ResponseFactory
{
    public static function json(
        $data,
        int $status = 200,
        array $headers = []
    ): ResponseInterface {
        return new Response(
            $status,
            array_merge(
                ['Content-Type' => 'application/json'],
                $headers
            ),
            json_encode($data)
        );
    }
}

Enter fullscreen mode Exit fullscreen mode

Next Steps

In our next post, we’ll explore PSR-15, which builds upon PSR-7 to define HTTP server request handlers and middleware. Check out our example repository for the implementation of these standards.

Resources

Baamaapii 👋

AWS Security LIVE!

Join us for AWS Security LIVE!

Discover the future of cloud security. Tune in live for trends, tips, and solutions from AWS and AWS Partners.

Learn More

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay