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

Опубликовано 0 комментариев 1530 просмотров
Обертка для работы с 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 = function_exists('snake_case') ? snake_case($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)
    {
        $response = json_decode($response, false); // TODO add JSON_THROW_ON_ERROR when php 7.3 released (https://gtxtymt.xyz/blog/php-73-whats-new-release-date#vozmozhnost-vyzvat-isklyuchenie-pri-rabote-s-json-encode-i-json-decode)

        if(!$response instanceof \stdClass) {
            throw new \Exception('Undefined response data.');
        }

        $this->response = $response;
        $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();
}

В ответ на сообщение

Доступна разметка Markdown. А еще вы можете использовать крутой пак эмоций.

Нажимая на кнопку «Отправить» вы даете свое согласие на обработку персональных данных в соответствии с законом №152-ФЗ «О персональных данных» от 27.07.2006 и принимаете условия Политики конфеденциальности.