DEV Community

Sebastien Armand
Sebastien Armand

Posted on

gRPC Advanced Error Handling From Go to PHP

The GO community has standardized on using the status package for sending rich errors in gRPC services back to the client.

This way we can send a status with a BadRequest error, and that error message itself could contain many FieldViolation errors with information about which field had an error and what the error was.

Those errors are fairly easy to retrieve and use from another GO gRPC client, but in my case I wanted a solution to get that information from a PHP client and there was very little information available.

This shows how to do it:

<?php declare(strict_types=1);

use GPBMetadata\Google\Rpc\ErrorDetails;
use Google\Rpc\Status;
use Google\Rpc\BadRequest;

[$response, $status] = $client->SomeRemoteCall($request)->wait();
if ($status->code !== \Grpc\STATUS_OK) {
    ErrorDetails::initOnce(); // Ensures that the protobuf descriptor is registered

    $details = $status->metadata["grpc-status-details-bin"][0] ?? null; // GO errors / status will be under this key
    if (is_null($details)) {
        throw new HttpException($message, $code, (array) $status);
    }
    $s = new Status();
    $s->mergeFromString($details);
    $errors = [];
    foreach ($s->getDetails() as $anyDetails) {
        $deets = $anyDetails->unpack(); // The details are a repeated Any field.
        $deets->discardUnknownFields(); // Because this was a "Any" field, it has unknown fields such as @type
        if ($deets instanceof BadRequest) {
            foreach ($deets->getFieldViolations() as $fv) {
                $errors[$fv->getField()] = [
                    'message' => $fv->getDescription(),
                ];
            }
        } else {
            $jsonDeets = $deets->serializeToJsonString(); // encode / decode the protobuf to json to get an array
            $errors[$deets->getField()] = json_decode($jsonDeets);
        }
    }

    // Formatted error with main error and a list of cause errors:
    // 'errors' [
    //  'field-name' => 'message describing the error'
    // ]
    $error = [
        'message' => $s->getMessage(),
        'errors' => $errors,
    ];
}

Enter fullscreen mode Exit fullscreen mode

The Status, ErrorDetails and BadRequest classes come from the package: google/common-protos so be sure to composer require google/common-protos

Top comments (1)

Collapse
 
aakarim profile image
A A Karim

Thank you so much!