【令和最新版】開発者フレンドリーなHTTP SDK作るには

公開日:

福岡市博多区福岡ファッションビル・FFBホールで開催された『PHPカンファレンス福岡2023』でライトニングトーク(5分)として発表しました。

Download PDF

スライドテキスト

Page 1

【令和最新版】

開発者フレンドリーな HTTP SDK作るには

Creating Developer-Friendly HTTP SDKs

pixiv Inc.
USAMI Kenta

2022-06-24

PHP Conference Fukuoka

Page 2

お前誰よ

  • うさみけんた (@tadsan) / Zonu.EXE / にゃんだーすわん
  • ピクシブ株式会社 pixiv事業本部 エンジニア
    • 最近はピクシブ百科事典(dic.pixiv.net)を開発しています
  • Emacs Lisper, PHPer
    • Emacs PHP Modeを開発しています (2017年-)
  • プログラミング言語にちょっとこだわりのある素人

Page 3

さて

Page 4

内容を詰め込んでるの でメモとかは無理です
後日詳細なフォロー アップを公開します

Page 5

今回のお題

Page 6

つまり…?

Page 7

そういう話です
🤖

Page 8

そういう話です
🤖

Page 9

テストの話はしますが
主題には
なりませんでした

Page 10

SDKを書く前に おさえておきたい
PHPでのHTTPの
使いかた

Page 11

大昔に別の
アプローチについて
書いたこともあります

Page 12

WEB+DB PRESS Vol.96

(2016年)

Page 13

関数ベースの処理は
イケてないから
Guzzle使おうぜ!
…という内容

Page 14

Zennに再掲しました

(2016年版)

Page 15

今回しない話

(発表時間15分なので)

  • OpenAPI(Swagger)の定義からコードを自動生成するとか
  • 具体的なSDKの実装方法
    • もうちょっと手前のHTTPの話が中心です
    • 後日、私がいままで作ったSDKをいくつか紹介します
  • 具体的なテスト手法について… 間に合いませんでした!
    • スライドじゃなくていい感じにするライブラリをちょこちょこ書いてます

Page 16

超ざっくり

PHP vs HTTP

Page 17

PHPからHTTPリクエスト

  • グローバル関数を使うと超かんたんにHTTPリクエストを発行できる
    • Ole_get_contents($url)
      • 名前に反してPOSTなど任意のメソッドのリクエストを発行できる(!)
    • cURL関数 [curl_init(), curl_exec(), ...]
    • こいつらは事実上の標準関数みたいな感じで外部ライブラリも要らないし
      簡単だけどリクエスト・レスポンスの組み立てがちょっとめんどい

Page 18

そうだ、HTTPクライアントを使おう

  • 実際にはuopzで可能
    「リクエスト関数」から「クライアントオブジェクト」へ

(例: clock-mock)

  • PHPではグローバル関数をモックすることはちょっと大変
  • インスタンスを外部から受け取ることで、HTTP通信が置換可能になる
  • ガ ズ ル シ ン フ ォ ニ ー
    よく知られた実装: Guzzle, Symfony HTTP Client

Page 19

Guzzle

Page 20

つまり…?

Page 21

PSRとは何か

Page 22

PHP-FIGとかいう
有志の団体が勧告して
いる標準仕様

Page 23

Framework
Interop
Group

Page 24

フレームワークを 作ってる人たちの
寄合所帯

Page 25

PSRの誤解

Page 26

ワシのPSRは
20式まであるぞ

一般的にはオートロードや コーディング規約が知られ
ていると思う

(たぶん)

Page 27

PSRではHTTPに 関連する仕様も多く
勧告されている

Page 28

最重要資料

Page 29

PSR-18は
HTTP Clientの インターフェイス

Page 30

PSR-18は
PSR-15と似ているが
よりシンプル

Page 31

PSR-15 vs PSR-18

Page 32

_人人人人人人人人人人人人人人人人人_ > 僕の知ってるHTTPClientと違う <  ̄Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^ ̄

Page 33

僕の知ってる
HTTP Clientって?

Page 34

GuzzleのREADMEに書いてる

Page 35

それに引き換えなんだこのPSR-18

シンプルすぎる

Page 36

だがそれがいい

Page 37

