{"id":50490736,"url":"https://github.com/bowphp/microservice","last_synced_at":"2026-06-02T02:30:57.724Z","repository":{"id":359234403,"uuid":"1244950756","full_name":"bowphp/microservice","owner":"bowphp","description":null,"archived":false,"fork":false,"pushed_at":"2026-05-21T00:18:36.000Z","size":1144,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-21T06:50:49.342Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bowphp.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-20T19:02:01.000Z","updated_at":"2026-05-21T00:18:40.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/bowphp/microservice","commit_stats":null,"previous_names":["bowphp/microservice"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/bowphp/microservice","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bowphp%2Fmicroservice","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bowphp%2Fmicroservice/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bowphp%2Fmicroservice/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bowphp%2Fmicroservice/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bowphp","download_url":"https://codeload.github.com/bowphp/microservice/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bowphp%2Fmicroservice/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33803734,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-02T02:00:07.132Z","response_time":109,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-02T02:30:56.919Z","updated_at":"2026-06-02T02:30:57.715Z","avatar_url":"https://github.com/bowphp.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# bowphp/microservice\n\nA NestJS-style, multi-transport microservice layer for **BowPHP**. One handler\nAPI, five transports: **TCP**, **Redis** (pub/sub), **RabbitMQ** (AMQP),\n**Kafka**, and **gRPC** (client only).\n\nThe design mirrors NestJS: you write *controllers* whose methods carry\n`#[MessagePattern]` (request/response) or `#[EventPattern]` (fire-and-forget)\nattributes, then run a consumer that listens on a transport. Callers use a\n`ClientProxy` with `send()` / `emit()`. The transport only moves bytes — your\nhandlers never change when you switch protocols.\n\n\u003e 📖 Full user guide: [docs/en.md](docs/en.md) — French version: [docs/fr.md](docs/fr.md)\n\n## Architecture\n\nThe package is a **framework-agnostic core** with a thin BowPHP adapter:\n\n```\nContracts/         ServerTransport, ClientTransport, Serializer  (the seams)\nMessage/           Packet, ResponsePacket, JsonSerializer        (wire format)\nConsumer/          MicroserviceServer, HandlerRegistry,\n                   MessagePattern, EventPattern, MicroserviceFactory\nClient/            ClientProxy, ClientFactory\nTransport/         {Tcp,Redis,RabbitMq,Kafka}{Server,Client}Transport\n                   GrpcClientTransport + Grpc/ (envelope, stub, codec)\nBow/               MicroserviceConfiguration  (the ONLY Bow-coupled file)\n```\n\nEvery transport implements the same two contracts, so adding a sixth (NATS,\nMQTT, etc.) means writing one server + one client class — nothing else moves.\n\n### The envelope\n\nAll transports share one packet shape (like Nest's `{ pattern, data, id }`):\n\n- **RPC**: request `Packet` → handler return value → `ResponsePacket`, matched\n  back to the caller by `id`.\n- **Event**: `Packet` with no reply.\n\nHow each transport correlates replies:\n\n| Transport | RPC reply mechanism                                  |\n|-----------|------------------------------------------------------|\n| TCP       | same socket, 4-byte length-prefixed JSON frames      |\n| Redis     | PUBLISH on `pattern` → RPUSH on `bow:reply:\u003cid\u003e`     |\n| RabbitMQ  | `reply_to` queue + `correlation_id`                  |\n| Kafka     | reply topic + `kafka_correlationId` header           |\n| gRPC      | unary `MessageService.Send` returns MessageEnvelope  |\n\n## Install\n\n```bash\ncomposer require bowphp/microservice\n```\n\nThen install the extension/library for the transport(s) you use:\n\n- TCP → `ext-sockets` (built in on most PHP)\n- Redis → `ext-redis` (phpredis)\n- RabbitMQ → `composer require php-amqplib/php-amqplib`\n- Kafka → `ext-rdkafka`\n- gRPC (client) → `pecl install grpc \u0026\u0026 composer require grpc/grpc google/protobuf`\n\n## Define handlers\n\n```php\nuse Bow\\Microservice\\Consumer\\MessagePattern;\nuse Bow\\Microservice\\Consumer\\EventPattern;\nuse Bow\\Microservice\\Message\\Packet;\n\nfinal class UserController\n{\n    #[MessagePattern('user.find')]\n    public function find(mixed $data, Packet $packet): array\n    {\n        return ['id' =\u003e $data['id'], 'name' =\u003e \"User #{$data['id']}\"];\n    }\n\n    #[EventPattern('user.created')]\n    public function onCreated(mixed $data): void\n    {\n        // send welcome email, etc.\n    }\n}\n```\n\n## Run the consumer\n\nTwo equivalent entrypoints — the BowPHP-integrated console command (recommended)\nand a standalone script:\n\n```bash\n# BowPHP console command — registered automatically by MicroserviceConfiguration\nphp bow microservice:listen --transport=redis    --patterns=user.find,user.created\nphp bow microservice:listen --transport=tcp      --host=0.0.0.0 --port=3000\nphp bow microservice:listen --transport=rabbitmq --queue=bow_microservice\nphp bow microservice:listen --transport=kafka    --topics=user_events --group=users\n\n# Standalone script — no Bow integration required\nphp examples/microservice.php --transport=redis --patterns=user.find\n```\n\nBoth honour `config/microservice.php`; CLI flags override config. They install\nSIGTERM/SIGINT handlers (when `ext-pcntl` is available) so supervisord /\nsystemd / Kubernetes can drain a worker cleanly. Run N copies for concurrency.\n\n## Call from another service\n\n```php\nuse Bow\\Microservice\\Client\\ClientFactory;\n\n$proxy = ClientFactory::create('redis', ['host' =\u003e '127.0.0.1']);\n$proxy-\u003econnect();\n\n$user = $proxy-\u003esend('user.find', ['id' =\u003e 42]); // RPC, blocks for reply\n$proxy-\u003eemit('user.created', ['id' =\u003e 99]);       // fire-and-forget\n\n// gRPC client to a non-PHP server implementing proto/microservice.proto\n$grpc = ClientFactory::create('grpc', ['host' =\u003e '127.0.0.1', 'port' =\u003e 50051]);\n$grpc-\u003econnect();\n$grpc-\u003esend('user.find', ['id' =\u003e 42]);\n```\n\n## BowPHP integration\n\nRegister the configuration provider in your Kernel so a connected `ClientProxy`\nis bound in the container:\n\n```php\n// app/Kernel.php\npublic function configurations(): array\n{\n    return [\n        \\Bow\\Microservice\\Bow\\MicroserviceConfiguration::class,\n    ];\n}\n```\n\nAdd `config/microservice.php` to your app (see this repo's\n[`config/microservice.php`](config/microservice.php) for the template). The\nprovider binds both `ClientProxy::class` and the `microservice.client` alias.\n\nBoth consumer entrypoints (`php bow microservice:listen` and\n`php examples/microservice.php`) boot the kernel and instantiate controllers\nthrough Bow's container — so your consumers can use constructor DI just like\nHTTP controllers. List them in `config('microservice.controllers')` or pass\n`--controllers=A,B` on the CLI. The standalone script also accepts\n`--kernel=` (or `MICROSERVICE_KERNEL`) to point at a custom Kernel class.\n\n## Notes \u0026 limits\n\n- The TCP server handles one connection at a time per process — run multiple\n  workers behind a balancer, or swap in an event-loop driver later (the framing\n  is unchanged).\n- Kafka has no native RPC; the reply-topic approach matches NestJS. For pure\n  event streaming, use `emit()` only.\n- The default serializer is JSON. Implement `Serializer` for msgpack/protobuf.\n- Handler exceptions become an error `ResponsePacket`; the client re-throws them\n  as `RpcException`. Events swallow-and-log errors (no caller to notify).\n- **gRPC is client-only.** The `grpc` PHP extension provides no server API and\n  a production-grade PHP gRPC server requires RoadRunner or Swoole, neither of\n  which fits the single-process consumer model here. Implement the server side\n  in any language with a real gRPC server following [proto/microservice.proto](proto/microservice.proto) —\n  PHP services call it through `GrpcClientTransport`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbowphp%2Fmicroservice","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbowphp%2Fmicroservice","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbowphp%2Fmicroservice/lists"}