More thoughts on WP-API 1.0

In my previous post, I shared some feedback on the WP-API 1.0 release based on a weekend of evaluation. Since then I’ve had conversations with several people and done more experimentation, and wanted to share some revised feedback.

On MIME types

I previously suggested using custom vendor MIME types to identify and version each of the individual REST media types. After further consideration, I’m no longer convinced that it’s worth the additional complexity that it imposes on clients.

There have been much discussion and debate about the merits of using MIME types for API-level versioning versus adding a version token to the URL, and I do not wish to rehash those arguments here. That’s a decision that can be made by the core team when the time is right.

Media Types

Instead, I think it will suffice to use simple strings to identify media types. For core, that would be “post”, “term”, “taxonomy”, “comment”, “user”, etc. It may make sense to prefix these with “core/” to avoid collisions with plugins (e.g., “core/post” and “buddypress/forum”).

If a media type’s schema has to change in a non-backwards compatible manner, then the type’s name should be changed so that clients can distinguish the versions. Possibly like “core/post-v2”.

API Structure

In my original feedback, I outlined how I thought the API should be structured to encourage consistency:

    • Entities (e.g., post, comment, user, term, etc.) are defined by a string name and documented schema.
    • 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/do-magic).

I still feel that enforcing this structure will lead to a cleaner and easier-to-consume API.

Permissions

One advantage of the HATEOS architectural style is that the user’s permissions are embedded into responses by nature of the presence or absence of links on a resource.

For example, if a user can read terms but not add new ones, the API response for a post object can specify that the terms sub-collection supports HEAD/GET but not POST.

WP-API 1.0 only puts the “supports” information (i.e., the valid HTTP verbs) in the root-level route descriptions. To better expose the user’s permissions and what actions the client can actually perform on behalf of the user, this “supports” information should be exposed for every individual (sub-)collections link.

As part of a post object, WP-API 1.0 returns:

"meta": {
	"links": {
		"self": "http://example.com/wp-json/posts/1",
		"author": "http://example.com/wp-json/users/1",
		"collection": "http://example.com/wp-json/posts",
		"replies": "http://example.com/wp-json/posts/1/comments",
		"terms": "http://example.com/wp-json/posts/1/terms",
		"version-history": "http://example.com/wp-json/posts/1/revisions"
	}
}

A future version could return:

"meta": {
	"links": {
		"self": "http://example.com/wp-json/posts/1",
		"author": "http://example.com/wp-json/users/1",
		"collection": "http://example.com/wp-json/posts",
		"collections": {
			"comments": {
				"self": "http://example.com/wp-json/posts/1/comments",
				"params": ["page", "filter"],
				"supports": ["HEAD", "GET", "POST"]
			},
			"terms": {
				"self": "http://example.com/wp-json/posts/1/terms",
				"params": ["page", "filter", "taxonomy"],
				"supports": ["HEAD", "GET"]
			},
			"revisions": {
				"self": "http://example.com/wp-json/posts/1/revisions",
				"params": [],
				"supports": ["HEAD", "GET"]
			}
		},
		"actions": {
			"domagic": "http://example.com/wp-json/posts/1/do-magic",
		}
	}
}

Notice that I have identified sub-collections by their media type identifier, rather than an arbitrary keyword (“responses”, “version-history”). This lets clients find the media types that they know about, and ignore the rest.

It also includes a “params” array which lists the set of valid query parameters. This tells the client what the supported parameters are before they try to use them, potentially allowing the client to adapt behavior depending on what the server supports.

Altogether, this response includes enough information for a client application (GUI or otherwise) to adapt its interface based on what the user is allowed to do, and truly uses hypermedia as the engine for application state.

There are a few unusual permissions issues that will have to be resolved. Some fields, like ‘sticky’ and ‘post_author’ have additional permissions that are applied to them if a user tries to change the value. We will need to find a way to expose that type of permissions information to a client, perhaps as a special field in the “meta” dictionary. Others, like ‘post_status’, can be dealt with by filtering the collection returned by the post statuses endpoint based on the user’s role.

Example

In an attempt to more clearly show what I’ve been trying to describe, see this (abbreviated) example of the structure in this gist:

https://gist.github.com/maxcutler/e22b2f6ba50e157b260f

C# client

This weekend I got started on a C# client library, which targets WP-API 1.0. If/when the plugin incorporates any of my feedback, I will update the library to take advantage of it. The library is still at an early stage, but includes most of the currently exposed media types, and has a simple console app that discovers the available routes and some recent content.

https://github.com/maxcutler/wp-api-csharp

Conclusion

I’ll undoubtedly have more feedback for the WP-API team over the coming days and weeks as I continue to work with it more and more. I’d love to see some more people write libraries or example apps/plugins/themes/whatever, so please spread the word and encourage people to share their own thoughts and feedback.

One Response to More thoughts on WP-API 1.0

Leave a Reply