dsl / my-target-sdk
API bindings for MyTarget
Installs: 7 566
Dependents: 1
Suggesters: 0
Security: 0
Stars: 8
Watchers: 13
Forks: 10
Open Issues: 5
Requires
Requires (Dev)
- doctrine/cache: ^1
- dsl/cache-control: 0.1.0
- guzzlehttp/guzzle: ^6
- phpunit/phpunit: ^4.7
- psr/log: ^1
README
PHP клиент для работы с MyTarget API (v1/v2).
Install it via composer
composer require dsl/my-target-sdk
How to work with it?
$clients = new ClientOperator(...); $client = $clients->create(new AdditionalUserInfo("cl1")); $campaigns = new CampaignOperator(...); $targeting = new CampaignTargeting(); $targeting->setAge(range(20, 30)); $targeting->setSex(Sex::female()); $createCampaign = new CreateCampaign("awesome campaign", new PackageId(83), $targeting); $createCampaign->setStatus(Status::active()); $createdCampaign = $campaigns->forClient($client->getUsername())->create($createCampaign);
Также можно не использовать *Operator
классы, и вместо этого составлять запросы вручную. (об этом ниже)
Bootstrap it in 5 minutes
Для того чтобы пример выше заработал нужно создать граф зависимостей для ClientOperator
и CampaignOperator
.
Зависят оба этих оператора от компонентов Client
и Mapper
.
Для песочницы, инстанциировать клиент вместе с его зависимостями можно так:
namespace sandbox; use MyTarget\Client; use GuzzleHttp\Psr7\Uri; use GuzzleHttp\Client as GuzzleClient; use MyTarget\Transport\GuzzleHttpTransport; use MyTarget\Transport\Middleware\HttpMiddlewareStack; use MyTarget\Transport\Middleware\HttpMiddlewareStackPrototype; use MyTarget\Transport\Middleware\Impl\CallbackMiddleware; use MyTarget\Transport\Middleware\Impl\ResponseValidatingMiddleware; use MyTarget\Token\Token; use Psr\Http\Message\RequestInterface; $baseUri = new Uri('https://target.my.com'); $token = new Token("ACCESS_TOKEN", "bearer", new \DateTime(), ""); // библиотека также в состоянии управлять набором токенов в любом типе хранилища (а также получать новые и рефрешить) $http = new GuzzleHttpTransport(new GuzzleClient()); $httpStack = HttpMiddlewareStackPrototype::newEmpty($http); $httpStack->push(new ResponseValidatingMiddleware()); // подпишем все запросы заранее полученным токеном (также можно использовать более сложный TokenGrantMiddleware, который способен хранить токен в любых хранилищах, обновлять и получать его) $accessToken = "foo bar"; $httpStack->push(new CallbackMiddleware(function (RequestInterface $req, HttpMiddlewareStack $stack, $context = null) use ($accessToken) { $req = $req->withHeader('Authorization', sprintf('Bearer %s', $accessToken)); return $stack->request($req, $context); })); $client = new Client(new RequestFactory($baseUri), $httpStack);
Это создаст простейший клиент который может самостоятельно подписывать все запросы переданным токеном и возвращать ответ в виде массива (либо выбрасывать исключение если что-то пошло не так). Помимо этого есть дополнительные возможности, такие как управление токенами и учёт лимитов API. (об этом в Advanced features) Создать маппер для песочницы гораздо проще:
$autoloader = require_once __DIR__ . '/../vendor/autoload.php'; // когда подключается автолоадер нужно присвоить его переменной (этот код будет в самом начале) AnnotationRegistry::registerLoader([$autoloader, 'loadClass']); // нужно для правильной работы doctrine/annotations $mapper = \MyTarget\simpleMapper($debug = true);
Теперь можно создать ClientOperator
и получить список клиентов:
$clients = new ClientOperator($client, $mapper); var_dump($clients->all());
Advanced features and usage
TODO
How does it work?
Весь проект разделен на несколько компонентов:
- Клиент (Transport) - всё что касается коммуникаций через сеть
- Маппер - нужен для того чтобы отображать ответы API на объекты
- Набор операторов - типизируют все возможные отправляемые и получаемые значения в виде объектов
Клиент использует набор middleware объектов которые имеют доступ к чтению/изменению запросов и ответов API.
Это позволяет легко разбивать различную функциональность, которая как-то связана с обработкой запросов, в разные сущности.
Например есть LimitingMiddleware
, ClientGrantMiddleware
и ResponseValidatingMiddleware
.
Все они схожи в том, что все работают на уровне HTTP-сообщений, но при этом семантически не имеют ничего общего.
Маппер выполняет простую функцию отражения API-ответов на типизированные объекты: $mapper->hydrateNew('Foo', $jsonObject)
вернёт экземпляр Foo
, где поля этого объекта будут заполнены в соответствии с аннотациями вида Field(name="api_field_name", type="string")
на них.
Операторы связывают два упомянутых выше компонента и позволяют работать с API на более высоком уровне. Но если вам не нравится работать с объектами и вас устраивают произвольные массивы данных, то есть возможность работать напрямую с клиентом. Таким образом вы все равно можете получить настроенную OAuth2 аутентификацию, конвертацию ошибочных ответов API в исключения и контроль ограничений на запросы.
HttpMiddleware
Работа с сетью происходит с помощью HttpMiddlewareStack
. Этот стек содержит все обработчики HTTP ответов и запросов, которые "стекуются" друг на друга. Пример обработчика выглядит так:
class MyMiddleware implements HttpMiddleware { public function request(RequestInterface $request, HttpMiddlewareStack $stack, array $context = null) { return $stack->request($request, $context); }
Этот middleware просто вызывает следующий за ним middleware. Данный вызов всегда возвращает объект типа Psr7\ResponseInterface
(либо выбрасывает исключение). Вот пример более полезного middleware, который может логировать весь HTTP-обмен:
class LoggingMiddleware implements HttpMiddleware { public function request(RequestInterface $request, HttpMiddlewareStack $stack, array $context = null) { try { $response = $stack->request($request, $context); log($request, $response); return $response; } catch (RequestException $e) { logError($request, $e); throw $e; } } }
Exceptions hierarchy
Все исключения этой библиотеки подчиняются такой иерархии:
- MyTarget\Exception\MyTargetException - Интерфейс (маркер) всех исключений этой библиотеки (если есть необходимость "не выпускать" никаких исключений от СДК, то нужно ловить этот тип исключения)
- MyTarget\Transport\Exception\TransportException - thrown during request transferring phase
- MyTarget\Transport\Exception\RequestException
- MyTarget\Transport\Exception\ClientErrorException
- MyTarget\Transport\Exception\ConnectException
- MyTarget\Transport\Exception\ServerErrorException
- MyTarget\Transport\Exception\TooManyRedirectsException
- MyTarget\Token\Exception\TokenRequestException
- MyTarget\Token\Exception\TokenLimitReachedException
- MyTarget\Token\Exception\TokenDeletedException
- MyTarget\Limiting\Exception\ThrottleException - thrown before the request if you've reached the rate limit, or after the response is parsed and it contains a 429 code
- MyTarget\Exception\DecodingException - thrown during response decoding phase
Помимо этого они все разделены на два вида: Dsl\MyTarget\Exception\ApiException
и Dsl\MyTarget\Transport\Exception\NetworkException
.
How to contribute
Для того чтобы предложить свои изменения, вы можете сделать форк этого репозитория и создать PR с произвольным сообщением описывающим изменения.