概要
WordPress REST APIは、PHPを介して他のWordPressコード内で内部的に呼び出すことができますが、REST APIはHTTPを介してリモートで使用するように設計されています。HTTPはインターネット上でデータを通信するための基盤であり、HTTPリクエストを行うことができるアプリケーションは、クライアントサイドのJavaScriptインターフェースであれ、PythonやJavaで実行されているリモートサーバー上のアプリケーションであれ、WordPress REST APIを利用できます。
リクエストのデータ構造は、WP_REST_Request
クラスによって便利に処理されます。
WP_REST_Request
このクラスは、WordPress 4.4で導入された3つの主要なインフラストラクチャクラスの1つです。APIのエンドポイントにHTTPリクエストが行われると、APIは提供されたデータに一致するWP_REST_Request
クラスのインスタンスを自動的に作成します。レスポンスオブジェクトはWP_REST_Server
のserve_request()
メソッドで自動生成されます。リクエストが作成され、認証が確認されると、リクエストが送信され、エンドポイントコールバックが開始されます。WP_REST_Request
オブジェクトに保存されたすべてのデータは、登録されたエンドポイントのコールバックに渡されます。したがって、permission_callback
とcallback
の両方がリクエストオブジェクトを渡して呼び出されます。これにより、コールバック内でさまざまなリクエストプロパティにアクセスでき、期待される出力に合わせてレスポンスを調整できます。
リクエストプロパティ
リクエストオブジェクトには多くの異なるプロパティがあり、それぞれがさまざまな方法で使用できます。主なプロパティは、リクエストメソッド、ルート、ヘッダー、パラメータ、および属性です。これらをリクエスト内での役割に分解してみましょう。リクエストオブジェクトを自分で作成すると、次のようになります:
$request = new WP_REST_Request( 'GET', '/my-namespace/v1/examples' );
上記のコードサンプルでは、リクエストオブジェクトのメソッドがGET
であり、ルート/my-namespace/v1/examples
に一致する必要があることを指定しています。これは、全体のURLの文脈では次のようになります: https://ourawesomesite.com/wp-json/my-namespace/v1/examples`. The method and route arguments for the
WP_REST_Request`コンストラクタは、リクエストを目的のエンドポイントにマッピングするために使用されます。リクエストが登録されていないエンドポイントに対して行われた場合、役立つ404エラーメッセージがレスポンスに返されます。さまざまなプロパティをより深く見てみましょう。
メソッド
リクエストオブジェクトのメソッドプロパティは、デフォルトでHTTPリクエストメソッドに一致します。メソッドはほとんどの場合、GET
、POST
、PUT
、DELETE
、OPTIONS
、またはHEAD
のいずれかになります。これらのメソッドは、ルートに登録されたさまざまなエンドポイントに一致させるために使用されます。APIがメソッドとルートの一致を見つけると、そのエンドポイントのコールバックが発火します。
次の規約は、HTTPメソッドを一致させるためのベストプラクティスです: GET
は読み取り専用タスク、POST
は作成、PUT
は更新、DELETE
は削除のために使用されます。リクエストメソッドは、エンドポイントの期待される機能の指標として機能します。ルートにGET
リクエストを行うと、読み取り専用データが返されることを期待する必要があります。
ルート
リクエストのルートは、デフォルトでパス情報のサーバー環境変数に一致します; $_SERVER['PATH_INFO']
。WordPress REST APIのルートにHTTPリクエストを行うと、生成されたWP_REST_Request
オブジェクトはそのパスに一致するように作成され、次に有効なエンドポイントに一致することが期待されます。要するに、リクエストのルートは、API内でリクエストをターゲットにしたい場所です。
もし私たちがGET
を使用して本のエンドポイントを登録していた場合、それはhttps://ourawesomesite.com/wp-json/my-namespace/v1/books
に存在するかもしれません。そのURLにブラウザでアクセスすると、JSONで表現された本のコレクションが表示されます。WordPressは自動的にリクエストオブジェクトを生成し、エンドポイントに一致させるためのすべてのルーティングを処理します。したがって、私たちが自分でルーティングを心配する必要はなく、リクエストに渡したい追加データを渡す方法を理解することがはるかに重要です。
ヘッダー
HTTPリクエストヘッダーは、単にHTTPリクエストに関する追加データです。リクエストヘッダーは、キャッシュポリシー、リクエストコンテンツ、リクエストの発信元などを指定できます。リクエストヘッダーは必ずしもエンドポイントと直接相互作用するわけではありませんが、ヘッダー内の情報はWordPressが何をすべきかを知るのに役立ちます。エンドポイントと相互作用するデータを渡すには、パラメータを使用する必要があります。
パラメータ
WordPress REST APIにリクエストを行う際、渡される追加データのほとんどはパラメータの形を取ります。パラメータとは何ですか?APIの文脈では4つの異なるタイプがあります。ルートパラメータ、クエリパラメータ、ボディパラメータ、およびファイルパラメータです。それぞれをもう少し詳しく見てみましょう。
URLパラメータ
URLパラメータは、要求されたルートのパス変数からWP_REST_Request
で自動的に生成されます。それはどういう意味ですか?個々の本をIDで取得するこのルートを見てみましょう: /my-namespace/v1/books/(?P<id>\d+)
。奇妙に見える(?P<id>\d+)
はパス変数です。パス変数の名前は「id
」です。
もし私たちがGET https://ourawesomesite.com/wp-json/my-namespace/v1/books/5`,
5will become the value for our
idpath variable. The
WP_REST_Request`オブジェクトにリクエストを行った場合、そのパス変数は自動的にURLパラメータとして保存されます。今、エンドポイントコールバック内でそのURLパラメータと簡単に相互作用できます。例を見てみましょう。
// Register our individual books endpoint.
function prefix_register_book_route() {
register_rest_route( 'my-namespace/v1', '/books/(?P<id>\d+)', array(
// Supported methods for this endpoint. WP_REST_Server::READABLE translates to GET.
'methods' => WP_REST_Server::READABLE,
// Register the callback for the endpoint.
'callback' => 'prefix_get_book',
) );
}
add_action( 'rest_api_init', 'prefix_register_book_route' );
/**
* Our registered endpoint callback. Notice how we are passing in $request as an argument.
* By default, the WP_REST_Server will pass in the matched request object to our callback.
*
* @param WP_REST_Request $request The current matched request object.
*/
function prefix_get_book( $request ) {
// Here we are accessing the path variable 'id' from the $request.
$book = prefix_get_the_book( $request['id'] );
return rest_ensure_response( $book );
}
// A simple function that grabs a book title from our books by ID.
function prefix_get_the_book( $id ) {
$books = array(
'Design Patterns',
'Clean Code',
'Refactoring',
'Structure and Interpretation of Computer Programs',
);
$book = '';
if ( isset( $books[ $id ] ) ) {
// Grab the matching book.
$book = $books[ $id ];
} else {
// Error handling.
return new WP_Error( 'rest_not_found', esc_html__( 'The book does not exist', 'my-text-domain' ), array( 'status' => 404 ) );
}
return $book;
}
上記の例では、パス変数がリクエストオブジェクト内でURLパラメータとして保存される様子が示されています。次に、エンドポイントコールバック内でそれらのパラメータにアクセスできます。上記の例は、URLパラメータを使用する一般的なユースケースです。ルートにパス変数を多く追加すると、ルートの一致が遅くなり、エンドポイントの登録が複雑になる可能性があるため、URLパラメータは控えめに使用することをお勧めします。URLパス内でパラメータを直接使用するべきでない場合、リクエストに追加情報を渡す別の方法が必要です。ここでクエリパラメータとボディパラメータが登場し、通常はAPI内での重い作業を行います。
クエリパラメータ
クエリパラメータは、URIのクエリ文字列部分に存在します。URIのクエリ文字列部分はhttps://ourawesomesite.com/wp-json/my-namespace/v1/books?per_page=2&genre=fiction` is
?per_page=2&genre=fiction. The query string is started by the '
?' character, the different values within the query string are separated by the '
&' character. We specified two parameters in our query string;
per_pageand
genre. In our endpoint we would want to grab only two books from the fiction genre. We could access those values in a callback like this:
$request[‘per_page’], and
$request[‘genre’]`($requestが使用している引数の名前であると仮定します)。PHPに慣れている場合、Webアプリケーションでクエリパラメータを使用したことがあるでしょう。
PHPでは、クエリパラメータはスーパーグローバル$_GET
に保存されます。スーパーグローバルやサーバー変数に直接アクセスすることは決してないことに注意することが重要です。WP_REST_Request
クラスによって提供されるものを使用するのが最善です。エンドポイントに変数を渡すためのもう1つの一般的な方法は、ボディパラメータを使用することです。
ボディパラメータ
ボディパラメータは、リクエストボディに保存されるキーと値のペアです。POST
リクエストを<form>
、cURL、または他の方法で送信したことがある場合、ボディパラメータを使用したことになります。ボディパラメータは、さまざまなコンテンツタイプとして渡すこともできます。Content-Type
リクエストのデフォルトヘッダーはx-www-form-urlencoded
です。x-www-form-urlencoded
を使用する場合、パラメータはクエリ文字列のように送信されます; per_page=2&genre=fiction
。HTMLフォームは、デフォルトでさまざまな入力をまとめてPOST
リクエストを送信し、x-www-form-urlencoded
パターンに一致します。
HTTP仕様ではGET
リクエストでボディパラメータを送信することを禁止していないが、GET
リクエストでボディパラメータを使用しないことが推奨されます。ボディパラメータはPOST
、PUT
、およびDELETE
リクエストに使用されるべきです。
ファイルパラメータ
WP_REST_Request
オブジェクト内のファイルパラメータは、リクエストが特別なコンテンツタイプヘッダーを使用する場合に保存されます; multipart/form-data
。ファイルデータは、$request->get_file_params()
を使用してリクエストオブジェクトからアクセスできます。ファイルパラメータは、PHPのスーパーグローバル$_FILES
に相当します。スーパーグローバルに直接アクセスせず、WP_REST_Request
オブジェクトが提供するもののみを使用してください。
エンドポイントコールバック内でwp_handle_upload()
を使用して、WordPressのメディアアップロードディレクトリに必要なファイルを追加できます。ファイルパラメータはファイルデータを扱うためだけに役立ち、他の目的で使用するべきではありません。
属性
属性では、サポートされているメソッド、オプション、このエンドポイントをインデックスに表示するかどうか、エンドポイントの登録引数のリスト、および登録されたコールバックが含まれるレスポンスを取得します。次のように見えるかもしれません:
``````bash
{
"methods": {
"GET": true
},
"accept_json": false,
"accept_raw": false,
"show_in_index": true,
"args": {
"context": {
"description": "Scope under which the request is made; determines fields present in response.",
"type": "string",
"sanitize_callback": "sanitize_key",
"validate_callback": "rest_validate_request_arg",
"enum": [
"view",
"embed",
"edit"
],
"default": "view"
},
"page": {
"description": "Current page of the collection.",
"type": "integer",
"default": 1,
"sanitize_callback": "absint",
"validate_callback": "rest_validate_request_arg",
"minimum": 1
},
"per_page": {
"description": "Maximum number of items to be returned in result set.",
"type": "integer",
"default": 10,
"minimum": 1,
"maximum": 100,
"sanitize_callback": "absint",
"validate_callback": "rest_validate_request_arg"
},
"search": {
"description": "Limit results to those matching a string.",
"type": "string",
"sanitize_callback": "sanitize_text_field",
"validate_callback": "rest_validate_request_arg"
},
"after": {
"description": "Limit response to resources published after a given ISO8601 compliant date.",
"type": "string",
"format": "date-time",
"validate_callback": "rest_validate_request_arg"
},
"author": {
"description": "Limit result set to posts assigned to specific authors.",
"type": "array",
"default": [],
"sanitize_callback": "wp_parse_id_list",
"validate_callback": "rest_validate_request_arg"
},
"author_exclude": {
"description": "Ensure result set excludes posts assigned to specific authors.",
"type": "array",
"default": [],
"sanitize_callback": "wp_parse_id_list",
"validate_callback": "rest_validate_request_arg"
},
"before": {
"description": "Limit response to resources published before a given ISO8601 compliant date.",
"type": "string",
"format": "date-time",
"validate_callback": "rest_validate_request_arg"
},
"exclude": {
"description": "Ensure result set excludes specific ids.",
"type": "array",
"default": [],
"sanitize_callback": "wp_parse_id_list"
},
"include": {
"description": "Limit result set to specific ids.",
"type": "array",
"default": [],
"sanitize_callback": "wp_parse_id_list"
},
"offset": {
"description": "Offset the result set by a specific number of items.",
"type": "integer",
"sanitize_callback": "absint",
"validate_callback": "rest_validate_request_arg"
},
"order": {
"description": "Order sort attribute ascending or descending.",
"type": "string",
"default": "desc",
"enum": [
"asc",
"desc"
],
"validate_callback": "rest_validate_request_arg"
},
"orderby": {
"description": "Sort collection by object attribute.",
"type": "string",
"default": "date",
"enum": [
"date",
"relevance",
"id",
"include",
"title",
"slug"
],
"validate_callback": "rest_validate_request_arg"
},
"slug": {
"description": "Limit result set to posts with a specific slug.",
"type": "string",
"validate_callback": "rest_validate_request_arg"
},
"status": {
"default": "publish",
"description": "Limit result set to posts assigned a specific status; can be comma-delimited list of status types.",
"enum": [
"publish",
"future",
"draft",
"pending",
"private",
"trash",
"auto-draft",
"inherit",
"any"
],
"sanitize_callback": "sanitize_key",
"type": "string",
"validate_callback": [
{},
"validate_user_can_query_private_statuses"
]
},
"filter": {
"description": "Use WP Query arguments to modify the response; private query vars require appropriate authorization."
},
"categories": {
"description": "Limit result set to all items that have the specified term assigned in the categories taxonomy.",
"type": "array",
"sanitize_callback": "wp_parse_id_list",
"default": []
},
"tags": {
"description": "Limit result set to all items that have the specified term assigned in the tags taxonomy.",
"type": "array",
"sanitize_callback": "wp_parse_id_list",
"default": []
}
},
"callback": [
{},
"get_items"
],
"permission_callback": [
{},
"get_items_permissions_check"
]
}
`
ご覧のとおり、エンドポイントに登録したすべての情報がすでにそこにあり、準備が整っています!リクエスト属性は通常、より低いレベルで使用され、WP_REST_Server
クラスによって処理されますが、エンドポイントコールバック内で登録された引数に一致する受け入れ可能なパラメータを制限するなど、面白いことができます。
WP REST APIは、内部をいじる必要がないように設計されているため、WP_REST_Request
との相互作用のためのこれらのより高度なメソッドは一般的に実践されません。WP REST APIを使用する核心は、ルートとエンドポイントの登録に関連しています。リクエストは、APIにどのエンドポイントにアクセスしたいかを伝えるためのツールです。これは通常HTTPを介して行われますが、内部でWP_REST_Request
を使用することもできます。
内部リクエスト
内部リクエストを行う鍵は、rest_do_request()
を使用することです。リクエストオブジェクトを渡すだけで、レスポンスが返されます。リクエストはWP_REST_Server
によって提供されないため、レスポンスデータはJSONにエンコードされることはなく、PHPオブジェクトとしてレスポンスオブジェクトを持つことができます。これは非常に素晴らしく、興味深いことをたくさん行うことができます。たとえば、効率的なバッチエンドポイントを作成できます。パフォーマンスの観点から、1つの課題はHTTPリクエストを最小限に抑えることです。rest_do_request()
を使用して、すべてのリクエストを内部で1つのHTTPリクエストで処理するバッチエンドポイントを作成できます。これは、読み取り専用データのための非常に単純なバッチエンドポイントの例ですので、rest_do_request()
がどのように機能するかを確認できます。
// Register our mock batch endpoint.
function prefix_register_batch_route() {
register_rest_route( 'my-namespace/v1', '/batch', array(
// Supported methods for this endpoint. WP_REST_Server::READABLE translates to GET.
'methods' => WP_REST_Server::READABLE,
// Register the callback for the endpoint.
'callback' => 'prefix_do_batch_request',
// Register args for the batch endpoint.
'args' => prefix_batch_request_parameters(),
) );
}
add_action( 'rest_api_init', 'prefix_register_batch_route' );
/**
* Our registered endpoint callback. Notice how we are passing in $request as an argument.
* By default, the WP_REST_Server will pass in the matched request object to our callback.
*
* @param WP_REST_Request $request The current matched request object.
*/
function prefix_do_batch_request( $request ) {
// Here we initialize the array that will hold our response data.
$data = array();
$data = prefix_handle_batch_requests( $request['requests'] );
return $data;
}
/**
* This handles the building of the response for the batch requests we make.
*
* @param array $requests An array of data to build WP_REST_Request objects from.
* @return WP_REST_Response A collection of response data for batch endpoints.
*/
function prefix_handle_batch_requests( $requests ) {
$data = array();
// Foreach request specified in the requests param run the endpoint.
foreach ( $requests as $request_params ) {
$response = prefix_handle_request( $request_params );
$key = $request_params['method'] . ' ' . $request_params['route'];
$data[ $key ] = prefix_prepare_for_collection( $response );
}
return rest_ensure_response( $data );
}
/**
* This handles the building of the response for the batch requests we make.
*
* @param array $request_params Data to build a WP_REST_Request object from.
* @return WP_REST_Response Response data for the request.
*/
function prefix_handle_request( $request_params ) {
$request = new WP_REST_Request( $request_params['method'], $request_params['route'] );
// Add specified request parameters into the request.
if ( isset( $request_params['params'] ) ) {
foreach ( $request_params['params'] as $param_name => $param_value ) {
$request->set_param( $param_name, $param_value );
}
}
$response = rest_do_request( $request );
return $response;
}
/**
* Prepare a response for inserting into a collection of responses.
*
* This is lifted from WP_REST_Controller class in the WP REST API v2 plugin.
*
* @param WP_REST_Response $response Response object.
* @return array Response data, ready for insertion into collection data.
*/
function prefix_prepare_for_collection( $response ) {
if ( ! ( $response instanceof WP_REST_Response ) ) {
return $response;
}
$data = (array) $response->get_data();
$server = rest_get_server();
if ( method_exists( $server, 'get_compact_response_links' ) ) {
$links = call_user_func( array( $server, 'get_compact_response_links' ), $response );
} else {
$links = call_user_func( array( $server, 'get_response_links' ), $response );
}
if ( ! empty( $links ) ) {
$data['_links'] = $links;
}
return $data;
}
/**
* Returns the JSON schema data for our registered parameters.
*
* @return array $params A PHP representation of JSON Schema data.
*/
function prefix_batch_request_parameters() {
$params = array();
$params['requests'] = array(
'description' => esc_html__( 'An array of request objects arguments that can be built into WP_REST_Request instances.', 'my-text-domain' ),
'type' => 'array',
'required' => true,
'validate_callback' => 'prefix_validate_requests',
'items' => array(
array(
'type' => 'object',
'properties' => array(
'method' => array(
'description' => esc_html__( 'HTTP Method of the desired request.', 'my-text-domain' ),
'type' => 'string',
'required' => true,
'enum' => array(
'GET',
'POST',
'PUT',
'DELETE',
'OPTIONS',
),
),
'route' => array(
'description' => esc_html__( 'Desired route for the request.', 'my-text-domain' ),
'required' => true,
'type' => 'string',
'format' => 'uri',
),
'params' => array(
'description' => esc_html__( 'Key value pairs of desired request parameters.', 'my-text-domain' ),
'type' => 'object',
),
),
),
),
);
return $params;
}
function prefix_validate_requests( $requests, $request, $param_key ) {
// If requests isn't an array of requests then we don't process the batch.
if ( ! is_array( $requests ) ) {
return new WP_Error( 'rest_invald_param', esc_html__( 'The requests parameter must be an array of requests.' ), array( 'status' => 400 ) );
}
foreach ( $requests as $request ) {
// If the method or route is not set then we do not run the requests.
if ( ! isset( $request['method'] ) || ! isset( $request['route'] ) ) {
return new WP_Error( 'rest_invald_param', esc_html__( 'You must specify the method and route for each request.' ), array( 'status' => 400 ) );
}
if ( isset( $request['params'] ) && ! is_array( $request['params'] ) ) {
return new WP_Error( 'rest_invald_param', esc_html__( 'You must specify the params for each request as an array of named key value pairs.' ), array( 'status' => 400 ) );
}
}
// This is a black listing approach to data validation.
return true;
}
これは、いくつかのトピックをカバーするかなりの量のコードですが、すべてはprefix_handle_request()
で何が起こるかに集中しています。ここでは、HTTPメソッド、ルート、およびリクエストに変換したいパラメータのセットを示す配列を渡しています。次に、メソッドとルートのリクエストオブジェクトを構築します。指定されたパラメータがある場合は、WP_REST_Request::set_param()
メソッドを使用して必要なパラメータを追加します。WP_REST_Request
が準備が整ったら、rest_do_request
を使用してそのエンドポイントを内部的に一致させ、レスポンスがバッチエンドポイントのレスポンスコレクションに返されます。このようなバッチエンドポイントを使用すると、複数のエンドポイントのレスポンスを取得するために1つのHTTPリクエストを行うだけで済むため、大きなパフォーマンス向上が得られます。この実装は必ずしも最良の方法ではなく、例として機能します; これはこれを行う唯一の方法ではありません。