Skip to content

Conversation

@kadamwhite
Copy link
Collaborator

This begins to address #140, by implementing an .endpoint method that will create and return a factory method which can create CollectionRequest instances against the provided endpoint.

Downsides to this approach:

  • Somewhat duplicative w/r/t .root()
  • Presumes that only resource(/:id) format collections will be used
    • Actually supporting an arbitrary structure of URL will eventually be necessary in order to support discovery-based generation; however, at present we haven't worked out a solid approach for parsing PCRE named groups.

Upsides:

  • Provides a vector to reintroduce .registerType very cleanly
  • The move towards defining filter methods as independent modules will make sharing functionality between endpoints much easier!

The current plan is to merge this, get feedback, and iterate prior to making a formal decision on supporting this or using an alternative approach prior to releasing v0.7.

This begins to address #140, by implementing an .endpoint method
that will create and return a factory method which can create
CollectionRequest instances against the provided endpoint.

Downsides to this approach:

- Somewhat duplicative w/r/t .root()
- Presumes that only resource(/:id) format collections will be used
  - Actually supporting an arbitrary structure of URL will eventually
    be necessary in order to support discovery-based generation; however,
    at present we haven't worked out a solid approach for parsing PCRE
    named groups.

Upsides:

- Provides a vector to reintroduce .registerType very cleanly

The current plan is to merge this, get feedback, and iterate prior to
making a formal decision on supporting this or using an alternative
approach prior to releasing v0.7.
* wp.myPluginResources().id( 7 ).then( // ...
*
* @method endpoint
* @param {Object} [options] An options hash for a new MediaRequest
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should both of the above lines be updated to new CollectionRequest and A CollectionRequest instance?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They ought to, yes :)

@timmyc
Copy link

timmyc commented Feb 8, 2016

I like this approach and the option of supporting custom endpoints was a question I was about to ask in slack just now 👍

I do think it still might be nice to expose a method for performing ad/hoc auth'ed requests via the library. In wpcom.js .req is exposed on the base object for GET'ing or POST'ing random endpoints. This comes in handy when prototyping new endpoints and also for endpoints that don't completely conform to a collection setup.

@kadamwhite
Copy link
Collaborator Author

@timmyc I think arbitrary queries w/out collection context should be possible, but I'll look at .req and try to put together a demo of the potential usage here for comparison's sake.

I'm curious to sound out your (and @jmeas', among others) thoughts on whether the above approach could/should be adjusted to support parsing a route definition regex. For example, if you define a route in the WP API:

register_rest_route( 'myplugin/v1', '/author/(?P<id>\d+)', array( // ...

you could then

wp.authors = wp.endpoint( '/author/(?P<id>\d+)' );
// .id() method is created and bound with a regex parameter validator
wp.authors().id( 72 ).get().//...

The benefit I see in using the regex for route creation (and this wouldn't preclude querying an arbitrary endpoint defined purely as a string) sets us up to eliminate the hard-coded .posts, etc handlers in favor of dynamically generating handlers for every set of endpoints based on the JSON schema returned from the API root, which would enable discovery/auto-generation that could work with any site, even if the site had moved or altered the endpoint locations. It also absolves us of having to manually specify handlers for all URL components: The posts() collection provides an id method while the types endpoint handler would provide a type method (/wp/v2/types/(?P<type>[\\w-]+)), and we can generate those ourselves. Route regex parsing is not trivial, but the alternative is that to register a handler for custom routes, especially if they're nested like post revisions are, you'd need to pass not just an endpoint string but an object of parameter specification methods with their corresponding validators. That seems clunky, and I feel the route parsing option would be more elegant/easy to use. (Especially since in the discovery context it'd be completely hidden from a user)

@timmyc
Copy link

timmyc commented Feb 9, 2016

The route parsing / auto-discovery does sound pretty interesting, and would work well with collection-type endpoints. I also totally agree that nested endpoints could be fun. For the auto-discovery path, is there already a request that is fired off when the library loads that would perform this operation?

As-is I think this PR provides a great way to handle collection type endpoints.

Let me know if you have any questions regarding the .req approach taken in wpcom.js

@elyobo
Copy link
Contributor

elyobo commented Apr 15, 2016

What's the latest on this (or on #158)?

kadamwhite added a commit that referenced this pull request Jun 15, 2016
Dynamically generate endpoint handlers based on schema

This is an alternative philosophy than the approach in #144, whereby
instead of manually configuring a route, the client auto-discovers all
possible endpoints and dynamically generates handlers from the route
and schema data. This should be considered heavily WIP, but after
discussions with @jmeas and @adamsilverstein I believe that dynamically
creating a handler by parsing the route definition strings will be a
more future-friendly way to create a dynamic route generation method.

This PR iterates on this idea to replicate all of the internal path-
specific methods (`.posts().id( # )` for example) dynamically by
consuming and parsing the root WP-API endpoint's response data:

![image](https://cloud.githubusercontent.com/assets/442115/12980849/3b9d0c02-d0ac-11e5-9e18-380762977ccf.png)

Key changes:

- Include the JSON response of the /wp-json in the library
- Rather than manually specifying each endpoint handler (e.g. define a
  PostsRequest class, then define wp.posts() factory), deduce handlers
  for all available endpoints from the routes property within the
  /wp-json endpoint response object
- Handle application of parameter and filter convenience methods as
  mixins applied based on endpoint, not base functionality of
  CollectionsRequest or individual endpoint handlers
- Remove CollectionsRequest entirely in favor of WPRequest and mixins
@kadamwhite
Copy link
Collaborator Author

@elyobo The latest is that #145 has merged, and autodiscovery logic and a custom endpoint support method leveraging the same URL-parsing infrastructure are in the works this week: my WCEU speaker deadline means I can't put off finishing the work any further :) So, soon! Apologies for the delay

kadamwhite added a commit that referenced this pull request Jun 16, 2016
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.
@kadamwhite
Copy link
Collaborator Author

Provisionally superseded by #176, input requested on that PR!

@kadamwhite kadamwhite deleted the support-arbitrary-endpoints-140 branch June 19, 2016 16:42
@kadamwhite
Copy link
Collaborator Author

#176 has merged

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants