Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Http Server Laravel Package

hyperf/http-server

Hyperf HTTP Server provides a high-performance, coroutine-based HTTP server for the Hyperf framework, built on Swoole or Swow. It offers PSR-7/PSR-15 middleware support, powerful routing, annotation-driven controllers, and fast request handling for scalable PHP microservices.

View on GitHub
Deep Wiki
Context7

Getting Started

Set expectations first: hyperf/http-server is not a Laravel package. It is the HTTP server component of the Hyperf framework — a coroutine-native, long-running PHP runtime built on Swoole/Swow. You cannot composer require it into a Laravel app and get anything useful; if you are staying on Laravel, this package is only worth reading as a reference for how a persistent-worker HTTP kernel is structured. If you are evaluating a Laravel → Hyperf migration, this is the component that replaces the Illuminate\Foundation\Http\Kernel + Request/Response stack.

Version note (v3.2.0): This release raises the floor to PHP >= 8.2, upgrades Symfony components to ^6.0 || ^7.0, and PHPUnit to ^11.0. If you are starting fresh, you get 3.2; if you are upgrading from 3.1, read the Gotchas section first — three config files (logger.php, cache.php, dependencies.php for Swow) changed shape.

Minimal install path (Hyperf app):

composer create-project hyperf/hyperf-skeleton my-app   # brings http-server + router + DI
cd my-app
php bin/hyperf.php start                               # listens on 0.0.0.0:9501

Standalone in an existing Hyperf project:

composer require hyperf/http-server hyperf/router

If you are on Swow: v3.2 requires an explicit dependency mapping (Swoole installs do not need it):

// config/autoload/dependencies.php
return [
    \Hyperf\Contract\ResponseEmitterInterface::class => \Hyperf\Engine\ResponseEmitter::class,
];

