Как работать с чужим API на примере Телеграмма

mendel
На сайте с 06.03.2008
Offline
183
932

Работа с внешними API различных сервисов - довольно частая ситуация.

И задача довольно простая, когда знаешь с какой стороны подойти.

Но когда подходишь к ним впервые, то бывает страшно и непонятно.

Большинство разработчиков пользуются какими-то библиотеками. Чужими или своими.

Но библиотеки еще надо написать, или изучить как они работают.

Но на самом деле всё просто.

Давайте напишем такую библиотеку на примере Телеграма.

Основные ограничения будут такие:

у нас должна быть библиотека CURL, поскольку без нее сложно, и хостингов без курл мало.

у нас должен быть пхп5.4+. На самом деле код скорее всего будет работать вплоть до 5.0, но мне не нравится писать array(), да и даже 5.4 это уже устаревшая ветка.

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

Код пишем максимально DRY, но без фанатизма. Это учебный пример который может работать в более широком поле, но мы не будем прорабатывать балансировку и валидацию проксей, поддержку cookie и т.п.

Итак начнем.

Первое что нам нужно уметь, это делать запросы к другим сайтам.

В принципе нам нужен только пост-запрос.

Сделаем так-же гет-запрос, и сохранение статусов ошибок.

Получим простейший класс:


/**
* Минимальный класс для запроса удаленных АПИ
* @author Mendel
*/
class MinimalBot
{
/**
* @var int максимальное время ожидания до таймаута в секундах
*/
protected $timeOut = 5;

/**
* Статус последнего запроса (код ошибки)
* @see https://curl.haxx.se/libcurl/c/libcurl-errors.html
* @var int
*/
public $lastErrorCode = 0;

/**
* @var string Последняя ошибка, текстом
*/
public $lastErrorText = '';

/**
* Инитим CURL основными настройками
* При необходимости расширяем :)
* @return type
*/
protected function prerareCurl() {
$curl = curl_init(); // initialize curl handle
curl_setopt($curl, CURLOPT_FAILONERROR, 1); // Fail on errors
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); // return into a variable
curl_setopt($curl, CURLOPT_TIMEOUT, $this->timeOut); // times out after 15s
return $curl;
}

/**
* Выполним наш запрос и вернем результат
* Сохраним статус последней ошибки
* @param resource $curl
* @return string
*/
protected function execCurl($curl) {
$result = curl_exec($curl);
if($result === FALSE) {
$this->lastErrorCode = curl_errno($curl);
$this->lastErrorText = curl_error($curl);
} else {
$this->lastErrorCode = 0;
$this->lastErrorText = '';
}
curl_close($curl);
return $result;
}

/**
* Выполним запрос по ссылке без параметров
* @param string $url адрес запроса
* @return string
*/
public function get($url) {
$ch = $this->prerareCurl();
curl_setopt($ch, CURLOPT_URL, $url); // set url to post to
return $this->execCurl($ch);
}

/**
* Выполним POST-запрос
* @param string $url адрес запроса
* @param array $data массив параметров
* @return string
*/
public function post($url, $data = []) {
$ch = $this->prerareCurl();
curl_setopt($ch, CURLOPT_URL, $url); // set url to post to
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
return $this->execCurl($ch);
}

Почему мы вынесли отдельно prerareCurl() и execCurl($curl)? Две причины - DRY, ведь иначе мы бы их повторяли и в гет, и в пост, и... DRY, поскольку так проше расширять, например мы можем захотеть работать через прокси, или указывать ЮзерАгент, или у нас может возникнуть конфликт с самоподписанными сертификатами сервера, и мы захотим отключить проверку....

В целом запросы мы делать умеем. Теперь напишем класс для работы собственно с Телегой.


class TelegramApi
{
/**
* Имя класса для выполнения запросов
* @var string
*/
protected $botClass = 'MinimalBot';
/**
* Ключ апи для нашего бота
* @var string
*/
protected $apiKey;

/**
* Авторизуемся, т.е. по факту сообщаем наш апиКей
* @param string $key
*/
public function login($key) {
$this->apiKey = $key;
}

/**
* Создадим соединение
* @return mixed
*/
protected function bot() {
$class = $this->botClass;
return new $class();
}

/**
* Выполним команду
* @param string $command команда
* @param array $data массив параметров
* @return array
* @throws \Exception
*/
public function command($command,$data=[]) {
if(is_null($this->apiKey)) throw new \Exception('Bad telegramApiKey');
$url = 'https://api.telegram.org/'.$this->apiKey.'/'.$command;
$result = $this->bot()->post($url, $data);
return json_decode($result,TRUE);
}
}

bot() возвращает нам объект для доступа по запросам. Вынесен в отдельную функцию чтобы просто было переопределить если что.

Теперь мы можем выполнять команды нашего апи, например вот так:


$telegram = new TelegramApi();
$telegram->login('наш ключ авторизации бота');
$result = $telegram->command('getUpdates');
var_dump($result);
$result = $telegram->command('sendMessage',['chat_id'=>273959847,'text'=>'Текст сообщения']);
var_dump($result);

Дальше уже нужно работать с ошибками, статусами, отрабатывать статус ошибки от соединения и т.п., но и так многабукафф

Шутку любишь над Фомой, так люби и над собой. (с) народ. Бесплатные списки читабельных(!) свободных доменов (http://burzhu.net/showthread.php?t=2976) (5L.com) Сайты, All inclusive. 5* (/ru/forum/962215)

Авторизуйтесь или зарегистрируйтесь, чтобы оставить комментарий