coroq / http-responder
Simple PSR-7 HTTP response factory with semantic method names
Installs: 4
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/coroq/http-responder
Requires
- php: ^8.0
- psr/http-factory: ^1.0
- psr/http-message: ^1.0 || ^2.0
Requires (Dev)
- nyholm/psr7: ^1.5
- phpunit/phpunit: ^9.5 || ^10.0
README
PSR-7 HTTP response factory with semantic method names.
Requirements
- PHP ^8.0
- PSR-7 HTTP Message implementation (e.g.,
nyholm/psr7,guzzlehttp/psr7) - PSR-17 HTTP Factory implementation (e.g.,
nyholm/psr7,laminas/laminas-diactoros)
Installation
composer require coroq/http-responder
Quick Start
use Coroq\HttpResponder\Responder; use Coroq\HttpResponder\JsonResponder; // Inject PSR-17 ResponseFactoryInterface $responder = new Responder($responseFactory); // Returns PSR-7 ResponseInterface with status 200 and HTML body return $responder->ok('<h1>Hello World</h1>'); // For JSON responses, use JsonResponder $responder = new JsonResponder($responseFactory); // Returns PSR-7 ResponseInterface with status 200, Content-Type: application/json, // and body: {"status":"success"} return $responder->ok(['status' => 'success']);
Concepts
Two independent classes for different response types:
- Responder - HTML, text, file downloads
- JsonResponder - JSON responses with automatic encoding
Method names map directly to HTTP status codes. No need to remember numbers.
Both classes return PSR-7 ResponseInterface, allowing standard PSR-7 chaining.
Who Is This For?
For developers building PSR-7/PSR-15 applications who want readable response creation without framework coupling. Good fit for Mezzio, Slim, or custom middleware stacks mixing HTML and JSON responses.
Not for pure REST APIs needing comprehensive status code coverage, or Laravel/Symfony projects with built-in response helpers.
Usage
Basic Responses
$responder = new Responder($responseFactory); // 200 OK return $responder->ok('Hello World'); return $responder->ok($streamInterface); return $responder->ok(); // empty body // 401 Unauthorized return $responder->unauthorized('Login required'); // 403 Forbidden return $responder->forbidden(); // 404 Not Found return $responder->notFound('<h1>Not Found</h1>'); // 500 Internal Server Error return $responder->internalServerError(); // 503 Service Unavailable return $responder->serviceUnavailable('Under maintenance'); // Custom status return $responder->response(418);
File Downloads
// With filename return $responder->okDownload( $fileContent, 'application/pdf', 'invoice.pdf' ); // UTF-8 filenames work return $responder->okDownload( $content, 'text/plain', 'ファイル.txt' ); // Without filename return $responder->okDownload($stream, 'image/png');
Redirects
// 302 Found (temporary redirect) return $responder->found('/login'); // With query parameters return $responder->found('/search', ['q' => 'test', 'page' => '2']); // With fragment return $responder->found('/page', [], 'section-3'); // Both return $responder->found('/article', ['id' => '123'], 'comments'); // 301 Moved Permanently return $responder->movedPermanently('/new-url'); return $responder->movedPermanently('/new', ['ref' => 'old']);
JSON Responses
$responder = new JsonResponder($responseFactory); // 200 OK return $responder->ok(['user' => 'john', 'status' => 'active']); // 201 Created return $responder->created(['id' => 123, 'created_at' => '2024-01-01']); // 400 Bad Request return $responder->badRequest(['error' => 'Invalid email format']); // 401 Unauthorized return $responder->unauthorized(['error' => 'Token expired']); // 403 Forbidden return $responder->forbidden(['error' => 'Insufficient permissions']); // 404 Not Found return $responder->notFound(['error' => 'User not found']); // 500 Internal Server Error return $responder->internalServerError(['error' => 'Database connection failed']); // 503 Service Unavailable return $responder->serviceUnavailable(['error' => 'Maintenance mode']); // Custom status return $responder->response(418, ['message' => "I'm a teapot"]);
JSON Redirects
return $responder->found('/dashboard'); return $responder->movedPermanently('/new-api', [], 'v2');
JSON Encoding Options
// Default flags: JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES $responder = new JsonResponder($responseFactory); return $responder->ok(['path' => '/foo/bar', 'name' => '日本語']); // Output: {"path":"/foo/bar","name":"日本語"} // Override flags for one response return $responder->withEncodingOptions(JSON_PRETTY_PRINT)->ok($data); // Returns new instance, original unchanged // Configure at construction $responder = new JsonResponder($responseFactory, JSON_PRETTY_PRINT); // Custom encoder $encoder = fn($data) => json_encode($data, JSON_THROW_ON_ERROR); $responder = new JsonResponder($responseFactory, 0, $encoder);