Where to look first, in this order:

  1. config/autoload/server.php — the equivalent of public/index.php + kernel bootstrap. Look for the servers array and the entry mapping a port to Hyperf\HttpServer\Server::class.
  2. config/routes.php — imperative route definitions (Router::get('/hello', ...)).
  3. app/Controller/ — annotation-driven controllers (#[Controller], #[GetMapping]), the closest thing to Laravel's controller ergonomics.
  4. config/autoload/middlewares.php and config/autoload/exceptions.php — per-server middleware stack and exception handling.

First use case — a JSON endpoint with injected request/response:

<?php
namespace App\Controller;

use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\HttpServer\Contract\ResponseInterface;
use Hyperf\Di\Annotation\Inject;

class UserController
{
    #[Inject]
    protected RequestInterface $request;

    #[Inject]
    protected ResponseInterface $response;

    public function show(int $id)
    {
        $verbose = $this->request->input('verbose', false);
        $user    = $this->request->route('id');   // route params are attributes

        return $this->response->json([
            'id'      => $id,
            'verbose' => $verbose,
            'user'    => $user,
        ]);
    }
}
// config/routes.php
Router::get('/users/{id:\d+}', 'App\Controller\UserController@show');

Two things that immediately feel different from Laravel: (a) the controller is resolved from the DI container per request, not per-instantiation-per-request-per-call like FPM, and (b) you must return a Psr\Http\Message\ResponseInterface — echo and die() do not produce a response.

Implementation Patterns

Controller injection. Constructor injection works, but #[Inject] on properties is the idiomatic Hyperf style for RequestInterface/ResponseInterface, because those contracts are proxy-resolved to the current coroutine's request. For anything request-scoped, prefer injecting the interface and letting the container hand you the coroutine-local instance — never new Request() yourself.

Routing: two coexisting styles. Annotation routing (#[Controller(prefix: '/api')], #[GetMapping(path: 'users/{id}')]) for app code, and config/routes.php for glue/health checks/proxies. Annotation routes are cached; see Gotchas. Route middleware is attached with #[Middleware(FooMiddleware::class)] per controller or per method — the closest analogue to Laravel's ->middleware() on route groups.

Middleware is PSR-15, not Laravel's pipeline. Signatures are process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface. Register globally per server in config/autoload/middlewares.php:

return [
    'http' => [                       // keyed by the server name from server.php
        App\Middleware\CorsMiddleware::class,
        App\Middleware\AuthMiddleware::class,   // order = execution order
    ],
];

Because the key is the server name, a second HTTP server on port 9502 can have an entirely different middleware stack. This is a genuinely nice pattern for separating public API from internal/admin traffic in one process.

Exception → response mapping. Mirror Laravel's Handler::render() with Hyperf's exception handlers:

class ValidationExceptionHandler extends ExceptionHandler
{
    public function handle(Throwable $throwable, ResponseInterface $response)
    {
        $this->stopPropagation();
        return $response->json(['message' => $throwable->getMessage()], 422);
    }

    public function isValid(Throwable $throwable): bool
    {
        return $throwable instanceof ValidationException;
    }
}

Register in config/autoload/exceptions.php under the same server name. Note the explicit stopPropagation() — without it the next handler (and eventually the framework's HttpExceptionHandler) also runs.

Request-scoped state: use Context, not singletons. This is the single biggest mental shift from Laravel. Any singleton (service, repository, listener) lives for the life of the worker, not the request. If you need "current user" in a service, stash it in the coroutine context:

use Hyperf\Context\Context;

Context::set('user', $user);           // in middleware
$user = Context::get('user');         // anywhere downstream, same coroutine

As of v3.2, Hyperf\Context\Context is Macroable, so you can wrap common patterns (Context::macro('user', ...)) instead of stringly-typed keys scattered across the codebase. Still: never store a RequestInterface (or anything holding one) on a singleton or in a static property — the next coroutine will read the previous request's data.

Responding with HTML / JSON contracts. v3.2 added Hyperf\Contract\Jsonable::toJson() and an Htmlable contract for HTTP responses. If you build a response-like value object, implement these instead of hand-serialising in the controller — the response emitter recognises them and skips your manual json_encode.

Async work. v3.2 added automatic registration of async queue consumer processes from configuration — no more hand-bolting every consumer into config/autoload/processes.php. If you previously registered consumers manually, prefer the config-driven path; it keeps worker counts next to the queue definition instead of scattered in a bootstrap file.

Customizing the server. Extending Hyperf\HttpServer\Server and overriding onRequest is the extension point for global concerns that don't fit middleware (e.g. injecting a request ID into logs before dispatch, or short-circuiting on a maintenance flag). Register the subclass in server.php in place of the default class. Swoole-level knobs (max_request, package_max_length, open_http2_protocol, SWOOLE_BASE vs SWOOLE_PROCESS) live in the same array's settings key.

Integration tips. Use hyperf/validation for rules, but call it explicitly ($this->validator->validate(...)) — there is no $request->validate(). File uploads come from $request->file('avatar') and land in runtime/ unless you configure upload_tmp_dir. For streaming/large downloads, return a Psr\Http\Message\ResponseInterface backed by a stream rather than buffering a string. For tests, Hyperf\Testing\Client gives you a Laravel-ish $client->get('/users/1')->assertStatus(200) without a real socket; v3.2's #[NonCoroutine] attribute lets you mark specific tests that must run outside a coroutine, which is handy for anything touching Swow/Swoole internals.

Gotchas and Tips

  • Upgrade blockers in v3.2 — check these before you deploy.
    • Logger config shape changed. config/autoload/logger.php now uses default as a channel name plus a channels map, instead of default being the channel definition itself. The old array silently produces "no logger" behaviour; existing path/driver/days settings must move under channels.default.
    • Cache config shape changed. config/autoload/cache.php now has default pointing at a store name plus a stores map. Same failure mode — old config looks valid, caches just miss or throw on boot.
    • Carbon BC. Carbon::createFromTimestamp() no longer falls back to date_default_timezone_get(); diffInDays() no longer returns an absolute value by default. Any code relying on either will drift silently after upgrade.
    • JobInterface::getQueueName() renamed to getPoolName(). Custom jobs overriding the old method compile-fail; grep before you composer update.
    • Swow dependency mapping (see Getting Started) — Swoole users can ignore, Swow users will fail to emit responses without it.
  • PHP 8.4 warning. fputcsv() / fgetcsv() now require an explicit escape (pass escape: '') before the deprecation turns fatal in your error collector. The framework did this internally in 3.2, but any application-level CSV export needs the same treatment.
  • No superglobals. $_GET, $_POST, $_SERVER, $_FILES, header(), setcookie() are all inert or misleading. Use $request->getQueryParams(), $request->getParsedBody(), $request->getHeaders(), $response->withCookie(...). Legacy code lifted from FPM apps will silently return empty data.
  • Singletons leak across requests. A property set on a #[Singleton] service in request A is still there in request B, and worse, is visible to a concurrent request in a different coroutine. Treat every singleton as immutable after boot. Same applies to the new Context macro cache — macros themselves are fine, but the keys you set are coroutine-scoped.
  • Blocking I/O is the classic production failure. sleep(), raw PDO, file_get_contents() on a remote URL, and heavy curl without hooks stall the entire worker. Either enable Swoole runtime hooks (SWOOLE_HOOK_ALL, usually on by default in the skeleton) or use the coroutine-native clients (hyperf/guzzle, hyperf/db-connection, hyperf/redis, Hyperf\Coroutine\System::sleep()). This is the #1 thing that makes a migrated Laravel app mysteriously slow under load.
  • Annotation cache vs. production. Adding a controller or route in dev "just works"; in production with scan_cacheable enabled in config/autoload/annotations.php, new annotations are invisible until you regenerate the scan cache as part of your deploy. Make that a build step, not a debugging surprise.
  • Port/worker config is in server.php, not .env alone. max_request (default ~100k) recycles workers — which is why long-lived in-memory caches are eventually wiped. package_max_length must be raised for large uploads; otherwise requests fail at the Swoole layer before your middleware ever runs, producing confusing empty-request errors.
  • Client IP behind a proxy. $request->getClientIp() returns the socket peer (your load balancer). Read X-Forwarded-For explicitly, and only trust it when the immediate peer is a known proxy.
  • Database ergonomics changed. In v3.2, deleted_at defaults to datetime rather than timestamp (check your migrations and any direct SQL), QueryException now carries the connection name (use it in your exception handlers to distinguish primary vs replica failures), and limit() throws on negative values rather than silently coercing.
  • Debugging. Logs land in runtime/logs/hyperf.log; enable the stdout logger (Hyperf\Framework\Logger\StdoutLogger) for fast feedback during development. v3.2 added a timestamp prefix to stdout log output — useful when you were previously guessing which line belonged to which request. var_dump inside a coroutine is interleaved across concurrent requests — include a request ID (set in middleware via Context) or you will misread the output. Watch mode: php bin/hyperf.php server:watch.
  • Exception handler ordering is silent. If your handler's isValid() returns true but you forget stopPropagation(), the framework's default handler overwrites your JSON with a generic 500 — a very common "my handler doesn't work" report.
  • Removed in v3.2 — audit your vendor tree. laminas/laminas-mime is gone; Hyperf\Serializer\Contract\CacheableSupportsMethodInterface is gone; Hyperf\AsyncQueue\JobMessage backward-compatible deserialisation is gone (old serialised payloads in Redis will fail to hydrate after the upgrade — drain the queue or accept a replay window); and a long tail of deprecated aliases (ResumeExitCoordinatorListener, SocketIO Future flag, WebSocket HandeShakeException typo alias) has been dropped.
  • The stats are misleading. hyperf/http-server is a read-only split of the hyperf/hyperf monorepo; the star count and release cadence belong to the split repo, not the ecosystem. Judge adoption by the monorepo and the docs at hyperf.wiki — issues and PRs are filed upstream, so searching this repository alone will look like an abandoned project.
  • Laravel package compatibility is essentially zero. illuminate/* components assume a synchronous container and superglobal-backed Request; they will not drop in. Budget for rewriting HTTP-layer code (form requests, middleware, exception rendering, session, CSRF) rather than expecting adapters. The payoff is that a Hyperf worker handles orders of magnitude more requests per process — but only if you honor the coroutine rules above.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
vento/laravel-airbrake
wfeller/laravel-batch
maco-studios/mage-os-installer
busarm/armie
siberfx/laravel-logger
kfteam1991/dcat-admin
dashed/dashed-laposta
dashed/dashed-ecommerce-montaportal
dashed/dashed-ecommerce-etsy
neohq/string-blade-compiler
log1x/acf-composer
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core
nodisrupt/laravel-agent
sierratecnologia/media-manager