Обертка для работы с JSON RPC 2

Опубликовано 44 просмотра
Обертка для работы с JSON RPC 2

JSON RPC - один из стандартов API, релиз 2 версии которого состоялся еще в 2010 году и был обновлен в 2013. Он довольно легок в освоении и в последнее время я довольно часто сталкивался с сервисами, которые используют его в своей работе.

Поэтому я написал свою обертку для отправки запросов и получения ответов от сервисов, использующих данный протокол. Вся реализация состоит из 2 классов - Client для отправки запроса и Response для обработки ответа.

Отправка запроса

<?php

namespace App\JsonRpc;

/**
 * Class Client
 * @package App\JsonRpc
 */
class Client
{
    const VERSION = '2.0';

    protected $url;

    protected $user;

    protected $password;

    private $method;

    private $params;

    public function __construct(string $url, array $auth = [])
    {
        $this->url = $url;

        if(count($auth) == 2) {
            $this->user = $auth[0];
            $this->password = $auth[1];
        }
    }

    /**
     * @param string $name
     * @param array $arguments
     * @return Response
     * @throws \Exception
     */
    public function __call(string $name, array $arguments = [])
    {
        $this->method = class_exists('Illuminate\Support\Str') ? Illuminate\Support\Str::snake($name) : $name;
        $this->params = count($arguments) == 1 && is_array($arguments[0]) ? $arguments[0] : $arguments;

        return $this->_curl();
    }

    /**
     * @return Response
     * @throws \Exception
     */
    private function _curl()
    {
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $this->url);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_POST, true);
        curl_setopt($curl, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
        curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode([
            'method' => $this->method,
            'params' => $this->params,
            'id' => microtime(),
            'jsonrpc' => self::VERSION
        ]));

        if(!is_null($this->user)) {
            curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
            curl_setopt($curl, CURLOPT_USERPWD, $this->user.':'.$this->password);
        }

        $result = curl_exec($curl);

        curl_close($curl);

        return new Response($result);
    }
}

В момент создания экземпляра класса ожидается 2 аргумента - адрес сервера и массив логин/пароль пользователя если требуется авторизация. При обращении к любому из методов API стоит вызывать аналогичный метод класса, указывая параметры в качестве аргументов.

$client = new \App\JsonRpc\Client('https://site.com', ['login', 'password']);
$response = $client->foo_bar('Hello, world!');

Для более красивого вызова в случае, если существует функция snake_case (=== подключен Laravel) название метода можно заменить на fooBar, оно будет преобразовано в foo_bar.

Если используются именованные параметры, указывайте их первым параметром в виде массива.

$client = new \App\JsonRpc\Client('https://site.com', ['login', 'password']);

$response = $client->colorOfFruit([
    'apple' => 'green',
    'banana' => 'yellow'
]);

Работа с ответом

<?php

namespace App\JsonRpc;

class Response
{
    protected $response;

    protected $success;

    public function __construct($response)
    {
        $this->response = json_decode($response, false, 512, JSON_THROW_ON_ERROR);
        $this->success = !isset($this->response->error);
    }

    /**
     * @return bool
     */
    public function isSuccess()
    {
        return $this->success;
    }

    /**
     * @return mixed
     */
    public function getResult()
    {
        return $this->response->result;
    }

    /**
     * @return integer
     */
    public function getErrorCode()
    {
        return $this->response->error->code;
    }

    /**
     * @return string
     */
    public function getErrorMessage()
    {
        return $this->response->error->message;
    }
}

Экземпляр данного класса возвращает каждый метод класса Client. Он отвечает за работу с ответом удаленного сервера.

  • isSuccess() - возвращает true если нет ошибок, иначе false
  • getResult() - возвращает ответ сервера
  • getErrorCode() - возвращает код ошибки если isSuccess() = false
  • getErrorMessage() - возвращает описание ошибки если isSuccess() = false

Таким образом примерно идеальный код выглядит так:

$client = new \App\JsonRpc\Client('https://site.com');
$response = $client->foo_bar('baz');

if($response->isSuccess()) {
    var_dump($response->getResult());
}
else {
    echo $response->getErrorCode().': '.$response->getErrorMessage();
}