设计应用程序编程接口 (API) 可能是一项具有挑战性的工作。好的 API 具有简单明了且易于使用的简单界面。在这个简单的界面背后可能有许多复杂的系统交互,而这些交互确实会使原本明确定义的端点任务变得浑浊。随着时间的流逝,开发人员可能会被要求为现有端点“添加”其他业务逻辑。然后,在不知不觉中,单个 API 调用正在与十几个系统进行交互,作为其主流程的一部分。

如果我们能开发一个简单明了的管道,但能够在以后添加其他任务而不会掩盖主流程,那不是很好吗?本文将向您展示如何调整 WordPress 和一般编程中的想法,以使您的 API 能够进行更强大的交互。

什么是钩子/动作?

钩子(又名操作/过滤器)是 WordPress 社区为事件及其相关回调命名的名称。如果您有任何编程经验,您可能熟悉回调和发布者-订阅者模式。在处理过程中,系统可能会触发一个事件,该事件调用订阅该事件的零到多个函数。例如,为了响应加载页面,WordPress 会调用用于加载标题、加载标题、列出帖子或查找正确模板的函数。这些任务的运行不会弄乱生成页面的主要过程。

钩子背后的想法并不是什么新鲜事,也不是WordPress发明的。但是,WordPress 在其服务器端页面处理生命周期中在实现它们方面做得很好。在我看来,这种钩子的使用可能是该平台最大的功能。有了这些钩子,用户可以编写自己的功能——无论是插件还是主题——这些功能都与 WordPress 相关联,并在需要时运行您想要的任何代码。是否需要更改发送给用户的标头?没问题:挂接到事件中,您可以根据需要更改标题。wp_headers

为什么要在 API 中使用钩子?

钩子对很多事情都有好处,包括触发一些附带任务、通过 PHP cURL 命令调用另一个系统、构建对象并将其放入任务队列中以供另一个系统稍后接收、发送电子邮件等等。这一切都可以在不需要云化给定端点的主流的情况下完成(并且可能在此过程中强制使用新的 API 版本)。

如果端点用于创建用户,我们可以专注于在数据库中创建该用户记录,并在此过程中调用在此过程中正在侦听的人。也许在创建用户记录后,我们会发送一个事件,上面写着“任何听这个的人,我刚刚创建了一个用户,这是他们的信息”。也许某些回调函数已订阅该事件并正在侦听,或者可能没有。该活动并不在乎。

有了这个系统,我们可以让我们的 API 调用以后可能编写的代码。我们可以在不接触 API 端点代码本身的情况下做到这一点。为了演示它是如何工作的,让我们换个角度,展示如何在 PHP API 中启动它的基本机制。请记住,虽然我们在这里使用 PHP,但我们实际上可以在使用其他语言的 Web 应用程序中实现类似的逻辑。

建立基本机制

首先,我们需要能够添加一个钩子/动作(从现在开始我将其称为“钩子”)。我们还需要能够移除钩子,最后触发钩子。一旦我们定义了这些机制,我们只需要确保它们包含在 API 中,然后在 API 中找到我们可能想要调用这些钩子的位置。以下是我们可能想要设置的一种方法。

这里是:hooks.php

解释
// Global array which will hold all of our hooks // We will reference this array in each function to add/remove/call our hooks // The code below should also be seen by any callbacks we write for the system later. $hooks = []; // Below are global functions that can be seen from our API code // The add_hook method will allow us to attach a function (callback) to a given event name function add_hook($event_name, $callback) { global $hooks; if ($callback !== null) { if ($callback) { // We can set up multiple callbacks under a single event name $hooks[$event_name][] = $callback; } } } // Super easy to implement, we remove the given hook by its name function remove_hook($event_name) { global $hooks; unset($hooks[$event_name]); } // When we want to trigger our callbacks, we can call this function // with its name and any parameters we want to pass. function do_hook($event_name, ...$params) { global $hooks; if (isset($hooks[$event_name])) { // Loop through all the callbacks on this event name and call them (if defined that is) // As we call each callback, we given it our parameters. foreach ($hooks[$event_name] as $function) { if (function_exists($function)) { call_user_func($function, ...$params); } } } }

现在我们已经创建了文件,我们只需要将其包含在我们的 API 中,以便可以看到这些函数。完成此操作后,只需使用 .hooks.phpdo_hook

举个简单的例子,假设我们有一个 API 用于向系统注册新用户。我们可能有一个名为 的 REST API 端点。为了简单起见,我们还假设这里的目标是简单地将新用户的姓名和年龄插入到数据库的表中。很简单,对吧?/addUserusers

解释
// POST endpoint for adding a user (part of a larger API class) public function addUser($name, $age) { if ($this->request->method === 'post') { try { $this->db->insert('users', ['name' => $name, 'age' => $age]); return new Response(200, 'User created successfully!'); } catch (Exception $e) { // Oops, something went wrong. // Do some logging or whatever. } } // If not a POST request, return http status 400 return new Response(400, 'Bad request'); }

上面的代码是关于我们如何添加新用户的过于简单和笼统的视图。这个想法是,如果有人要调用我们 API 的端点,他们最终会到达这个函数,其中用户的姓名和年龄将从发布的数据中提取出来。我们首先检查以确保他们正在发布(按照正确的 REST 规则要求),然后尝试将用户插入到表中。/addUserusers

接下来,如果用户已成功插入,我们想要调用一个钩子,让任何代码侦听用户被创建(这类似于引发其他语言的事件)。

需求发生变化时该怎么办

几个月后,我们的营销部门坚持要求,当创建新用户时,应该发送一封包含用户详细信息的电子邮件。我们可能倾向于将帮助程序函数写入 API,然后从此端点代码调用它。伟大。。。如果这就是所要求的全部内容。但是,如果支持团队后来来找您并希望您也将用户添加到他们的 Zendesk 系统中,该怎么办?因此,您编写了另一个函数,并将该调用也固定到此端点中。

接下来你知道,这个端点不仅将用户添加到我们的网站数据库,而且还调用用于发送电子邮件的函数,将用户添加到Zendesk,Jira和Microsoft云,然后处理他们的成功/失败结果。所有这些额外的东西实际上都偏离了将用户添加到我们数据库的明确点。我们想调用一个事件,让其他代码在创建用户时侦听并执行自己的操作,而无需修改此端点。也许没有其他服务关心添加新用户,因此没有人被要求做任何事情。终结点不必关心。真是太棒了,对吧?

让我们继续我们的例子,给我们的钩子起一个名字。这是所有回调代码侦听时需要使用的名称。同样,其他语言将此设置称为“事件”,因此请务必使用给定的语言查找它以了解更多信息。

我们称之为钩子。简单明了,你不觉得吗?一旦我们有了名字,我们就可以决定在哪里调用这个钩子。我认为在成功插入后立即是一个好主意:added_user

解释
public function addUser($name, $age) { if ($this->request->method === 'post') { try { $this->db->insert('users', ['name' => $name, 'age' => $age]); // Call our new hook and give it the name and age of the user. Anyone listening can then access these params. do_hook('added_user', $name, $age); return new Response(200, 'User created successfully!'); } catch (Exception $e) { // Oops, something went wrong. // Do some logging or whatever. } } return new Response(400, 'Bad request'); }

现在我们可以有几十个回调函数监听钩子,或者根本不听。也许我们有一个回调负责将用户插入 Zendesk,另一个回调将获取姓名和年龄并生成一封发送给营销的电子邮件。这个“订阅者”代码可以位于代码库中的其他位置,只要它能看到 API 项目中的代码。我通常将回调函数放在一个单独的文件中,并将该文件包含在 API 中。下面是一个回调示例,现在可以利用我们创建的这个新钩子:added_userhooks.php

解释
function sendContactToMarketing($name, $age) { // Do email stuff } add_hook('added_user', 'sendContactToMarketing');

我们可以在哪里放置这些钩子?

在上面的代码中,我们演示了如何在单个端点中使用钩子。仅当调用终结点时,并且仅在插入成功后才会触发此挂钩。但这并不是您可以使用这些钩子的唯一地方。也许您的 API 类中有一些路由代码,这些代码通过检查 API 密钥是否有效,或者您甚至是否收到了某种类型的请求来运行。/addUser

您可以在 API 中的全局级别放置一个钩子,以便每个请求都触发它。然后,在稍后的某个时候,有人可以编写一个记录器,将其附加到您创建的钩子上,然后突然开始记录对 API 发出的所有请求——同样,不触及主 API 类代码。同样的钩子可能还附加了一个额外的回调,该回调将检查 API 滥用,并在开始看到有人用请求抨击您的 API 时将其报告给您的信息技术部门。api_init

下图是这一切在架构上的样子。由于您可以在多个位置使用此机制,因此您甚至可以在 API 端点的开头、中间和结尾调用钩子。您还可以在处理请求的整个 API 生命周期的不同点设置钩子。插入这些调用的位置完全取决于您的设计。do_hook

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论
小程序二维码

微信小程序

微信扫一扫体验

立即
投稿
公众号二维码

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部