From f54b1461acaabe31c6a343a3817deb1383c2efef Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Tue, 16 May 2017 16:34:22 +0000 Subject: [PATCH] REST API: JS Client - Enable connecting to multiple endpoints. Enable connecting to multiple wp-api `endpoints`. Calling `wp.api.init` with a new `apiRoot` will parse the new endpoint's schema and store a new set of models and collections. A collection of connected endpoints is stored in `wp.api.endpoints`. Props lucasstark. Fixes #39683. Merges [40364] to the 4.7 branch. git-svn-id: https://develop.svn.wordpress.org/branches/4.7@40735 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/js/wp-api.js | 34 ++++++++++++++----------- tests/qunit/fixtures/wp-api.js | 6 +++-- tests/qunit/wp-includes/js/wp-api.js | 37 +++++++++++++++++++++++++--- 3 files changed, 57 insertions(+), 20 deletions(-) diff --git a/src/wp-includes/js/wp-api.js b/src/wp-includes/js/wp-api.js index 0ce6bbce09..3f950a47f5 100644 --- a/src/wp-includes/js/wp-api.js +++ b/src/wp-includes/js/wp-api.js @@ -1126,8 +1126,8 @@ /** * Tracking objects for models and collections. */ - loadingObjects.models = routeModel.get( 'models' ); - loadingObjects.collections = routeModel.get( 'collections' ); + loadingObjects.models = {}; + loadingObjects.collections = {}; _.each( routeModel.schemaModel.get( 'routes' ), function( route, index ) { @@ -1310,7 +1310,9 @@ loadingObjects.collections[ collectionClassName ] = wp.api.WPApiBaseCollection.extend( { // For the url of a root level collection, use a string. - url: routeModel.get( 'apiRoot' ) + routeModel.get( 'versionString' ) + routeName, + url: function() { + return routeModel.get( 'apiRoot' ) + routeModel.get( 'versionString' ) + routeName; + }, // Specify the model that this collection contains. model: function( attrs, options ) { @@ -1337,13 +1339,15 @@ loadingObjects.models[ index ] = wp.api.utils.addMixinsAndHelpers( model, index, loadingObjects ); } ); + // Set the routeModel models and collections. + routeModel.set( 'models', loadingObjects.models ); + routeModel.set( 'collections', loadingObjects.collections ); + } } ); - wp.api.endpoints = new Backbone.Collection( { - model: Endpoint - } ); + wp.api.endpoints = new Backbone.Collection(); /** * Initialize the wp-api, optionally passing the API root. @@ -1357,28 +1361,30 @@ var endpoint, attributes = {}, deferred, promise; args = args || {}; - attributes.apiRoot = args.apiRoot || wpApiSettings.root; - attributes.versionString = args.versionString || wpApiSettings.versionString; + attributes.apiRoot = args.apiRoot || wpApiSettings.root || '/wp-json'; + attributes.versionString = args.versionString || wpApiSettings.versionString || 'wp/v2/'; attributes.schema = args.schema || null; if ( ! attributes.schema && attributes.apiRoot === wpApiSettings.root && attributes.versionString === wpApiSettings.versionString ) { attributes.schema = wpApiSettings.schema; } if ( ! initializedDeferreds[ attributes.apiRoot + attributes.versionString ] ) { - endpoint = wp.api.endpoints.findWhere( { apiRoot: attributes.apiRoot, versionString: attributes.versionString } ); + + // Look for an existing copy of this endpoint + endpoint = wp.api.endpoints.findWhere( { 'apiRoot': attributes.apiRoot, 'versionString': attributes.versionString } ); if ( ! endpoint ) { endpoint = new Endpoint( attributes ); - wp.api.endpoints.add( endpoint ); } deferred = jQuery.Deferred(); promise = deferred.promise(); - endpoint.schemaConstructed.done( function( endpoint ) { + endpoint.schemaConstructed.done( function( resolvedEndpoint ) { + wp.api.endpoints.add( resolvedEndpoint ); // Map the default endpoints, extending any already present items (including Schema model). - wp.api.models = _.extend( endpoint.get( 'models' ), wp.api.models ); - wp.api.collections = _.extend( endpoint.get( 'collections' ), wp.api.collections ); - deferred.resolveWith( wp.api, [ endpoint ] ); + wp.api.models = _.extend( wp.api.models, resolvedEndpoint.get( 'models' ) ); + wp.api.collections = _.extend( wp.api.collections, resolvedEndpoint.get( 'collections' ) ); + deferred.resolve( resolvedEndpoint ); } ); initializedDeferreds[ attributes.apiRoot + attributes.versionString ] = promise; } diff --git a/tests/qunit/fixtures/wp-api.js b/tests/qunit/fixtures/wp-api.js index d9d0804c89..c28486d421 100644 --- a/tests/qunit/fixtures/wp-api.js +++ b/tests/qunit/fixtures/wp-api.js @@ -32,12 +32,14 @@ var pathToData = { * * @param {object} param The parameters sent to the ajax request. * - * @return {Object} A jQuery defered object that resolves with the mapped data. + * @return {Object} A jQuery deferred object that resolves with the mapped data. */ Backbone.ajax = function ( param ) { var data, - request = param.url.replace( 'http://localhost/', '' ); + request = param.url + .replace( 'http://remotehost/', '' ) + .replace( 'http://localhost/', '' ); if ( pathToData[ request ] ) { data = pathToData[ request ]; diff --git a/tests/qunit/wp-includes/js/wp-api.js b/tests/qunit/wp-includes/js/wp-api.js index acca46112e..180942fbce 100644 --- a/tests/qunit/wp-includes/js/wp-api.js +++ b/tests/qunit/wp-includes/js/wp-api.js @@ -192,10 +192,10 @@ } ); } ); -// Test the jswidget custom namespace and endpoints. -wp.api.init( { - 'versionString': 'js-widgets/v1/' -} ).done( function() { + // Test the jswidget custom namespace and endpoints. + wp.api.init( { + 'versionString': 'js-widgets/v1/' + } ).done( function() { var customClasses = [ 'WidgetsArchives', 'WidgetsCalendar', @@ -232,4 +232,33 @@ wp.api.init( { } ); + // Check connecting to a second URL. + wp.api.loadPromise.done( function() { + QUnit.test( 'Checking connecting to a remote url.' , function( assert ) { + var done = assert.async(); + + wp.api.init({ + 'apiRoot': 'http://remotehost/wp-json/' + } ).done( function(){ + var lastEndpoint = wp.api.endpoints.last(), + models = lastEndpoint.get( 'models' ), + post = new models.Post(); + + assert.equal( 'http://remotehost/wp-json/wp/v2/posts', post.url(), 'The remote API objects should have their own URLs' ); + + wp.api.init({ + 'apiRoot': 'http://localhost/wp-json/' + } ).done( function(){ + var lastEndpoint = wp.api.endpoints.first(), + models = lastEndpoint.get( 'models' ), + post = new models.Post(); + + assert.equal( 'http://localhost/wp-json/wp/v2/posts', post.url(), 'The local API objects should have their own URLs' ); + + done(); + } ); + } ); + } ); + }); + } )( window.QUnit );