{"id":19312105,"url":"https://github.com/bigcommerce/grphp","last_synced_at":"2025-04-05T13:07:45.835Z","repository":{"id":37686644,"uuid":"91984524","full_name":"bigcommerce/grphp","owner":"bigcommerce","description":"PHP gRPC Framework","archived":false,"fork":false,"pushed_at":"2025-03-20T07:12:52.000Z","size":284,"stargazers_count":25,"open_issues_count":0,"forks_count":7,"subscribers_count":74,"default_branch":"master","last_synced_at":"2025-03-29T12:08:07.742Z","etag":null,"topics":["grpc","php","protobuf"],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bigcommerce.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","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}},"created_at":"2017-05-21T20:12:58.000Z","updated_at":"2024-12-29T21:35:05.000Z","dependencies_parsed_at":"2024-06-20T23:26:50.399Z","dependency_job_id":"350c5d0e-c50e-4284-a0c7-4bbc054f4ca4","html_url":"https://github.com/bigcommerce/grphp","commit_stats":{"total_commits":120,"total_committers":13,"mean_commits":9.23076923076923,"dds":0.5166666666666666,"last_synced_commit":"f7f8e6af2020849c8096b04e9f50e9dcba206401"},"previous_names":[],"tags_count":45,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bigcommerce%2Fgrphp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bigcommerce%2Fgrphp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bigcommerce%2Fgrphp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bigcommerce%2Fgrphp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bigcommerce","download_url":"https://codeload.github.com/bigcommerce/grphp/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247339158,"owners_count":20923014,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["grpc","php","protobuf"],"created_at":"2024-11-10T00:32:52.714Z","updated_at":"2025-04-05T13:07:45.814Z","avatar_url":"https://github.com/bigcommerce.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# grphp - gRPC PHP Framework\n\n[![Build Status](https://travis-ci.com/bigcommerce/grphp.svg?token=D3Cc4LCF9BgpUx4dpPpv\u0026branch=master)](https://travis-ci.com/bigcommerce/grphp)\n\ngrphp is a PHP framework that wraps the [gRPC PHP library](https://github.com/grpc/grpc/tree/master/src/php) to\nprovide a more streamlined integration into PHP applications.\n\nIt provides an abstracted client for gRPC services, along with other tools to help get gRPC services in PHP\nup fast and efficiently at scale. Some of its features include:\n\n* Robust client error handling and metadata transport abilities\n* Server authentication strategy support, with basic auth with multiple key support built in\n* Error data serialization in output metadata to allow fine-grained error handling in the transport while still \npreserving gRPC BadStatus codes\n* Client execution timings in responses\n* H2Proxy via nghttpx support that allows gRPC-based communication without the gRPC C libraries\n\ngrphp currently has active support for gRPC 1.9.0, and requires PHP 7.4+ to run.\n\n## Installation\n\n```bash\ncomposer require bigcommerce/grphp\n```\n\nYou'll need to make sure you fit \n[the requirements for the grpc/grpc PHP library](https://github.com/grpc/grpc/tree/master/src/php#environment),\nwhich does involve installing the gRPC PHP extension (unless you are using the H2Proxy strategy).\n\n## Client\n\n```php\n$config = new Grphp\\Client\\Config([\n    'hostname' =\u003e 'IP_OF_SERVER:PORT',\n]);\n$client = new Grphp\\Client(Things\\ThingsClient::class, $config);\n\n$request = new Things\\GetThingReq();\n$request-\u003esetId(1234);\n\n$resp = $client-\u003ecall($request, 'GetThing');\n$thing = $resp-\u003egetResponse(); // Things\\Thing\necho $thing-\u003eid; // 1234\necho $resp-\u003egetStatusCode(); // 0 (these are gRPC status codes)\necho $resp-\u003egetStatusDetails(); // OK\n``` \n\n## Strategy\n\ngrphp comes with the ability to utilize injectable strategies for how it communicates outward. Currently, there are two\nstrategies that come packaged with grphp:\n\n* *Grpc* - This strategy class will utilize the core gRPC PHP libraries to communicate outbound to services\n* *H2Proxy* - This strategy is set to call out to an [nghttpx](https://nghttp2.org/) proxy to communicate via HTTP/1.1,\n  which is then upgraded to an HTTP/2 connection, and transformed into a gRPC request.\n  \n### H2Proxy Strategy\n\nThe H2Proxy strategy pairs with a [nghttpx](https://nghttp2.org/) service and sends HTTP/1.1 requests that are upgraded\nto HTTP/2 and gRPC. It does this by sending the binary encoded protobuf across the wire with the `Upgrade: h2c` and \n`Connection: Upgrade` headers, which nghttpx uses to upgrade the connection into a proper gRPC request.\n\nThis is useful if you do not want to utilize the gRPC PHP C extension but still gain the benefit of the protobuf\ncontracts. If you do not have the gRPC PHP C extension installed, grphp will automatically switch you to the H2Proxy\nstrategy.\n\nYou can use and configure the proxy strategy like so, assuming we have a nghttpx service running at the address 0.0.0.0 \non port 3000:\n\n```php\n$proxyConfig = new Grphp\\Client\\Strategy\\H2Proxy\\Config('http://0.0.0.0:3000', 15);\n$proxyStrategyFactory = new Grphp\\Client\\Strategy\\H2Proxy\\StrategyFactory($proxyConfig);\n$config = new Grphp\\Client\\Config([\n    'strategy' =\u003e $proxyStrategyFactory-\u003ebuild(),\n]);\n```\n\nThis sets the proxy client to also utilize a timeout of 15 seconds. This setup is configurable per-client, so you can\nadjust these settings - and the strategy - on a service-by-service basis.\n\n### Envoy Strategy\n\nThe Envoy strategy uses [Envoy](https://www.envoyproxy.io/) as an HTTP/1.1 bridge for gRPC egress traffic. It \nautomatically serializes messages and buffers requests to handle the response trailers. More can be read about the\n[Envoy bridge here](https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/grpc_http1_bridge_filter).\n\n```php\n// Connect to Envoy at 127.0.0.1:19000\n$envoyConfig = new Grphp\\Client\\Strategy\\Envoy\\Config('127.0.0.1', 19000, 2);\n$envoyStrategyFactory = new Grphp\\Client\\Strategy\\Envoy\\StrategyFactory($envoyConfig);\n$config = new Grphp\\Client\\Config([\n    'strategy' =\u003e $envoyStrategyFactory-\u003ebuild(),\n]);\n```\n\nThis sets the proxy client to also utilize a timeout of 2 seconds. This setup is configurable per-client, so you can\nadjust these settings - and the strategy - on a service-by-service basis.\n\n## Authentication\n\nAuthentication is done via adapters, which are specified in the config. You can either pass in:\n\n* The string \"basic\" for basic HTTP auth\n* A string class name for an existing class\n* An instantiated object that extends `Grphp\\Authentication\\Base`\n\n### Basic Authentication\n\ngrphp supports basic auth for requests that is sent through the metadata of the request. \n\n```php\n$config = new Grphp\\Client\\Config([\n    'hostname' =\u003e 'IP_OF_SERVER:PORT',\n    'authentication' =\u003e 'basic',\n    'authentication_options' =\u003e [\n        'username' =\u003e 'foo',\n        'password' =\u003e 'bar', // optional\n    ]\n]);\n```\n\n### Custom Client Interceptors\n\ngrphp comes with a base Client Interceptor class that can be extended to provide your own custom interceptors. \nThis is an example interceptor that adds a \"X-Foo\" header with a customizable value to all metadata:\n\n```php\n\u003c?php\nuse Grphp\\Client\\Response;\nuse Grphp\\Client\\Interceptors\\Base as BaseInterceptor;\n\nclass FooHeader extends BaseInterceptor\n{\n    /**\n     * @param callable $callback\n     * @return Response\n     */\n    public function call(callable $callback)\n    {\n        // set outgoing metadata\n        $this-\u003emetadata['stuff'] = ['my_thing'];\n        // make the outbound call\n        $response = $callback();  \n        // adjust incoming metadata        \n        $response-\u003esetMetadata([\n            'X-Foo' =\u003e $this-\u003eoptions['foo_value'],\n        ]);\n        return $response;\n    }\n}\n```\n\nYou'll note that you have to make sure to execute the callback that is called.\n\nThen you add it as normal:\n\n```php\n$i = new FooHeader(['foo_value' =\u003e 'bar']);\n$client-\u003eaddInterceptor($i);\n```\n\nInterceptors run in the order that they are added, wrapping each as they go.\n\n## Retry Interceptor\n\nRetries can be enabled for given gRPC error status codes with the `Retry` interceptor. \n```php\nuse Grphp\\Client\\Interceptors\\Retry;\n\n$client-\u003eaddInterceptor(new Retry(['max_retries' =\u003e 3]));\n```\n\nThe retry behaviour can be customized by passing in an array of options to the constructor. The following options are available:\n\n| Option               | Default                                                                                     | Description                                                    |\n|----------------------|---------------------------------------------------------------------------------------------|----------------------------------------------------------------|\n| `max_retries`        | `3`                                                                                         | The maximum number of retries to attempt.                      |\n| `retry_on_statuses`  | `[Grphp\\Client\\Error::CODE_UNAVAILABLE]`                                                    | An array of gRPC error status codes that should be retried on. |\n| `delay_milliseconds` | `200`                                                                                       | The initial delay in milliseconds before a retry.              |\n| `backoff_func`       | `function (int $attempt, int $delayMilliseconds) { /* exponential backoff with jitter */ }` | A callback defining the backoff behaviour.                     |\n\n\n## Error Handling\n\ngRPC prefers handling errors through status (BadStatus) codes; however, these do not return much information as to \nfield specific errors, application codes, or debug information. grphp provides a way to read data from the response \nmetadata, which is stored in the `error-internal-bin` key (configurable through the `error_metadata_key` configuration \noption).\n\nAssuming we have a service that has a method that appends that data, you can access it like so:\n\n```php\ntry {\n    $resp = $client-\u003ecall($request, 'GetErroringMethod');\n    \n} catch (\\Grphp\\Client\\Error $e) {\n    $trailer = $e-\u003egetTrailer();\n    var_dump($trailer); // ['message' =\u003e 'Foo']\n}\n```\n\nBy default the deserializer for the data is JSON; it's fairly simple to create your own, such as one that has the error \nheader serialized as a binary protobuf. From there, you can set it simply:\n\n```php\nclass MyProtoSerializer extends Grphp\\Serializers\\Errors\\Base\n{\n    public function deserialize($trailer)\n    {\n        $header = new \\My\\Proto\\ErrorHeader();\n        $header-\u003emergeFromString($trailer);\n        return $header;\n    }\n}\n\n$config = new Grphp\\Client\\Config([\n    'hostname' =\u003e 'IP_OF_SERVER:PORT',\n    'error_serializer' =\u003e new MyProtoSerializer(),\n]);\n```\n\nThe serializer can be passed as a string name of the class or the instance of the class. If you pass the string name,\nyou can pass in an associative array of `error_serializer_options` to the config to provide options for your serializer.\n\n## Roadmap\n\n* Add TLS configuration support\n* Experimental gRPC server support via sidecar proxy through FastCGI\n\n## License\n\nCopyright (c) 2017-present, BigCommerce Pty. Ltd. All rights reserved \n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated \ndocumentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the \nrights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit \npersons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the \nSoftware.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE \nWARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR \nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR \nOTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbigcommerce%2Fgrphp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbigcommerce%2Fgrphp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbigcommerce%2Fgrphp/lists"}