Skip to content

Conversation

@kadamwhite
Copy link
Collaborator

This supersedes both #144 and #158 by providing a method that developers can use to arbitrarily support any endpoint.


Support for Custom Post Types is provided via the .registerRoute method. This method returns a handler function which can be assigned to your site instance as a method, and takes the same namespace and route string arguments as rest_register_route:

var site = new WP({ endpoint: 'http://www.yoursite.com/wp-json' });
site.myCustomResource = site.registerRoute( 'myplugin/v1', '/author/(?P<id>)' );
site.myCustomResource().id( 17 ); // => myplugin/v1/author/17

The string (?P<id>) indicates that a level of the route for this resource is a dynamic property named ID. By default, properties identified in this fashion will not have any inherent validation. This is designed to give developers the flexibility to pass in anything, with the caveat that only valid IDs will be accepted on the WordPress end.

You might notice that in the example from the official WP-API documentation, a pattern is specified with a different format: this is a regular expression designed to validate the values that may be used for this capture group.

var site = new WP({ endpoint: 'http://www.yoursite.com/wp-json' });
site.myCustomResource = site.registerRoute( 'myplugin/v1', '/author/(?P<id>\\d+)' );
site.myCustomResource().id( 7 ); // => myplugin/v1/author/7
site.myCustomResource().id( 'foo' ); // => Error: Invalid path component: foo does not match (?P<a>\d+)

Adding the regular expression pattern (as a string) enabled validation for this component. In this case, the \\d+ will cause only numeric values to be accepted.

NOTE THE DOUBLE-SLASHES in the route definition here, however: '/author/(?P<id>\\d+)' This is a JavaScript string, where \ must be written as \\ to be parsed properly. A single backslash will break the route's validation.

Each named group in the route will be converted into a named setter method on the route handler, as in .id() in the example above: that name is taken from the <id> in the route string.

The route string 'pages/(?P<parentPage>[\d]+)/revisions/(?P<id>[\d]+)' would create the setters .parentPage() and id(), permitting any permutation of the provided URL to be created.

To permit custom parameter support methods on custom endpoints, a configuration object may be passed to the registerRoute method with a mixins property defining any functions to add:

site.handler = site.registerRoute( 'myplugin/v1', 'collection/(?P<id>)', {
    mixins: {
        myParam: function( val ) {
            return this.param( 'my_param', val );
        }
    }
});

This permits a developer to extend an endpoint with arbitrary parameters in the same manner as is done for the automatically-generated built-in route handlers.

Auto-discovery of all available routes will be supported in the near future, as will re-utilizing existing mixins (like .search()) on custom routes.

@kadamwhite
Copy link
Collaborator Author

@jasonphillips @timmyc @elyobo @joehoyle @rmccue I'd love your feedback on this!

@kadamwhite
Copy link
Collaborator Author

kadamwhite commented Jun 16, 2016

To clarify the intent of this function: .registerRoute is meant to give a developer more granular control over which custom routes a WP client instance supports for any given site. In this way the default (no HTTP request needed, contains all built-in routes) client's route support can be augmented case-by-case with specific additional routes, as opposed to starting with the "auto-make me a handler for every detected route" approach represented by the impending auto-discovery functionality (which will depend on querying your site or otherwise importing a JSON export from it)

@gnarf
Copy link
Collaborator

gnarf commented Jun 16, 2016

I think I like this API more than "auto detect by query endpoint"

Can you still pass an "api description" object to some endpoint to force the "auto-build" behavior?

@jasonphillips
Copy link
Contributor

This supersedes both #144 and #158 by providing a method that developers can use to arbitrarily support any endpoint.

Do I understand correctly that the download-endpoint-json function will still exist alongside this new option to register routes directly? I've used the prior method in the last couple of days (generating a local json file using your method) and it is particularly useful for my case of running automated tests against the current demo.wp-api.org, which is an always moving target as their development proceeds.

@kadamwhite
Copy link
Collaborator Author

@jasonphillips correct, I do not plan for that to go anywhere, because it is still an integral component of maintaining this library in concert with the API itself. In fact the goal is to have it be even easier.

I think I like this API more than "auto detect by query endpoint"

Can you still pass an "api description" object to some endpoint to force the "auto-build" behavior?

