【入門編】Hackの『Shape』型を用いたAPIレスポンスの型安全なマッピング戦略 – Hack言語 コア・静的型システムとHHVMのアーキテクチャ解析バイブル

こんにちは!HHVMとHack言語の深淵へようこそ。チーフアーキテクトの私です。

他の言語、例えばJavaScriptやPHPの連想配列(Array)のノリで外部APIのJSONをいじっていて、「あれ、このキーの名前なんだっけ?」「あれ、この値が `null` になってクラッシュした…」なんて悲劇を繰り返していませんか?

静的型付き言語であるHackの真骨頂は、「実行時エラーをコンパイル時(型チェック時)の絶望へと事前に変換する」ことにあります。そして、外部からやってくる構造化データを完全に手なずけるための最強の武器が `shape`(シェイプ)型 です。

今回は、この `shape` を使って、外部APIレスポンスを美しく、かつ鉄壁の型安全性でマッピングする戦略を一緒にマスターしていきましょう。ここをクリアすれば、あなたの書くHackコードの信頼性は一段と跳ね上がりますよ!

—

1. そもそも `shape` 型ってなに?

PHPの連想配列やTypeScriptのオブジェクト型をイメージしてください。
「キー(key)が決まっていて、それぞれのキーに特定の型(type)が紐づいているデータの集まり」を表現したいとき、Hackでは `shape` を使います。

普通の `array` は、「何が入っているか分からない、無法地帯のオモチャ箱」です。一方、`shape` は「仕切りが細かく決まっていて、指定されたパーツしか入らない精密なパーツケース」だと思ってください。

基本の書き方を見てみましょう

<<__Strict>>
namespace HackMasterclass;

// ユーザー情報を表すshape型を定義します
type TUser = shape(
‘id’ => int,
‘name’ => string,
‘email’ => ?string, // ?がついているので、nullを許容します
);

この `TUser` という型を定義しておくと、型チェッカー(`hh_client`)が「おい、`name` に int型を入れようとしてるぞ!」とか、「`email` キーを打ち間違えてるよ!」と、コードを実行する前に教えてくれます。最高ですよね。

—

2. 【現場の現実】外部APIのJSONは「信用ならない」

さて、ここからが本題です。外部のREST APIから飛んでくるJSONデータは、残念ながら信用できません。ネットワークの向こうからやってくるデータは、型チェッカーの目の届かない「ただの文字列(JSON)」だからです。

これをHackの型安全な世界に引き込むためには、以下の2ステップを踏む必要があります。

1. トランスレーション(境界でのバリデーション): 生のデータ(`array` や `mixed`)が本当に期待した `shape` の構造をしているかをチェックする。
2. ドメインモデルへのマッピング: チェックが通った安全なデータを、アプリケーション内で扱う型付きのオブジェクトや構造体に昇華させる。

悪い例:ただのキャストや配列アクセス

// ❌ 絶対にやってはいけないアンチパターン
function handle_api_response(array $raw_data): void {
// キーが存在するか分からないままアクセスすると、キー欠損時にバグる
$name = $raw_data[‘name’];
}

良い例:`shape` とガーード関数を使った堅牢なマッピング

では、実際に外部APIから受け取ったユーザーデータのJSONを、型安全に処理するコードを見てみましょう。

<<__Strict>>
namespace HackMasterclass;

// 1. APIレスポンスの構造を定義するShape
type TApiResponse = shape(
‘status’ => string,
‘data’ => shape(
‘id’ => int,
‘username’ => string,
),
);

// 2. 境界防御(バリデーション)を行う関数
function parse_api_response(mixed $json_input): ?TApiResponse {
// 実際の現場ではここで json_decode() や、
// キーの存在確認、型の厳密なチェック(is_int など)を行います。
// ここでは概念を分かりやすくするために簡略化しています。

if (!\is_array($json_input)) {
return null;
}

// 型チェッカーと実行時の安全性を担保しつつキャスト
// ※HHVMの強力なTypehint機能やShapes::idxを活用することもあります

return $json_input as TApiResponse;
}

function process_user(mixed $raw_json): void {
$response = parse_api_response($raw_json);

if ($response === null) {
\Asio\succeed(\print(“無効なAPIレスポンスです。\n”));
return;
}

// ✨ ここから先は完全に型安全!
// $response[‘data’][‘username’] が string であることが型チェッカーに保証されています。
$username = $response[‘data’][‘username’];

\print(“ようこそ、{$username} さん!\n”);
}

—

3. 陥りやすい文法エラーと罠

Hackの `shape` を使い始めの頃、誰もが一度はハマるポイントがあります。先輩からのアドバイスとして頭の片隅に入れておいてください。

罠1: オプショナルキー(`?`)の扱いを誤る

shapeの定義で `’age’ => ?int` とした場合、「キー自体が存在しない」 のか、「キーは存在するが値が `null` なのか」 は、厳密には区別されます。

  • キー自体を省略可能にしたい場合は、`<<__Optional>>` アノテーションを使うか、`Shapes::idx()` 関数を使って安全に値を取り出す必要があります。

type TProfile = shape(
‘name’ => string,
// キーが存在しないかもしれない場合は Shapes::idx を使うのが定石
);

function get_age(TProfile $profile): int {
// ‘age’ キーがないかもしれない場合は直接 $profile[‘age’] と書くと型エラーになります
return Shapes::idx($profile, ‘age’, 0); // キーがなければデフォルト値 0 を返す
}

罠2: 動的なキーの追加

`shape` は「構造が固定されたデータ」のためのものです。「キーが何になるか実行時まで分からない」という場合は、`shape` ではなく、通常の辞書型である `dict` や `Map` を使用してください。用途を間違えると型チェッカーに怒られてしまいます。

—

まとめ:型安全な境界線を作ろう

今回は、Hackの `shape` 型を用いたAPIレスポンスの型安全なマッピング戦略について解説しました。

  • 外部からの入力(JSON等)は、すべて `mixed` や信用ならないデータとして扱う。
  • 境界線(Boundary)で `shape` を使ったバリデーションを行い、安全な型へと変換する。
  • 一度 `shape` に落とし込めば、その先の世界では型チェッカーが完璧にあなたを守ってくれる。

この設計思想を取り入れるだけで、プロダクション環境での「Undefined index」や「Call to a member function… on null」といったおなじみのエラーを根絶することができます。

ここをクリアできれば、あなたも立派なHack使いの仲間入りです。明日からのコーディングで、ぜひこの `shape` マッピング戦略を試してみてくださいね!それでは、良きHackライフを!

タイトルとURLをコピーしました