agentsclimarketplace

Php http psr

Skill fusengine/agents/plugins/php-expert/skills/php-http-psr

Use when building framework-agnostic HTTP code in PHP — PSR-7 messages, PSR-15 middleware pipelines, PSR-17 factories, PSR-18 HTTP clients. Covers immutable Request/Response/Stream/Uri, RequestHandler + Middleware, factory interfaces, and reference implementations (nyholm/psr7, guzzlehttp/psr7, laminas-diactoros). Do NOT use for Laravel HTTP (use laravel-expert) or Symfony HttpFoundation (not PSR-7 — see references/implementations.md).From its SKILL.md

Install
npx -y skills add fusengine/agents --skill php-http-psr

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 22 stars22 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

6.0 KB, ~1.3k tokens by cl100k_base, as published. Nobody here has run it

PHP HTTP — PSR-7 / 15 / 17 / 18

Agent Workflow (MANDATORY)

Before ANY implementation, use TeamCreate to spawn 3 agents:

  1. fuse-ai-pilot:explore-codebase - Detect the PSR-7 implementation already in use (composer.json)
  2. fuse-ai-pilot:research-expert - Verify current interface versions on php-fig.org + Packagist
  3. mcp__context7__query-docs - Check the chosen implementation's factory API

After implementation, run fuse-ai-pilot:sniper for validation.


Overview

These four PSR standards let libraries handle HTTP without coupling to any framework. Code depends on interfaces (Psr\Http\*); a concrete implementation is injected.

StandardPackageProvides
PSR-7psr/http-messageImmutable HTTP messages: MessageInterface, RequestInterface, ResponseInterface, ServerRequestInterface, StreamInterface, UriInterface, UploadedFileInterface
PSR-15psr/http-server-handler + psr/http-server-middlewareRequestHandlerInterface, MiddlewareInterface — the middleware pipeline
PSR-17psr/http-factoryFactories that create PSR-7 objects without naming a concrete class
PSR-18psr/http-clientClientInterface::sendRequest() — send a PSR-7 request, get a PSR-7 response

Critical Rules

  1. Messages are immutable - Every with*() returns a NEW instance; the original is unchanged. $r->withHeader(...) alone is a no-op — reassign.
  2. Depend on interfaces, not classes - Type-hint ResponseInterface, inject a ResponseFactoryInterface. NEVER new Response() inside reusable code.
  3. Streams are NOT immutable - StreamInterface wraps a real resource; use read-only streams for requests/responses.
  4. PSR-18 4xx/5xx are NOT errors - A client MUST return them as normal responses; it throws only on transport failure (NetworkExceptionInterface) or malformed requests (RequestExceptionInterface).
  5. Headers are case-insensitive - getHeaderLine('foo') == getHeaderLine('FOO'); original case is preserved in getHeaders().

Architecture

src/
├── Http/
│   ├── Middleware/          # implements Psr\Http\Server\MiddlewareInterface
│   │   ├── ErrorHandlerMiddleware.php
│   │   └── AuthMiddleware.php
│   ├── Handler/             # implements Psr\Http\Server\RequestHandlerInterface
│   │   └── Dispatcher.php   # the pipeline runner
│   └── Client/              # wraps a Psr\Http\Client\ClientInterface
└── interfaces/              # your own contracts (SOLID)

→ See middleware-pipeline.md for a complete runnable pipeline


Reference Guide

Concepts

TopicReferenceWhen to Consult
Messagespsr7-messages.mdReading/building requests, responses, streams, URIs
Middlewarepsr15-middleware.mdBuilding a middleware + handler pipeline
Factoriespsr17-factories.mdCreating PSR-7 objects implementation-agnostically
HTTP Clientpsr18-client.mdSending outbound requests, exception handling
Implementationsimplementations.mdChoosing nyholm / guzzle / laminas + PSR-18 clients

Templates

TemplateWhen to Use
middleware-pipeline.mdBuilding a PSR-15 dispatcher with middleware queue

Quick Reference

Immutable update (reassign!)

$response = $response
    ->withStatus(201)
    ->withHeader('Content-Type', 'application/json');

Minimal middleware

final class AuthMiddleware implements MiddlewareInterface
{
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        if (!$request->hasHeader('Authorization')) {
            return $this->responseFactory->createResponse(401);
        }
        return $handler->handle($request);
    }
}

PSR-17 factory (no concrete class named)

$request = $requestFactory->createRequest('GET', 'https://api.example.com');
$request = $request->withBody($streamFactory->createStream('{"ping":true}'));

→ See psr17-factories.md for all six factory interfaces


Best Practices

DO

  • Inject a ResponseFactoryInterface so middleware never names a concrete class
  • Put an exception-catching middleware FIRST in the queue (PSR-15 recommendation)
  • Use nyholm/psr7 when you want a lightweight, strict PSR-7 + PSR-17 in one package
  • Reassign the result of every with*() call

DON'T

  • Mutate a message in place — with*() returns a new object
  • Treat a 404/500 response from a PSR-18 client as an exception
  • Confuse Symfony HttpFoundation with PSR-7 — they are different; bridge via symfony/psr-http-message-bridge
  • Hardcode new GuzzleHttp\Psr7\Response() in library code — depend on the factory

What ships with it: 7 files

20.5 KB alongside SKILL.md

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.