@gnarf The goal is to have three interfaces for querying an arbitrary endpoint; I'd love your thoughts on whether this is over-extending, but here's the plan:

  1. Create a WP instance that is custom-configured for a JSON endpoint object specifying many routes. Any functions derived from the routes list will be available. This will support three modes:
    • Default/automatic, where the parsing will happen under the hood in the default case to configure the query builders for the default routes
    • Bootstrapping, where an existing JSON (or plain JS) object specifying routes can be passed to a configuration method on WP to generate a configured site client instance
    • Discovery, where a method on WP can be called with a URL to asynchronously query for an API endpoint and download the JSON endpoint data: This path would return a configured site client instance to the user via a callback or a promise
  2. Augment an existing WP instance with a set of routes, using the same plumbing put in place in Dynamically generate endpoint handlers based on schema #145: basically, give it an array of route objects (likely copied from the JSON output from an endpoint) following the convention established by the wp-json root endpoint response, and those routes will added to the WP instance's capabilities
  3. use this registerRoute method to programmatically create a specific, individual route handler function.

I see these as being interrelated and being all three useful in their own way, but the purpose of this thread is to hold up that assertion for critique! Input welcome.

@kadamwhite
Copy link
Collaborator Author

Got a positive review in slack from @joehoyle, and have not heard any negative feedback, so we're going to keep moving forward!

This supersedes both #144 and #158 by providing a method that developers can use to arbitrarily support any endpoint.

---------------------------------------

Support for Custom Post Types is provided via the `.registerRoute` method. This method returns a handler function which can be assigned to your site instance as a method, and takes the [same namespace and route string arguments as `rest_register_route`](http://v2.wp-api.org/extending/adding/#bare-basics):

```js
var site = new WP({ endpoint: 'http://www.yoursite.com/wp-json' });
site.myCustomResource = site.registerRoute( 'myplugin/v1', '/author/(?P<id>)' );
site.myCustomResource().id( 17 ); // => myplugin/v1/author/17
```

The string `(?P<id>)` indicates that a level of the route for this resource is a dynamic property named ID. By default, properties identified in this fashion will not have any inherent validation. This is designed to give developers the flexibility to pass in anything, with the caveat that only valid IDs will be accepted on the WordPress end.

You might notice that in the example from the official WP-API documentation, a pattern is specified with a different format: this is a [regular expression](http://www.regular-expressions.info/tutorial.html) designed to validate the values that may be used for this capture group.
```js
var site = new WP({ endpoint: 'http://www.yoursite.com/wp-json' });
site.myCustomResource = site.registerRoute( 'myplugin/v1', '/author/(?P<id>\\d+)' );
site.myCustomResource().id( 7 ); // => myplugin/v1/author/7
site.myCustomResource().id( 'foo' ); // => Error: Invalid path component: foo does not match (?P<a>\d+)
```
Adding the regular expression pattern (as a string) enabled validation for this component. In this case, the `\\d+` will cause only _numeric_ values to be accepted.

**NOTE THE DOUBLE-SLASHES** in the route definition here, however: `'/author/(?P<id>\\d+)'` This is a JavaScript string, where `\` _must_ be written as `\\` to be parsed properly. A single backslash will break the route's validation.

Each named group in the route will be converted into a named setter method on the route handler, as in `.id()` in the example above: that name is taken from the `<id>` in the route string.

The route string `'pages/(?P<parentPage>[\d]+)/revisions/(?P<id>[\d]+)'` would create the setters `.parentPage()` and `id()`, permitting any permutation of the provided URL to be created.

To permit custom parameter support methods on custom endpoints, a configuration object may be passed to the `registerRoute` method with a `mixins` property defining any functions to add:

```js
site.handler = site.registerRoute( 'myplugin/v1', 'collection/(?P<id>)', {
    mixins: {
        myParam: function( val ) {
            return this.param( 'my_param', val );
        }
    }
});
```
This permits a developer to extend an endpoint with arbitrary parameters in the same manner as is done for the automatically-generated built-in route handlers.

Auto-discovery of all available routes will be supported in the near future, as will re-utilizing existing mixins (like `.search()`) on custom routes.

----

Thank you to @jasonphillips, @joehoyle, @gnarf, @elyobo, @timmyc

Closes #158, closes #144 (superseded by this PR)
@kadamwhite kadamwhite force-pushed the register-custom-endpoint branch from 0d6634f to 0b4fbe8 Compare June 19, 2016 16:38
@kadamwhite kadamwhite merged commit 0b4fbe8 into master Jun 19, 2016
@kadamwhite kadamwhite deleted the register-custom-endpoint branch June 19, 2016 16:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants