WordPress源码深度解析之:`WordPress`的`REST API`:如何利用`register_rest_route()`创建自定义端点。

各位靓仔靓女们,晚上好!我是你们的老朋友,今天咱们来聊聊WordPress REST API这个磨人的小妖精,特别是如何用register_rest_route()来调戏它,创造属于你自己的API端点。

开场白:WordPress REST API 是个啥玩意儿?

想象一下,WordPress不再只是一个简单的博客平台,而是变成了一个数据服务中心。你可以用它存储各种奇奇怪怪的数据,然后通过一套标准化的接口(就是REST API)让其他应用来访问这些数据。比如说,你的手机App,你的前端框架(React, Vue, Angular),甚至是你的智能冰箱,都可以通过REST API和你的WordPress站点进行交流。

REST API就像一个翻译官,把各种不同的语言(比如JavaScript, Python, Java)翻译成WordPress能听懂的“语言”,然后把WordPress的回答再翻译成这些语言能理解的格式(通常是JSON)。

正餐:register_rest_route() 登场!

register_rest_route()是WordPress REST API的核心函数之一,它的作用就是注册一个新的API端点。你可以把它想象成在你的WordPress站点上开辟了一条新的“高速公路”,让外部应用可以访问你的自定义数据。

register_rest_route() 的语法结构

register_rest_route()函数接受三个参数:

  1. $namespace (string): API的命名空间,用于区分不同的API。通常使用插件或主题的名称作为命名空间,比如my-plugin/v1
  2. $route (string): API的路由地址,也就是API的URL路径。比如/books/authors
  3. $args (array): 一个包含API配置信息的数组,包括HTTP方法,回调函数,参数验证等等。

举个栗子:

add_action( 'rest_api_init', function () {
  register_rest_route( 'my-plugin/v1', '/books', array(
    'methods'  => 'GET',
    'callback' => 'get_all_books',
  ) );
} );

function get_all_books( $request ) {
  // 在这里编写获取所有书籍的代码
  $books = array(
    array( 'id' => 1, 'title' => 'The Hitchhiker's Guide to the Galaxy', 'author' => 'Douglas Adams' ),
    array( 'id' => 2, 'title' => 'Pride and Prejudice', 'author' => 'Jane Austen' ),
  );

  return rest_ensure_response( $books );
}

这段代码注册了一个API端点:my-plugin/v1/books。当客户端发起一个GET请求到这个URL时,get_all_books函数会被调用,然后返回一个包含所有书籍信息的JSON数据。

$args 数组详解

$args数组是register_rest_route()函数中最关键的部分,它决定了你的API端点的行为。下面是一些常用的参数:

参数名 类型 描述
methods string/array 允许的HTTP方法,比如GET, POST, PUT, DELETE。可以是一个字符串,也可以是一个包含多个方法的数组。
callback callable 回调函数,当API端点被访问时,这个函数会被调用。这个函数接收一个WP_REST_Request对象作为参数,可以从中获取请求参数。
permission_callback callable 权限验证回调函数,用于检查用户是否有权限访问这个API端点。如果返回true表示有权限,返回false表示没有权限。
args array 用于定义请求参数的数组。可以指定参数的类型,是否必须,以及验证规则。

HTTP 方法:GET, POST, PUT, DELETE

REST API的核心概念之一就是使用不同的HTTP方法来表示不同的操作。

  • GET: 获取数据。比如获取所有书籍,获取某本书的详细信息。
  • POST: 创建新的数据。比如创建一个新的书籍。
  • PUT: 更新已存在的数据。比如更新某本书的信息。
  • DELETE: 删除数据。比如删除某本书。

回调函数:处理请求,返回数据

回调函数是你的API端点的“大脑”。它负责处理客户端的请求,从数据库中获取数据,进行业务逻辑处理,然后将结果返回给客户端。

回调函数接收一个WP_REST_Request对象作为参数。这个对象包含了客户端请求的所有信息,包括请求参数,请求头,请求方法等等。

你可以使用$request->get_params()方法来获取请求参数。比如:

function get_book( $request ) {
  $book_id = $request->get_param( 'id' ); // 获取名为'id'的请求参数

  // 从数据库中获取ID为$book_id的书籍信息
  $book = get_book_from_database( $book_id );

  if ( empty( $book ) ) {
    return new WP_Error( 'book_not_found', 'Book not found', array( 'status' => 404 ) );
  }

  return rest_ensure_response( $book );
}

权限验证:保护你的API

权限验证是API安全的关键。permission_callback参数允许你定义一个函数,用于检查用户是否有权限访问这个API端点。

比如,你可以检查用户是否已经登录,或者是否具有特定的角色。

function check_permission() {
  if ( ! is_user_logged_in() ) {
    return new WP_Error( 'rest_not_logged_in', 'You are not currently logged in.', array( 'status' => 401 ) );
  }
  return true;
}

add_action( 'rest_api_init', function () {
  register_rest_route( 'my-plugin/v1', '/books', array(
    'methods'  => 'POST',
    'callback' => 'create_book',
    'permission_callback' => 'check_permission',
  ) );
} );

这段代码注册了一个POST API端点,用于创建新的书籍。permission_callback设置为check_permission函数,这个函数会检查用户是否已经登录。如果用户没有登录,会返回一个错误。

参数验证:确保数据的有效性

args参数允许你定义请求参数的验证规则。你可以指定参数的类型,是否必须,以及验证规则。

add_action( 'rest_api_init', function () {
  register_rest_route( 'my-plugin/v1', '/books', array(
    'methods'  => 'POST',
    'callback' => 'create_book',
    'args' => array(
      'title' => array(
        'required' => true,
        'type' => 'string',
        'description' => 'The title of the book.',
      ),
      'author' => array(
        'required' => true,
        'type' => 'string',
        'description' => 'The author of the book.',
      ),
    ),
  ) );
} );

function create_book( $request ) {
  $title = $request->get_param( 'title' );
  $author = $request->get_param( 'author' );

  // 创建新的书籍
  $book_id = create_book_in_database( $title, $author );

  return rest_ensure_response( array( 'id' => $book_id ) );
}

这段代码定义了两个请求参数:titleauthor。这两个参数都是必须的,类型都是字符串,并且都有一个描述。如果客户端没有提供这两个参数,或者参数类型不正确,WordPress REST API会自动返回一个错误。

错误处理:优雅地告诉用户发生了什么

当API发生错误时,你需要优雅地告诉用户发生了什么。WordPress REST API提供了一个WP_Error类,用于表示错误信息。

function get_book( $request ) {
  $book_id = $request->get_param( 'id' );

  $book = get_book_from_database( $book_id );

  if ( empty( $book ) ) {
    return new WP_Error( 'book_not_found', 'Book not found', array( 'status' => 404 ) );
  }

  return rest_ensure_response( $book );
}

这段代码在找不到书籍时,返回一个WP_Error对象。WP_Error对象包含了错误代码,错误信息,以及HTTP状态码。客户端可以根据这些信息来判断发生了什么错误。

一个完整的例子:CRUD 操作

让我们来创建一个完整的例子,实现对书籍的CRUD(Create, Read, Update, Delete)操作。

add_action( 'rest_api_init', function () {
  // 获取所有书籍
  register_rest_route( 'my-plugin/v1', '/books', array(
    'methods'  => 'GET',
    'callback' => 'get_all_books',
  ) );

  // 获取某本书籍
  register_rest_route( 'my-plugin/v1', '/books/(?P<id>d+)', array(
    'methods'  => 'GET',
    'callback' => 'get_book',
    'args' => array(
      'id' => array(
        'required' => true,
        'type' => 'integer',
        'description' => 'The ID of the book.',
      ),
    ),
  ) );

  // 创建新的书籍
  register_rest_route( 'my-plugin/v1', '/books', array(
    'methods'  => 'POST',
    'callback' => 'create_book',
    'permission_callback' => 'check_permission',
    'args' => array(
      'title' => array(
        'required' => true,
        'type' => 'string',
        'description' => 'The title of the book.',
      ),
      'author' => array(
        'required' => true,
        'type' => 'string',
        'description' => 'The author of the book.',
      ),
    ),
  ) );

  // 更新书籍
  register_rest_route( 'my-plugin/v1', '/books/(?P<id>d+)', array(
    'methods'  => 'PUT',
    'callback' => 'update_book',
    'permission_callback' => 'check_permission',
    'args' => array(
      'id' => array(
        'required' => true,
        'type' => 'integer',
        'description' => 'The ID of the book.',
      ),
      'title' => array(
        'type' => 'string',
        'description' => 'The title of the book.',
      ),
      'author' => array(
        'type' => 'string',
        'description' => 'The author of the book.',
      ),
    ),
  ) );

  // 删除书籍
  register_rest_route( 'my-plugin/v1', '/books/(?P<id>d+)', array(
    'methods'  => 'DELETE',
    'callback' => 'delete_book',
    'permission_callback' => 'check_permission',
    'args' => array(
      'id' => array(
        'required' => true,
        'type' => 'integer',
        'description' => 'The ID of the book.',
      ),
    ),
  ) );
} );

function get_all_books( $request ) {
  // 在这里编写获取所有书籍的代码
  $books = get_all_books_from_database();

  return rest_ensure_response( $books );
}

function get_book( $request ) {
  $book_id = $request->get_param( 'id' );

  $book = get_book_from_database( $book_id );

  if ( empty( $book ) ) {
    return new WP_Error( 'book_not_found', 'Book not found', array( 'status' => 404 ) );
  }

  return rest_ensure_response( $book );
}

function create_book( $request ) {
  $title = $request->get_param( 'title' );
  $author = $request->get_param( 'author' );

  $book_id = create_book_in_database( $title, $author );

  return rest_ensure_response( array( 'id' => $book_id ) );
}

function update_book( $request ) {
  $book_id = $request->get_param( 'id' );
  $title = $request->get_param( 'title' );
  $author = $request->get_param( 'author' );

  $updated = update_book_in_database( $book_id, $title, $author );

  if ( ! $updated ) {
    return new WP_Error( 'book_not_found', 'Book not found', array( 'status' => 404 ) );
  }

  return rest_ensure_response( array( 'id' => $book_id ) );
}

function delete_book( $request ) {
  $book_id = $request->get_param( 'id' );

  $deleted = delete_book_from_database( $book_id );

  if ( ! $deleted ) {
    return new WP_Error( 'book_not_found', 'Book not found', array( 'status' => 404 ) );
  }

  return rest_ensure_response( array( 'deleted' => true ) );
}

function check_permission() {
  if ( ! is_user_logged_in() ) {
    return new WP_Error( 'rest_not_logged_in', 'You are not currently logged in.', array( 'status' => 401 ) );
  }
  return true;
}

// 假设这些函数已经定义
function get_all_books_from_database() {
  // 从数据库获取所有书籍
  return array(
    array( 'id' => 1, 'title' => 'The Hitchhiker's Guide to the Galaxy', 'author' => 'Douglas Adams' ),
    array( 'id' => 2, 'title' => 'Pride and Prejudice', 'author' => 'Jane Austen' ),
  );
}

function get_book_from_database( $book_id ) {
  // 从数据库获取ID为$book_id的书籍
  if ($book_id == 1) {
    return array( 'id' => 1, 'title' => 'The Hitchhiker's Guide to the Galaxy', 'author' => 'Douglas Adams' );
  } elseif ($book_id == 2) {
      return array( 'id' => 2, 'title' => 'Pride and Prejudice', 'author' => 'Jane Austen' );
  }
  return null;
}

function create_book_in_database( $title, $author ) {
  // 在数据库中创建新的书籍,并返回ID
  return 3; // 假设创建成功,返回ID为3
}

function update_book_in_database( $book_id, $title, $author ) {
  // 在数据库中更新ID为$book_id的书籍
  return true; // 假设更新成功
}

function delete_book_from_database( $book_id ) {
  // 从数据库中删除ID为$book_id的书籍
  return true; // 假设删除成功
}

正则表达式:更灵活的路由匹配

register_rest_route()函数中,你可以使用正则表达式来定义更灵活的路由匹配规则。

比如,上面的代码中使用了(?P<id>d+)来匹配书籍的ID。(?P<id>d+)是一个正则表达式,它的含义是:

  • (?P<id>...): 定义一个名为id的捕获组。
  • d+: 匹配一个或多个数字。

这意味着,/books/1, /books/123, /books/12345 都会匹配到这个路由,并且id参数的值会分别是1, 123, 12345

调试技巧:让你的API开发更轻松

  • WP_DEBUG: 开启WordPress的调试模式。这可以帮助你发现代码中的错误。
  • rest_validate_request_arg 过滤器: 使用这个过滤器可以调试请求参数的验证过程。
  • rest_pre_dispatch 过滤器: 使用这个过滤器可以调试API的调用过程。
  • 使用API客户端: 使用Postman, Insomnia等API客户端来测试你的API端点。

总结:掌握register_rest_route(),玩转 WordPress REST API

register_rest_route()是WordPress REST API的基石。掌握了它,你就可以创建各种各样的自定义API端点,让你的WordPress站点变得更加强大和灵活。

记住,REST API的核心在于合理使用HTTP方法,进行权限验证,进行参数验证,以及优雅地处理错误。

希望今天的讲座对大家有所帮助。下次再见!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注