Flexible API Design - Create Hooks For Your PHP API Pipeline - SitePoint
Flexible API Design - Create Hooks For Your PHP API Pipeline - SitePoint
Tim Hurd
ADVERTISEMENT
Wouldn’t it be nice if we could develop a pipeline that’s straightforward but with the
capability to add additional tasks later without obscuring the main flow? This article will
show you how you can adapt an idea from WordPress, and programming in general, to give
your APIs the ability to do more powerful interactions.
// 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 give
function add_hook($event_name, $callback) {
global $hooks;
unset($hooks[$event_name]);
}
if (isset($hooks[$event_name])) {
// Loop through all the callbacks on this event name and call them (if d
// 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);
}
}
}
}
Now that we have our hooks.php file created, we simply need to include it into our API so
that these functions can be seen. Once this is done, it’s just a matter of inserting the hooks
into our API using do_hook .
As a simple example, let’s assume we have an API for registering a new user with our
system. We may have a REST API endpoint called /addUser . In the name of simplicity, let’s
also assume that the goal here is to simply insert a new user’s name and age into our
database’s users table. Pretty straight forward, right?
The code above is an overly simplistic and generalized view of how we might add a new
user. The idea is that, if someone were to call our API’s /addUser endpoint, they would
eventually arrive at this function where the name and age of the user is pulled out of the
posted data. We first check to make sure they’re posting (as proper REST rules dictate) and
then try to insert the user into the users table.
Next, if the user has been inserted successfully, we want to call a hook to let any code
listening that a user was created (this is similar to raising an event in other languages).
ADVERTISEMENT
What to do when requirements change
A few months later, we have our marketing department insisting that, when a new user is
created, an email should be sent with the user’s details. We might be inclined to write a
helper function into the API, then call it from this endpoint code. Great … if that’s all that was
requested. But what if the support team later comes to you and wants you to also add the
user to their Zendesk system. So you write another function and tack that call into this
endpoint also.
Next thing you know, this endpoint is not only adding a user to our website database, but
making calls to functions for sending emails, adding users to Zendesk, Jira and the Microsoft
cloud and then dealing with their success/failure results. All this additional stuff is really
taking away from the clear point of adding the user to our database. We’d like to call one
event and have other code just listen for when a user is created and do their own things —
without us needing to modify this endpoint whatsoever. Perhaps no other services care
about adding a new user, so no one is called upon to do anything. The endpoint doesn’t have
to care. Pretty awesome, right?
Let’s continue our example by giving our hook a name. This is the name that all callback
code will need to use to listen. Again, other languages refer to this setup as “events”, so be
sure to look it up in your given language to learn more.
We’ll call our hook added_user . Simple and straight to the point, don’t you think? Once we
have a name, we can decide where we want to call this hook. I think right after a successful
insert would be a good idea:
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 li
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.
}
}
Now we can have dozens of callback functions listening to the added_user hook or none at
all. Maybe we have one callback that’s responsible for inserting the user into Zendesk and
another that will take the name and age and generate an email to marketing. This
“subscriber” code can live somewhere else in the codebase, as long as it can see the
hooks.php code inside the API project. I typically put my callback function in a separate file
and include that file into the API as well. Below is one example of a callback that can now
take advantage of this new hook we created:
function sendContactToMarketing($name, $age) {
// Do email stuff
}
add_hook('added_user', 'sendContactToMarketing');
Since you can use this mechanism in multiple locations, you can even have hooks called at
the beginning, middle and at the end of an API endpoint. You could also have hooks at
various points of the entire API lifecycle of handling a request. It’s really up to your design on
where you insert these do_hook calls.
Best Practices
Let’s now cover some best practices for you and your developers to follow.
One thing to keep in mind is that these hooks still do call out to code that will execute in the
single thread. Unless you trigger something in your callback which kicks the task to some
background process or other service, the API will still be running this extra code (when the
hook is triggered). This means that we should do our best to keep any callback code lean
and mean. Long-running callback code is going to slow down the endpoints or the API as a
whole.
Conclusion
In this article, we discussed what hooks/actions are and how they might be used. We gave
some example PHP code that you can use in your PHP API to implement “hooking” and how
a callback might be used to tie into that hook. We also discussed adding hooks on a general
API level (more globally for all requests) as well as in endpoints. In addition to that, we also
talked a bit about some of the drawbacks of this system and that it’s a good idea to keep
your callbacks lean and mean. But in the event you do have a long-running callback, we
mentioned a few strategies for dealing with such processes to prevent them from impacting
your API pipeline.
If you implement this system, you too can gain some of the greatest functionality that the
WordPress community (and programmers in general) have enjoyed for years. You’ll also save
yourself a lot of time and headaches from having to modify your API code directly, and you’ll
be able to focus on small callback code instead. You can also add and remove callbacks that
may be entire integrations with other systems. All this functionality — and not once having to
republish your API pipeline code! That’s a pretty good deal, right? With this system, I’ve
managed to do some simple integrations in a day, and now you can do it too.
Thanks for reading!
api
100 Jamstack Tools, APIs & Content as UX: Building a Getting Started With The
Services to Power Your More Human Web Particle Photon
Sites Georgina Laidlaw Patrick Catanzariti
Lucero del Alba
Stuff we do Contact
Premium Contact us
Newsletters FAQ
Learning paths Publish your book with us
Library Write an article with us
Forums Advertise
About Connect
Our story RSS
Corporate memberships Facebook
Terms of use Instagram
Privacy policy Twitter (X)
This site is protected by reCAPTCHA and the Google Privacy
Policy and Terms of Service apply.
Back to top