概要
API のレスポンスは、私たちが求めるすべてのデータを保持しています。リクエストに誤りがあった場合、レスポンスのデータはエラーが発生したことを知らせるべきです。WordPress REST API のレスポンスは、要求したデータまたはエラーメッセージを返す必要があります。API のレスポンスは、API の三つのインフラストラクチャクラスの一つである WP_REST_Response
クラスによって処理されます。
WP_REST_Response
WP_REST_Response
は WordPress の WP_HTTP_Response
クラスを拡張し、レスポンスヘッダー、レスポンスステータスコード、およびレスポンスデータへのアクセスを可能にします。
// The following code will not do anything and just serves as a demonstration.
$response = new WP_REST_Response( 'This is some data' );
// To get the response data we can use this method. It should equal 'This is some data'.
$our_data = $response->get_data();
// To access the HTTP status code we can use this method. The most common status code is probably 200, which means OK!
$our_status = $response->get_status();
// To access the HTTP response headers we can use this method.
$our_headers = $response->get_headers();
上記は非常に簡単で、レスポンスから必要なものを取得する方法を示しています。WP_REST_Response
はさらに進んでいます。レスポンスの一致したルートにアクセスして、レスポンスがどのエンドポイントから来たのかを追跡することができます $response->get_matched_route()
。$response->get_matched_handler()
は、私たちのレスポンスを生成したエンドポイントに登録されたオプションを返します。これらは、API のログ記録などに役立つ可能性があります。レスポンスクラスは、エラーハンドリングにも役立ちます。
エラーハンドリング
リクエストに何か重大な問題が発生した場合、私たちはエンドポイントコールバック内で WP_Error
オブジェクトを返し、何が間違っていたのかを説明することができます。
// Register our mock batch endpoint.
function prefix_register_broken_route() {
register_rest_route( 'my-namespace/v1', '/broken', 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_an_error',
) );
}
add_action( 'rest_api_init', 'prefix_register_broken_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_an_error( $request ) {
return new WP_Error( 'oops', esc_html__( 'This endpoint is currently broken, try another endpoint, I promise the API is cool! EEEK!!!!', 'my-textdomain' ), array( 'status' => 400 ) );
}
これは少し馬鹿げた例ですが、いくつかの重要な点に触れています。最も重要なことは、WordPress REST API が自動的に WP_Error オブジェクトを HTTP レスポンスに変換し、あなたのデータを含むことです。WP_Error
オブジェクトでステータスコードを設定すると、HTTP レスポンスのステータスコードはその値を取ります。これは、見つからなかったコンテンツのための 404 や、禁止されたアクセスのための 403 など、異なるエラーコードを使用する必要があるときに非常に便利です。私たちがする必要があるのは、エンドポイントコールバックがリクエストを返すことだけで、WP_REST_Server
クラスが私たちのために非常に重要なことを多く処理してくれます。
レスポンスクラスは、リンク作成など、他にもクールなことを手伝ってくれます。
リンク作成
もし私たちが投稿とその投稿の最初のコメントを取得したい場合、別のエンドポイントを作成してこのユースケースを処理する必要がありますか?もしそうした場合、さまざまな小さなユースケースを処理するために多くのエンドポイントを追加しなければならず、私たちの API インデックスは非常に早く膨れ上がってしまいます。レスポンスリンク作成は、API が理解できるリソース間の関係を形成する方法を提供します。API は、リソースリンク作成のための HAL として知られる標準を実装しています。投稿とコメントの例を見てみましょう。それぞれのリソースに対してルートを持つ方が良いでしょう。
投稿 ID = 1 とコメント ID = 3 があるとしましょう。コメントは投稿 1 に割り当てられているので、現実的には二つのリソースはルート /my-namespace/v1/posts/1
と /my-namespace/v1/comments/3
に存在することができます。私たちはレスポンスにリンクを追加して、それらの間の関係を作成します。まずコメントの視点から見てみましょう。
// Register our mock endpoints.
function prefix_register_my_routes() {
register_rest_route( 'my-namespace/v1', '/posts/(?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_rest_post',
) );
register_rest_route( 'my-namespace/v1', '/comments', 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_rest_comments',
// Register the post argument to limit results to a specific post parent.
'args' => array(
'post' => array(
'description' => esc_html__( 'The post ID that the comment is assigned to.', 'my-textdomain' ),
'type' => 'integer',
'required' => true,
),
),
) );
register_rest_route( 'my-namespace/v1', '/comments/(?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_rest_comment',
) );
}
add_action( 'rest_api_init', 'prefix_register_my_routes' );
// Grab a post.
function prefix_get_rest_post( $request ) {
$id = (int) $request['id'];
$post = get_post( $id );
$response = rest_ensure_response( array( $post ) );
$response->add_links( prefix_prepare_post_links( $post ) );
return $response;
}
// Prepare post links.
function prefix_prepare_post_links( $post ) {
$links = array();
$replies_url = rest_url( 'my-namespace/v1/comments' );
$replies_url = add_query_arg( 'post', $post->ID, $replies_url );
$links['replies'] = array(
'href' => $replies_url,
'embeddable' => true,
);
return $links;
}
// Grab a comments.
function prefix_get_rest_comments( $request ) {
if ( ! isset( $request['post'] ) ) {
return new WP_Error( 'rest_bad_request', esc_html__( 'You must specify the post parameter for this request.', 'my-text-domain' ), array( 'status' => 400 ) );
}
$data = array();
$comments = get_comments( array( 'post__in' => $request['post'] ) );
if ( empty( $comments ) ) {
return array();
}
foreach( $comments as $comment ) {
$response = rest_ensure_response( $comment );
$response->add_links( prefix_prepare_comment_links( $comment ) );
$data[] = prefix_prepare_for_collection( $response );
}
$response = rest_ensure_response( $data );
return $response;
}
// Grab a comment.
function prefix_get_rest_comment( $request ) {
$id = (int) $request['id'];
$post = get_comment( $id );
$response = rest_ensure_response( $comment );
$response->add_links( prefix_prepare_comment_links( $comment ) );
return $response;
}
// Prepare comment links.
function prefix_prepare_comment_links( $comment ) {
$links = array();
if ( 0 !== (int) $comment->comment_post_ID ) {
$post = get_post( $comment->comment_post_ID );
if ( ! empty( $post->ID ) ) {
$links['up'] = array(
'href' => rest_url( 'my-namespace/v1/posts/' . $comment->comment_post_ID ),
'embeddable' => true,
'post_type' => $post->post_type,
);
}
}
return $links;
}
/**
* 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;
}
上記の例のように、私たちはリンクを使用してリソース間の関係を作成しています。投稿にコメントがある場合、私たちのエンドポイントコールバックは、現在の投稿 ID に一致する post
パラメータを指定してコメントルートへのリンクを追加します。したがって、そのルートをたどると、その投稿 ID に割り当てられたコメントが得られます。コメントを検索すると、各コメントには投稿を指すリンクが up
という形で存在します。up
は HAL 仕様を使用したリンクに特別な意味を持ちます。コメントの up
リンクをたどると、そのコメントの親である投稿が返されます。リンク作成は非常に素晴らしいですが、さらに良くなります。
WordPress REST API は、埋め込みと呼ばれるものもサポートしています。追加した両方のリンクで、私たちは embeddable => true
を指定しました。これにより、リンクされたデータをレスポンスに埋め込むことができます。したがって、コメント 3 とその割り当てられた投稿を取得したい場合、次のリクエストを行うことができます https://ourawesomesite.com/wp-json/my-namespace/v1/comments/3?_embed
。_embed
パラメータは、私たちのリクエストに対して埋め込むことができるすべてのリソースリンクを API に追加するように指示します。埋め込みを使用することは、複数のリソースが一つの HTTP リクエストで処理されるため、パフォーマンスの向上になります。
埋め込みとリンクの賢い使用は、WordPress REST API を非常に柔軟で強力なものにし、WordPress と対話するためのものです。