GuzzleHttpでRiot Games APIから戦績を取ってみた

#この記事について
これは[Laravel Advent Calendar 2017](https://qiita.com/advent-calendar/2017/laravel), 9日目の記事です

この記事では[GuzzleHttp](http://docs.guzzlephp.org/en/stable/)を使ってAPIからデータを取ってくる方法について書きます、今回は例として[Riot Games API](https://developer.riotgames.com/)から戦績を取ってみて、文句をタレながらついでに解説をします。

適当な記事なので間違っていたらごめんよ。

#目次
* GuzzleHttpの導入
* Riot Games APIの設定

#GuzzleHttpの導入

```console
$ composer require guzzlehttp/guzzle
```
後は必要なコントローラー等で

```php:RandomRepository.php
namespace App\Repositories;

use GuzzleHttp\Client;
use GuzzleHttp\Psr7\Response;

class CallApiRepository
{
    private $client;

    public function __construct(Client $client)
    {
        $headers = ['X-Riot-Token' => config('services.api_key')];

        $this->client = new Client([
            'base_uri' => config('services.api_url'),
            'http_errors' => false,
            'headers' => $headers,
        ]);
    }

    public function callRiotApi(string $path): Response
    {
        $response = $this->client->get($path);

        return $response;
    }

    public function resolveResponse(Response $response): array
    {
        if ($response->getStatusCode() !== 200) {
            abort($response->getStatusCode());
        }

        $result = json_decode($response->getBody(), true);

        return $result;
    }
}

```
###適当な解説
こんな風にしてやればOK、[ソースコード](https://github.com/guzzle/guzzle/blob/master/src/Client.php)を参考に適当に解説をすると

```php:GuzzleHttp\Client->__construct()
public function __construct(array $config = [])
    {
        if (!isset($config['handler'])) {
            $config['handler'] = HandlerStack::create();
        } elseif (!is_callable($config['handler'])) {
            throw new \InvalidArgumentException('handler must be a callable');
        }
        // Convert the base_uri to a UriInterface
        if (isset($config['base_uri'])) {
            $config['base_uri'] = Psr7\uri_for($config['base_uri']);
        }
        $this->configureDefaults($config);
    }
```
####base_uriの行方
渡した'base_uri'が[Guzzlehttp\Psr7](https://github.com/guzzle/psr7/blob/811b676fbab9c99e359885032e5ebc70e442f5b8/src/functions.php)の54行目に飛んでなんか処理されてるっぽい。

```php:Guzzlehttp\Psr7\functions.php
/**
 * Returns a UriInterface for the given value.
 *
 * This function accepts a string or {@see Psr\Http\Message\UriInterface} and
 * returns a UriInterface for the given value. If the value is already a
 * `UriInterface`, it is returned as-is.
 *
 * @param string|UriInterface $uri
 *
 * @return UriInterface
 * @throws \InvalidArgumentException
 */
function uri_for($uri)
{
    if ($uri instanceof UriInterface) {
        return $uri;
    } elseif (is_string($uri)) {
        return new Uri($uri);
    }
    throw new \InvalidArgumentException('URI must be a string or UriInterface');
}
```

####http_errorsとheadersの行方
'http_errors'はconfigureDefaultsで使われている、因みにコイツがtrueだと400~のレスポンスを帰さなくなる、今回はエラーハンドリングを自前でやりたいからfalseで。一応trycatchとかやればtrueのままでもいい？

'headers'はfor文で回されていて、'User-Agent'が存在するかどうかをチェックしている模様、array_key_existsじゃダメなのか？？

```php:GuzzleHttp\Client->configureDefaults()
    /**
     * Configures the default options for a client.
     *
     * @param array $config
     */
    private function configureDefaults(array $config)
    {
        $defaults = [
            'allow_redirects' => RedirectMiddleware::$defaultSettings,
/**********************************************/
            'http_errors'     => true,
            'decode_content'  => true,
            'verify'          => true,
            'cookies'         => false
        ];
        // Use the standard Linux HTTP_PROXY and HTTPS_PROXY if set.
        // We can only trust the HTTP_PROXY environment variable in a CLI
        // process due to the fact that PHP has no reliable mechanism to
        // get environment variables that start with "HTTP_".
        if (php_sapi_name() == 'cli' && getenv('HTTP_PROXY')) {
            $defaults['proxy']['http'] = getenv('HTTP_PROXY');
        }
        if ($proxy = getenv('HTTPS_PROXY')) {
            $defaults['proxy']['https'] = $proxy;
        }
        if ($noProxy = getenv('NO_PROXY')) {
            $cleanedNoProxy = str_replace(' ', '', $noProxy);
            $defaults['proxy']['no'] = explode(',', $cleanedNoProxy);
        }
        $this->config = $config + $defaults;
        if (!empty($config['cookies']) && $config['cookies'] === true) {
            $this->config['cookies'] = new CookieJar();
        }
        // Add the default user-agent header.
        if (!isset($this->config['headers'])) {
            $this->config['headers'] = ['User-Agent' => default_user_agent()];
/**************************************/
        } else {
            // Add the User-Agent header if one was not already set.
            foreach (array_keys($this->config['headers']) as $name) {
                if (strtolower($name) === 'user-agent') {
                    return;
                }
            }
            $this->config['headers']['User-Agent'] = default_user_agent();
        }
    }
```
####Responseの取り扱い

200じゃなきゃabort、200ならarrayにjson_decodeして返す

```php:RandomRepository->resolveResponse()
public function resolveResponse(Response $response): array
    {
        if ($response->getStatusCode() !== 200) {
            abort($response->getStatusCode());
        }

        $result = json_decode($response->getBody(), true);

        return $result;
```

```php:dd(json_decode($response->getBody(),true));
array:6 [▼
  "id" => 44810338
  "accountId" => 207563369
  "name" => "Tyler1"
  "profileIconId" => 10
  "revisionDate" => 1495787074000
  "summonerLevel" => 30
]
```
#Riot Games APIの設定

クソ時間かかるので元々アカウントがないなら諦めよう！！

[公式](https://developer.riotgames.com/)でRegenerate API KeyをクリックしてAPI Keyを取得、それをURLのパラメーターに入れるか、Headerに入れて送らないと401が返される、そりゃそうだ。

[opgg](http://na.op.gg/)の様な名前を入力するだけで試合の一覧が出る戦績サイトを作るには

* /lol/summoner/v3/summoners/by-name/{summonerName}で名前から情報を取得
 * /lol/league/v3/positions/by-summoner/{summonerId}に引いて来た*summonerId*を突っ込んでランクを取得
* /lol/match/v3/matchlists/by-account/{accountId}/recentに*accountId*を突っ込んで直近20戦のmatchIdを取得
 * /lol/match/v3/matches/{matchId}にforeachでmatchIdを突っ込んで試合の詳細を取得

4回APIを叩けば大体あんな感じの物ができる、アイテム等の画像を取得するには別途[こういう感じで](https://developer.riotgames.com/static-data.html)

```php
$path = 'http://ddragon.leagueoflegends.com/cdn/6.24.1/img/item/' . $itemId . '.png';
```
取ってくればいい

####あとがき

勝敗ぐらいは一覧取ったタイミングで配列に入れておいていいんじゃないか？
RoleとLaneは返して勝敗を返さないのがよくわからん。
true falseじゃなくて'win' 'fail'で保存されてるのもよくわからん。