Implementation Details
Method Naming
By convention, all functions and methods use underscore_case, as per the WordPress Coding Standards.
Routing
The routing code is written in such a way to ensure that the input and output are handled only by this code.
The majority of state is handled in the serve_request()
method, which handles
both reading input and serializing the output to JSON. This is responsible for
translating HTTP to an internal representation suitable for dispatching.
The routing code also operates with global state, as it’s intended to handle the HTTP interactions, which is inherently global in PHP.
The dispatch()
method handles matching the requested route with an endpoint.
This method also deals with global state for GET and POST parameters, however
this is not the optimal situation, as it requires reimplementation of the
routing code when embedding the API.
This could possibly be optimized by performing straight string matching for the static portion of the URL. Symfony uses this internally in their routing, although they don’t allow arbitrary regular expressions for routes.
Parameters
Endpoints take parameters as direct function arguments. This fits in with the philosophy that the endpoints should match up with functions fairly directly. This means that in order to write an endpoint, all you need to know is how to write a function.
This uses the Reflection API to match provided parameters up with the function’s parameters in the correct order, and with default values as needed. The performance of this API is anecdotally not a real consideration, however benchmarks are yet to be taken in a rigorous manner.
Intentionally, it is not possible to get all supplied parameters. This is
regarded as a bad API smell, as each parameter should be fully documented for
consumers. It is possible to construct hacks around this using the
json_dispatch_args
filter, but this is intentionally made to feel hacky.
Some parameters give information about the context of the call. These are prefixed with an underscore, and are always set. This ensures that a rogue consumer can’t pass in the internal name to override it and possibly cause a security issue.