PSR-7/18 vs Guzzle (1)

  • PSRはフレームワークの相互運用できる共通部品となるべく設計された
    • PSR-7/18はHTTPの仕様を(PHPで扱える範囲で)そのまま表現できる
  • Guzzleはエンドユーザーが使いやすいように設計されていて、
    ユーザーはHTTPやPSRの仕様を考えなくても簡単に使えるようになってる
    • リクエスト生成やHTTPヘッダの組み立てなどの実装も含んでいる

Page 38

PSR-7/18 vs Guzzle (2)

  • PSR-7/18は仕様がコンパクトなので気のきいた機能は定義されてない
    • HTTPを理解していないと正しくリクエストを送れないこともありうる
  • Guzzleは充実した便利機能を内包しているので、少ない記述量で
    複数のHTTPリクエストを発行できる
    • なおかつPSR-18のClientInterfaceも実装している
    • Guzzle独自の便利メソッドとPSR-18のシンプルメソッド両方使える

Page 39

PSR-15 vs PSR-18

Page 40

一年前に話した

Page 41

Middleware呼び出しイメージ

Middleware

RequestHandler

ServerRequest

Response

Page 42

Middleware呼び出しイメージ

Middleware

RReeqquueessttHHaannddlleerr

ServerRequest

Response

Page 43

特定の場合に
処理を横取りできると
うれしいことがある

Page 44

例:ユニットテスト

Page 45

HttpClient呼び出しイメージ

外部API

HttpClient

Request

Response

Page 46

外部にリクエストを送らない

外部API

リクエスト送らない

MockHttpClient

Request

Response

Page 47

外部にリクエストが送られないように

  • PSR-18の場合、仕様がとてもシンプルなのでClientInterfaceを実装し
    たシンプルな無名クラスを作ってしまうのが簡単
  • Guzzleの場合、MockHandlerというハンドラを有効化して
    テスト用に任意のレスポンスを返す関数を登録してやることができる
  • 重要: アプリケーション内に不用意に new Guzzle Client()とか書かない

\

  • 普通の方法で処理を横取りできなくなってしまう

Page 48

依存の注入

(Dependency Injection)

  • オブジェクトはメソッド内でその都度生成するのではなく、
    呼び出し側(もしくはさらに上位のモジュール)から入れ込むことで 共通のインターフェイスを持ったものに交換できることを保証する
  • 同一機能を持った別のライブラリに乗り換えることもできるし、
    テスト時に決まった値を返すモックオブジェクトに差し替えることも簡単
  • くわしくは「ちょうぜつソフトウェア設計入門」を読んで!

Page 49

ここまでで
準備ができた

Page 50

Page 51

概ねいままで
言ってきたことをやるな
という話

Page 52

Guzzle便利なのはいいんだけど

  • 世の中、Guzzleを使いたいひとばかりではない
    • 僕はkriswallsmith/Buzzという素朴なPSR-18実装が好きです
  • SDKとしてはpsr/http-clientとpsr/http-factoryにだけ
    依存するのが理想
    • SDKの実装としてはGuzzleの便利機能に頼れないのを不便に感じること
      はあるかもしれない

Page 53

ユーザーの利便性 vs 依存の注入

  • ユーザーがSDKを使いはじめるときに事前準備が多すぎると辟易させる
  • プログラミングがあんまり得意じゃないユーザーにも使ってもらうことを考え
    ると、事前準備は少なければ少ないほどいい
    • 一方で、依存を注入してテストで差し替えたいという
      利用者の邪魔をしてはいけない

Page 54

利用者の邪魔をするパターン

  • SDKの実装の中で new Guzzle Client() って書く

\

  • SDKの実装の中で file_get_contents() とか curl 関数を呼ぶ
    • ただしこれらのパターンはPHP-VCRというテスト用ライブラリを
      活用することで通信をフックして任意のレスポンスに書き換えたりすること
      もできなくはない

Page 55

php-http/discovery

  • php-httpという団体が提供しているライブラリ
    • 動作実績のとれているHTTPライブラリがハードコードされている
  • インストール済みのPSR-HTTPライブラリを検出して自動で生成してくれる
    • これはstaticに状態を持っておりDIパターンではないが、
      DIが使えない環境における強い味方
  • 欠点:ドキュメントが不親切め

Page 56

ユーザーを邪魔しない
使いやすいSDKを
作ろう

Page 57