timostamm/symfony-twirp-handler
帮助在 Symfony 应用中实现 Twirp
v0.0.5
2022-12-12 08:55 UTC
Requires
- php: >=7.1
- google/protobuf: ^3.10
- psr/container: ^1.0
- symfony/event-dispatcher: >=4
- symfony/http-foundation: >=4.3
- symfony/http-kernel: >=4
- symfony/property-info: >=4
Requires (Dev)
- phpunit/phpunit: ^9.5
Suggests
- ext-bcmath: Need to support JSON deserialization
- psr/container: To resolve service implementation from container
- psr/log: To handle requests
- symfony/http-foundation: To handle requests
README
帮助在 Symfony 应用中实现 Twirp。
最简单的方法
假设你在 proto 文件中定义了此服务
syntax = "proto3"; service SearchService { rpc Search (SearchRequest) returns (SearchResponse); }
首先使用 protoc 生成 PHP 代码,例如
protoc --proto_path protos/ --php_out out-php protos/example-service.proto
然后为对应的 Twirp 路由创建控制器
// SearchServiceController.php /** * @Route("/twirp/SearchService") */ class SearchServiceController { use TwirpControllerTrait; /** * @Route("/MakeHat") */ public function makeHat(Request $request): Response { /** @var SearchRequest $input */ $input = $this->readTwirp($request, SearchRequest::class); // ... $output = new SearchResponse(); // ... return $this->writeTwirp($request, $output); } }
Twirp 路由 URL 构造如下:twirp/{proto 包名}.{proto 服务名}/{proto 方法名}
。
readTwirp()
和 writeTwirp()
将为您处理内容协商。
正确处理错误
Twirp 有自己的错误格式。要自动转换异常,可以使用 TwirpErrorSubscriber
。
// services.yaml SymfonyTwirp\TwirpErrorSubscriber: arguments: $requestTagAttribute: "_request_id" $debug: '%kernel.debug%' $prefix: "twirp"
如果您已设置此订阅者,还可以抛出您自己的 TwirpError
(完全控制 twirp 错误代码和元数据)。有关 TwirpErrorSubscriber
参数的文档,请查看 PHPdoc。
高级用法
为每个 RPC 编写 symfony 路由既繁琐又容易出错。
启用 php_generic_services
为每个服务生成 PHP 接口
// example-service.proto syntax = "proto3"; option php_generic_services = true; service SearchService { rpc Search (SearchRequest) returns (SearchResponse); }
从此文件开始,protoc 生成通用服务接口 SearchServiceInterface.php
。创建一个新的类 SearchService
并实现该接口
// SearchService.php class SearchService implements SearchServiceInterface { public function search(SearchRequest $request) { $response = new SearchResponse(); $response->setHits(['a', 'b', 'c']); return $response; } }
要使用 Twirp 提供此服务,您可以使用 TwirpHandler
。您只需要为一个或多个服务提供一个路由。处理程序负责路由、内容协商、解析和序列化,并自动调用您服务上的正确方法。
创建一个匹配所有 twirp/ 请求的路由,并如下使用 TwirpHandler
// TwirpController.php /** * @Route( path="twirp/{serviceName}/{methodName}" ) */ public function execute(RequestInterface $request, string $serviceName, string $methodName): Response { $resolver = new ServiceResolver(); $resolver->registerInstance( SearchServiceInterface::class, // the interface generated by protoc new SearchService() // your implementation of the interface ); // alternatively, you can register a factory // $resolver->registerFactory(SearchServiceInterface::class, function() { // return new SearchService(); // }); // .. or a PSR container with $resolver->registerContainer() $handler = new TwirpHandler($resolver); return $handler->handle($serviceName, $methodName, $request); }