FileMaker Data API を使う 2025 年版 vol.3 から続きます。
サンプルデータの作成は FileMaker Data API を使う 2025 年版 vol.1 を参照してください。
利用環境
以下の環境を前提に説明しています。
- Claris FileMaker Pro 21.1.1.41 macOS
- Claris FileMaker Server 21.1.1.40 Ubuntu 22(AMD)
- サーバ: Ubuntu 22.04.5 LTS
- SSL 証明書
- リクエストする側のサーバ(任意)
開発段階では、以下を使用した方が楽でしょう。
- Postman Version 11.30.0
今回のシナリオ
FileMaker Data API のレコード操作には、いくつかのリクエストがあります。また、一つのリクエストでも、いくつかのパターンがあります。
今回は、その中で、「records - Get Records」を取り上げますが、これにもいくつかのパターンがありますが、以下のようなシナリオを考えてみました。
- ログイン
- (何らかの処理があり、リンクでページ遷移した想定)
- セッションの検証
- レコード取得
- (何らかの処理)
- ログアウト
「何らかの Web ページ/アプリケーション にログインし、トップページから、レコード取得ページに遷移して、フィルタ操作やダウンロード等の操作をユーザが行い、ログアウトした」というようなシナリオで進めたいと思います。
事前準備
FileMaker Data API でリクエストするレイアウトはリクエストごとに必要なフィールドを並べたものを用意しましょう。
FileMaker Pro/Go で使用中のレイアウトを使用すると、レスポンスに不要なデータも含まれることになりデータ転送量の無駄になります。また、ポータルが含まれたレイアウトは、レスポンスが複雑になります。
「レイアウトは必要最小限のフィールドのみを配置する」
これを鉄則にしてください。レイアウトを見せるわけではないので、何の装飾もないただ、雑にフィールドを配置したものでまったく問題ありません。
取得するデータの想定
作成したデータは、1,375 件の STATCAST の PLAYER BATTING の Leaderboard のデータです。42 フィールドありますが、「player_batting」テーブルオカレンスを元にして、以下のフィールドに限定して、レイアウトを作成します。
(テーブルオカレンスは、元のテーブルオカレンスを複製し、用途ごとに作成することを推奨しますが、ここではそのまま使用しています。)
- last_name_ first_name (選手の姓名)
- player_id (プレーヤーID)
- year (シーズン)
- ab (打数)
- hit (安打)
- single (単打)
- double (二塁打)
- triple (三塁打)
- home_run (本塁打)
- on_base_percent (出塁率)
レイアウト名は「player_batting_basic」とします。
Login 〜 Log out のテンプレート
ログインとログアウトはリクエスト毎に行う処理なので、クラスか関数にしておくのがいいでしょう。ここでは、簡単にクラスにして、以後、利用していくことにします。
filemaker-data-api.php
<?php
class FileMaker_Data_API
{
public $host, $version, $database, $username, $password, $layout;
public $bearer_session_token;
function __construct (string $host, string $version)
{
$this->host = $host;
$this->version = $version;
}
/**
* リクエスト
**/
// ログイン
public function login (string $database, string $username, string $password): string
{
$this->database = $database;
$this->username = $username;
$this->password = $password;
$auth_value = $username . ':' . $password;
$authorization = 'Authorization: Basic ' . base64_encode($auth_value);
$content_type = 'Content-Type: application/json';
$curlopt_httpheader = array($authorization, $content_type);
$endpoint = "https://{$this->host}/fmi/data/{$this->version}/databases/{$database}/sessions";
return self::executeCurl($endpoint, 'POST', $curlopt_httpheader);
}
// ログアウト
public function logOut(string $database, string $bearer_session_token): string
{
$endpoint = "https://{$this->host}/fmi/data/{$this->version}/databases/{$database}/sessions/{$bearer_session_token}";
return self::executeCurl($endpoint, 'DELETE');
}
/**
* ユーティリティ
**/
// レスポンスコードの取得
public function getMessagesCode (string $response): string
{
$response_array = self::json2array($response);
return $response_array['messages'][0]['code'];
}
// Bearer Session Token 取得
public function getBearerSessionToken (string $response): string
{
$response_array = self::json2array($response);
$this->bearer_session_token = $response_array['response']['token'];
return $this->bearer_session_token;
}
// JSON を 配列へ変換
public function json2array (string $json): array
{
$json = mb_convert_encoding($json, 'UTF8', 'ASCII,JIS,UTF-8,EUC-JP,SJIS-WIN');
return json_decode($json, true);
}
// cURL 実行
static function executeCurl(string $curlopt_url, string $curlopt_customrequest, array $curlopt_httpheader = []): string
{
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => $curlopt_url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => $curlopt_customrequest,
CURLOPT_POSTFIELDS => "{}",
CURLOPT_HTTPHEADER => $curlopt_httpheader,
));
$response = curl_exec($curl);
curl_close($curl);
return $response;
}
}
やや冗長ですが、処理の流れを分かりやすく書いてみました。これを読み込んで、ログインからログアウトまでのテンプレートを書いてみます。
login-log_out.php
<?php
require_once(__DIR__ . '/filemaker-data-api.php');
$host = '(FileMaker Server のドメイン名)';
$version = 'vLatest';
$database = '(FileMaker ソリューション名)';
$username = '(FileMaker ユーザ名)';
$password = '(FileMaker パスワード)';
$layout = 'player_batting_basic';
$bearer_session_token = null;
$fmda = new FileMaker_Data_API($host, $version);
// ログイン
$response = $fmda->login($database, $username, $password);
// ログイン成功?
if ($fmda->getMessagesCode($response) === '0') {
// ログイン成功なら、Bearer Session Token を取得する
$bearer_session_token = $fmda->getBearerSessionToken($response);
echo $bearer_session_token, PHP_EOL;
} else {
// ログイン失敗の処理を書く
echo "FileMaker Data API へのログインに失敗しました。\n";
}
// (何らかの処理があり、リンクでページ遷移した想定)
// セッションの検証
// レコード取得
// (何らかの処理)
// ログアウト
$response = $fmda->logOut($database, $bearer_session_token);
簡単に説明します。
-
$fmda = new FileMaker_Data_API($host, $version);
でクラスのインスタンスを作成します。引数は、FileMaker以後は、$fmda
がハンドルになります -
login()
メソッドを呼びます -
response.messages[0].code
のレスポンスコードを取得します。これが 0 ならログイン成功です - 成功の場合は、
getBearerSessionToken()
を呼んで、Bearer Session Token を取得します - 失敗の場合は、失敗処理をします
- (何らかの処理があり、リンクでページ遷移した想定)
- セッションの検証
- レコード取得
- (何らかの処理)
-
logOut()
メソッドを呼んで、ログアウトします
尚、コーディングにおけるブレース{}
は、クラス、メソッド、関数の場合は改行を入れて、if等その他の場合は、改行しないで書いています。
以上が、FileMaker Data API の基本的な流れになります。
Validate Session
Web アプリケーションで、ユーザにログイン情報を入力してもらったら、それを何らかの方法で保持しながら、FileMaker Data API のログイン〜処理〜ログアウトを繰り返すことになりますが、ログイン以降のリクエストは、すべて Bearer Session Token を使って行います。
しかし、Web 閲覧中のユーザの行動は予測できませんので(例えば、戻る動作をしている、長時間放置している等)、何らかのリクエストをする前には、auth - Validate Session を使って、Bearer Session Token が有効であるのかを検証しましょう。
filemaker-data-api.php への追加コード
(logOut メソッドのブロックの下に追加)
// データベースセッションの検証
public function validateSession (string $session_token): string
{
$authorization = 'Authorization: Bearer ' . $session_token;
$curlopt_httpheader = array($authorization);
$endpoint = "https://{$this->host}/fmi/data/{$this->version}/validateSession";
return self::executeCurl($endpoint, 'GET', $curlopt_httpheader);
}
login-log_out.php
の// セッションの検証
と// レコード取得
のコメントの部分を書き換えます。
// セッションの検証
$response = $fmda->validateSession($bearer_session_token);
if ($fmda->getMessagesCode($response) === '0') {
// セッション有効なら、行いたいリクエスト実行
echo "成功\n";
// レコード取得
} else {
// セッション無効なら、必要な Web データを保持して、ユーザに再ログインを促す
echo "再ログインしてください。\n";
}
Get Records
セッションを検証したら、メインのリクエストを行います。
まず、クラスに、records - Get Recordsのメソッドを追加します。
(validateSession メソッドのブロックの下に追加)
// レコード範囲の取得
public function getRecords(string $database, string $layout, string $bearer_session_token): string
{
$this->layout = $layout;
$authorization = 'Authorization: Bearer ' . $bearer_session_token;
$curlopt_httpheader = array($authorization);
$endPoint = "https://{$this->host}/fmi/data/{$this->version}/databases/{$database}/layouts/{$layout}/records";
return self::executeCurl($endPoint, 'GET', $curlopt_httpheader);
}
先程書き換えたセッションの検証のブロックの if の中身を書き換えます。
// セッションの検証
$response = $fmda->validateSession($bearer_session_token);
if ($fmda->getMessagesCode($response) === '0') {
// セッション有効なら、行いたいリクエスト実行
$response = $fmda->getRecords($database, $layout, $bearer_session_token);
print_r($response);
// レコード取得
} else {
// セッション無効なら、必要な Web データを保持して、ユーザに再ログインを促す
echo "再ログインしてください。\n";
}
成功すると、何やら JSON の塊が表示されますが、一応、Get Records が出来ました。
しかし、Get Records リクエストには、様々なパラメータを渡せます。また、取得できたのは、1,375件中 Get Records のデフォルトの100件のみです。
次回は、レスポンスの JSON の構造と Get Records のもう少し、細かい使い方をやってみたいと思います。
完成版 filemaker-data-api.php
<?php
class FileMaker_Data_API
{
public $host, $version, $database, $username, $password, $layout;
public $bearer_session_token;
function __construct (string $host, string $version)
{
$this->host = $host;
$this->version = $version;
}
/**
* リクエスト
**/
// ログイン
public function login (string $database, string $username, string $password): string
{
$this->database = $database;
$this->username = $username;
$this->password = $password;
$auth_value = $username . ':' . $password;
$authorization = 'Authorization: Basic ' . base64_encode($auth_value);
$content_type = 'Content-Type: application/json';
$curlopt_httpheader = array($authorization, $content_type);
$endpoint = "https://{$this->host}/fmi/data/{$this->version}/databases/{$database}/sessions";
return self::executeCurl($endpoint, 'POST', $curlopt_httpheader);
}
// ログアウト
public function logOut(string $database, string $bearer_session_token): string
{
$endpoint = "https://{$this->host}/fmi/data/{$this->version}/databases/{$database}/sessions/{$bearer_session_token}";
return self::executeCurl($endpoint, 'DELETE');
}
// データベースセッションの検証
public function validateSession (string $session_token): string
{
$authorization = 'Authorization: Bearer ' . $session_token;
$curlopt_httpheader = array($authorization);
$endpoint = "https://{$this->host}/fmi/data/{$this->version}/validateSession";
return self::executeCurl($endpoint, 'GET', $curlopt_httpheader);
}
// レコード範囲の取得
public function getRecords(string $database, string $layout, string $bearer_session_token): string
{
$this->layout = $layout;
$authorization = 'Authorization: Bearer ' . $bearer_session_token;
$curlopt_httpheader = array($authorization);
$endPoint = "https://{$this->host}/fmi/data/{$this->version}/databases/{$database}/layouts/{$layout}/records";
return self::executeCurl($endPoint, 'GET', $curlopt_httpheader);
}
/**
* ユーティリティ
**/
// レスポンスコードの取得
public function getMessagesCode (string $response): string
{
$response_array = self::json2array($response);
return $response_array['messages'][0]['code'];
}
// Bearer Session Token 取得
public function getBearerSessionToken (string $response): string
{
$response_array = self::json2array($response);
$this->bearer_session_token = $response_array['response']['token'];
return $this->bearer_session_token;
}
// JSON を 配列へ変換
public function json2array (string $json): array
{
$json = mb_convert_encoding($json, 'UTF8', 'ASCII,JIS,UTF-8,EUC-JP,SJIS-WIN');
return json_decode($json, true);
}
// cURL 実行
static function executeCurl(string $curlopt_url, string $curlopt_customrequest, array $curlopt_httpheader = []): string
{
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => $curlopt_url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => $curlopt_customrequest,
CURLOPT_POSTFIELDS => "{}",
CURLOPT_HTTPHEADER => $curlopt_httpheader,
));
$response = curl_exec($curl);
curl_close($curl);
return $response;
}
}
完成版 get_records.php
<?php
require_once(__DIR__ . '/filemaker-data-api.php');
$host = '(FileMaker Server のドメイン名)';
$version = 'vLatest';
$database = '(FileMaker ソリューション名)';
$username = '(FileMaker ユーザ名)';
$password = '(FileMaker パスワード)';
$layout = 'player_batting_basic';
$bearer_session_token = null;
$fmda = new FileMaker_Data_API($host, $version);
// ログイン
$response = $fmda->login($database, $username, $password);
// ログイン成功?
if ($fmda->getMessagesCode($response) === '0') {
// ログイン成功なら、Bearer Session Token を取得する
$bearer_session_token = $fmda->getBearerSessionToken($response);
echo $bearer_session_token, PHP_EOL;
} else {
// ログイン失敗の処理を書く
echo "FileMaker Data API へのログインに失敗しました。\n";
}
// (何らかの処理があり、リンクでページ遷移した想定)
// セッションの検証
$response = $fmda->validateSession($bearer_session_token);
if ($fmda->getMessagesCode($response) === '0') {
// セッション有効なら、行いたいリクエスト実行
$response = $fmda->getRecords($database, $layout, $bearer_session_token);
print_r($response);
// レコード取得
} else {
// セッション無効なら、必要な Web データを保持して、ユーザに再ログインを促す
echo "再ログインしてください。\n";
}
// レコード取得
// (何らかの処理)
// ログアウト
$response = $fmda->logOut($database, $bearer_session_token);
login-log_out.php テンプレート
<?php
require_once(__DIR__ . '/filemaker-data-api.php');
$host = 'remixworks.cloud';
$version = 'vLatest';
$database = 'remixworks_test';
$username = 'remixworks_1228';
$password = 'tomikf19';
$layout = 'player_batting_basic';
$bearer_session_token = null;
$fmda = new FileMaker_Data_API($host, $version);
// 次のメタデータ取得のリクエストはログインする必要がない。
// Product Info
// Database Names
/**
* Login begin
*/
// ログイン
$response = $fmda->login($database, $username, $password);
// ログイン成功?
if ($fmda->getMessagesCode($response) === '0') {
// ログイン成功なら、Bearer Session Token を取得する
$bearer_session_token = $fmda->getBearerSessionToken($response);
} else {
// ログイン失敗の処理を書く
echo "FileMaker Data API へのログインに失敗しました。\n";
}
/**
* Login end
*/
// (何らかの処理があり、リンクでページ遷移した想定)
// セッションの検証
$response = $fmda->validateSession($bearer_session_token);
if ($fmda->getMessagesCode($response) === '0') {
// セッション有効なら、以下の任意のリクエストを実行
// 取得 Get Records
// 取得 Get Single Record by Id
// 作成 Create Record
// 編集 Edit Record
// 編集 Upload to Container Field
// 編集 Upload to Container Field (specific repetition)
// 編集 Set Global Fields
// 削除 Delete Record
// 複製 Duplicate Record
// 検索 Find Record
// スクリプト Execute Script
// メタデータ取得 Layout Names
// メタデータ取得 Script Names
// メタデータ取得 Layout Metadata
// メタデータ取得 Old Layout Metadata
} else {
// セッション無効なら、必要な Web データを保持して、ユーザに再ログインを促す
echo "再ログインしてください。\n";
}
// レコード取得
// (何らかの処理)
/**
* Log out begin
*/
// ログアウト
$response = $fmda->logOut($database, $bearer_session_token);
/**
* Log out end
*/