The last 5 projects all needed some kind of API endpoint. Over time, I've settled for a custom "api" page under home. In two projects, this is a very simple piece of code with a switch statement, in others it looks for individual templates under templates/api. I'm not completely happy with any of them, though, and I've often wished for something akin to hooks with enough boilerplate to avoid repetitive code.
I do concur that Laravel has some very nice and expressive features. I could picture a WireApi singleton class with which modules could register, and a fixed "api" page that is by default not much more than
<?php namespace ProcessWire;
wire('api')->handleRequest();
WireApi may or may not route to matching PHP files under templates/api by default.
Autload modules could register their routes in their init() method. Just a rough example with one or two Laravel niceties stirred into the usual PW awesomeness to get a nice declarative approach to api route definitions:
<?php namespace ProcessWire;
class ApiExampleHandler extends ApiRoute {
public static function getModuleInfo() {
return [...];
}
public function init() {
parent::init();
# hand GET requests to /api/users/USERID/profiledata off to our getUsrProfileData method
# and pass the value in place of USERID as the first parameter $user to the method.
# Use $sanitizer->intUnsigned on $user to make sure it is a valid page id.
$this->api->get('/users/{user}/profiledata', $this, 'getUserProfileData')->whereSanitized('user', 'intUnsigned');
}
public function getUserProfileData($user) {
$u = $this->users->get($user) ?: $this->api->notFound();
$p = $u->profilepage ?: $this->api->notFound();
# Set Content-Type header, set json_encode return value and output it
$this->api->jsonResponse([
'nickname' => $p->nick,
'hobbies' => $p->hobbies,
'membersince' => $p->joindate
]);
}
}
Something along those lines could go a long way to making endpoint implementation easier. I don't know how often I've checked for isAjax et al, called json_decode and json_encode, checked the request method, sanitized and compared urlSegement1 and urlSegment2 and urlSegment3 (and sometimes even urlSegement4) in nested conditionals...
For quick and dirty solutions, api route registration could go into api.php before handleRequest() is called, or even into site/ready.php.
With a bit of creative magic, a nice PWish equivalent to Laravel's model binding should also be in the realm of possible things.