Feedback on WP-API 1.0

Recently the WP-API team released version 1.0 of their new JSON-based API for WordPress. I’ve been following their progress from a distance, but now that it is under consideration for inclusion into WordPress core I thought it was time to take a closer look.

As context for those unaware, I was a large contributor to the WordPress XML-RPC API in 3.4 and 3.5 when we added a bunch of new features to that API. I was a minor contributor to the official WordPress mobile apps, and have been building my own (as-yet-unreleased) WordPress mobile app over the past few months. I’ve written libraries for the XML-RPC API in Python, C#, and JavaScript, and have consulted on numerous projects that consumed the API.

As such, most of this feedback is from the perspective of a client library author and mobile app developer. I will not address the actual PHP implementation, as other core devs/contributors are more qualified for that perspective.

High-level thoughts

Discovery & HATEOS

Good
    • Multiple easy methods of checking for the existence of WP-API in a WordPress installation
    • Link headers and ‘meta’ links in response body for relevant related API calls, like sub-collections (comments on a post) or resultset paging
    • Uses standard HTTP methods as expected for actions on collections and entities
Needs work
    • Meta links seem arbitrary – ‘author’ appears as both an embedded object in the post object, as well as a link in the meta links collection; terms is embedded in post, but comments are a link
    • No means of discovering routes based on content type, so clients must hardcode URLs for the top-level routes
    • No auto-generated schema to allow for discovery of what content types are supported on a particular server (other than checking for particular hard-coded routes)

Transport

Good
    • Default serialization is JSON, which is universally supported and easy to work with
    • Pluggable authentication, with plugins already built for Basic Auth, OAuth 1.0a, and WordPress cookie
Needs work
    • Need proof-of-concept plugin for at least one different serialization technology – YAML, Protobufs, XML, etc.
    • Need to figure out plan for client oAuth registration against many sites – Ryan has outline of options, needs to be solved before general purpose mobile clients can be developed
    • Need plan and documentation for how clients are supposed to detect available authentication schemes
    • “Context” abstraction does not give adequate flexibility on response structure – XML-RPC added “fields” parameter to allow for customization, may need something similar

Forward & Backward Compatibility

Good
    • WP-API team has acknowledged this will likely be an issue in the future
Needs work
    • Needs to be resolved before shipping in core, especially versioning of entity schemas – see below
    • Need to consider needs of both “core” API (posts, terms, comments, etc.) and APIs added by plugins (e.g., BuddyPress, Pods)

Documentation

Good
    • Quality documentation on the major topics that need to be covered
    • Schemas documented in both human-readable Markdown and machine-readable JSON
Needs work
    • Would be better if schema and route documentation were auto-generated rather than manually written – humans make mistakes, and plugin authors likely won’t have same level of documentation quality if it requires manual work

Musings on content types

Clients for the WP-API 1.0 release have to hard-code too much knowledge about routes. For example, the reference JS client has hard-coded path substrings rather than discovering them HATEOS-style from the root document. This means that sites cannot customize the API routes at all without breaking general-purpose clients; for example, if a site wanted to change their API to use different terminology like “document” instead of “post”, a client wouldn’t be able to interact with it even though it does actually understand the underlying schema.

Speaking of entity schemas, I think there have to be affordances for future changes in the API’s design and implementation. WordPress core has historically been relatively stable (though there’s long been talk of changes to taxonomies), so it’s perhaps not as critical for the core APIs. But if we expect plugins to extend the API with their own functionality, then there must be a mechanism for their authors to evolve the schemas over time.

This works in both directions. If I write code against a plugin’s 2014 schema, I don’t want that code to suddenly break in 2016 when the plugin’s schemas are dramatically changed. And if I write code in 2016, I should be able to talk to both the 2014 and 2016 schemas so that it works with WordPress installations that are slow to upgrade plugins. As a developer of a general-purpose client, I need the flexibility to handle those types of compatibility scenarios.

A potential reframing

To address some of these concerns, this is how I would consider framing the API:

Structural
    • Entities (e.g., post, comment, user, term, etc.) are defined by a schema that is identified as a vendor MIME-type. For example, ‘application/vnd.wordpress.post.v1.read+json’.
    • Collections are filter-able & page-able lists of a particular entity type.
    • Entities can contain sub-collections (e.g., post contains collection of comments).
    • Entities can expose “special” actions, that can be invoked via POST only (e.g., POST /posts/42/domagic).
    • The root document contains a map of MIME-type to collection URL.
Behavioral
    • Clients can use the ‘Accept’ HTTP header to specify the preferred MIME-types they would like to receive. If no Accept header is sent, the API can return the latest default type. This allows clients that care about forward and backward compatibility to negotiate appropriately with the server.
    • Clients can discover all URLs without any a priori knowledge other than the MIME-type schemas that they are programmed to understand, by using the index’s map to find a collection URL and then following links to the entities, sub-collections, special actions, etc.
    • Clients can determine if a server supports a particular feature (e.g., has the BuddyPress plugin installed) by checking for the presence of one of its MIME-types in the index document.
    • Each entity type can be versioned independently from other entity types.
    • Plugins could add handlers for new MIME-types to existing entities, and clients that are aware of those special types could use them or fall back on the standard type for that entity.
    • Auto-generated schema and/or documentation would allow for tools to do interesting things with the API, like generate alternate schema representations, sandbox tools (e.g., Swagger, iodocs), code for libraries, and anything else that clever developers can think of.

By having consistent structure and behavior, it becomes much easier for flexible and long-lived clients to be created. Core and plugins would have consistent behavior with minimal effort on the part of plugin authors.

I haven’t looked closely enough at the 1.0 implementation to know how easy it would be to enforce these structures and behaviors, that will have to be the topic of further investigation and experimentation.

Conclusion

If WP-API is integrated into WordPress core, it will be around for a long time (xmlrpc.php was added May 23rd, 2004). We owe it to the community to put in some work and experimentation now to avoid years of potential pain and workarounds.

For my part, I’ll be attending at least three WordCamps this summer (Philly, Seattle, NYC) where I will be working on client libraries and proof-of-concept apps that use WP-API 1.0 (and any future iterations). If you will be at any of these events and want to talk about or hack on the API, please let me know!

9 Responses to Feedback on WP-API 1.0

Leave a Reply