Skip to content

Commit

Permalink
Add a new @wordpress/api-request package (#7018)
Browse files Browse the repository at this point in the history
* Add a wordpress/api-request package

* Add the middlewares API

* Fix unit tests

* Adding unit tests

* Adding internal dependencies comment

* Improve unit tests

* Restore wpApiSettings global for wp-api

* Lint package.json

* Align jQuery versions
  • Loading branch information
youknowriad authored Jun 8, 2018
1 parent a60b0f2 commit 8ec748a
Show file tree
Hide file tree
Showing 34 changed files with 580 additions and 197 deletions.
4 changes: 4 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ module.exports = {
selector: 'ImportDeclaration[source.value=/^@wordpress\\u002F.+\\u002F/]',
message: 'Path access on WordPress dependencies is not allowed.',
},
{
selector: 'ImportDeclaration[source.value=/^api-request$/]',
message: 'Use @wordpress/api-request as import path instead.',
},
{
selector: 'ImportDeclaration[source.value=/^blob$/]',
message: 'Use @wordpress/blob as import path instead.',
Expand Down
7 changes: 6 additions & 1 deletion components/higher-order/with-api-data/request.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@
import memoize from 'memize';
import { mapKeys } from 'lodash';

/**
* WordPress dependencies
*/
import apiRequest from '@wordpress/api-request';

export const getStablePath = memoize( ( path ) => {
const [ base, query ] = path.split( '?' );
if ( ! query ) {
Expand Down Expand Up @@ -75,7 +80,7 @@ export function getCachedResponse( request ) {
}

export function getResponseFromNetwork( request ) {
const promise = wp.apiRequest( request )
const promise = apiRequest( request )
.then( ( body, status, xhr ) => {
return {
body,
Expand Down
27 changes: 15 additions & 12 deletions components/higher-order/with-api-data/test/request.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/**
* WordPress dependencies
*/
import apiRequest from '@wordpress/api-request';

/**
* Internal dependencies
*/
Expand Down Expand Up @@ -25,15 +30,13 @@ describe( 'request', () => {
),
};

let wpApiRequest;
beforeEach( () => {
getStablePath.clear();
for ( const key in cache ) {
delete cache[ key ];
}

wpApiRequest = wp.apiRequest;
wp.apiRequest = jest.fn( () => ( {
apiRequest.mockReturnValue = {
// jQuery.Deferred aren't true promises, particularly in their
// treatment of resolved arguments. $.ajax will spread resolved
// arguments, but this is not valid for Promise (only single).
Expand All @@ -43,11 +46,7 @@ describe( 'request', () => {
'success',
xhr
) ),
} ) );
} );

afterEach( () => {
wp.apiRequest = wpApiRequest;
};
} );

describe( 'getResponseHeaders()', () => {
Expand Down Expand Up @@ -97,7 +96,7 @@ describe( 'request', () => {
} );

return awaitResponse.then( ( data ) => {
expect( wp.apiRequest ).toHaveBeenCalled();
expect( apiRequest ).toHaveBeenCalled();
expect( data ).toEqual( actualResponse );
} );
} );
Expand Down Expand Up @@ -129,6 +128,10 @@ describe( 'request', () => {
} );

describe( 'request()', () => {
beforeEach( () => {
apiRequest.mockClear();
} );

it( 'should try from cache for GET', () => {
cache[ getStablePath( '/wp?c=5&a=5&b=5' ) ] = actualResponse;
const awaitResponse = request( {
Expand All @@ -137,7 +140,7 @@ describe( 'request', () => {
} );

return awaitResponse.then( ( data ) => {
expect( wp.apiRequest ).not.toHaveBeenCalled();
expect( apiRequest ).not.toHaveBeenCalled();
expect( data ).toEqual( actualResponse );
} );
} );
Expand All @@ -150,7 +153,7 @@ describe( 'request', () => {
} );

return awaitResponse.then( ( data ) => {
expect( wp.apiRequest ).toHaveBeenCalled();
expect( apiRequest ).toHaveBeenCalled();
expect( data ).toEqual( actualResponse );
} );
} );
Expand All @@ -162,7 +165,7 @@ describe( 'request', () => {
} );

return awaitResponse.then( ( data ) => {
expect( wp.apiRequest ).toHaveBeenCalled();
expect( apiRequest ).toHaveBeenCalled();
expect( data ).toEqual( actualResponse );
} );
} );
Expand Down
3 changes: 2 additions & 1 deletion core-blocks/embed/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
BlockAlignmentToolbar,
RichText,
} from '@wordpress/editor';
import apiRequest from '@wordpress/api-request';

/**
* Internal dependencies
Expand All @@ -30,7 +31,7 @@ import './editor.scss';
const HOSTS_NO_PREVIEWS = [ 'facebook.com' ];

// Caches the embed API calls, so if blocks get transformed, or deleted and added again, we don't spam the API.
const wpEmbedAPI = memoize( ( url ) => wp.apiRequest( { path: `/oembed/1.0/proxy?${ stringify( { url } ) }` } ) );
const wpEmbedAPI = memoize( ( url ) => apiRequest( { path: `/oembed/1.0/proxy?${ stringify( { url } ) }` } ) );

const matchesPatterns = ( url, patterns = [] ) => {
return patterns.some( ( pattern ) => {
Expand Down
10 changes: 0 additions & 10 deletions edit-post/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,6 @@ import store from './store';
import { initializeMetaBoxState } from './store/actions';
import Editor from './editor';

/**
* Configure heartbeat to refresh the wp-api nonce, keeping the editor
* authorization intact.
*/
window.jQuery( document ).on( 'heartbeat-tick', ( event, response ) => {
if ( response[ 'rest-nonce' ] ) {
window.wpApiSettings.nonce = response[ 'rest-nonce' ];
}
} );

/**
* Reinitializes the editor after the user chooses to reboot the editor after
* an unhandled error occurs, replacing previously mounted editor element using
Expand Down
3 changes: 2 additions & 1 deletion edit-post/store/effects.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { reduce, some } from 'lodash';
import { select, subscribe } from '@wordpress/data';
import { speak } from '@wordpress/a11y';
import { __ } from '@wordpress/i18n';
import apiRequest from '@wordpress/api-request';

/**
* Internal dependencies
Expand Down Expand Up @@ -98,7 +99,7 @@ const effects = {
additionalData.forEach( ( [ key, value ] ) => formData.append( key, value ) );

// Save the metaboxes
wp.apiRequest( {
apiRequest( {
url: window._wpMetaBoxUrl,
method: 'POST',
processData: false,
Expand Down
7 changes: 6 additions & 1 deletion editor/components/autocompleters/user.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/**
* WordPress dependencies
*/
import apiRequest from '@wordpress/api-request';

/**
* A user mentions completer.
*
Expand All @@ -12,7 +17,7 @@ export default {
if ( search ) {
payload = '?search=' + encodeURIComponent( search );
}
return wp.apiRequest( { path: '/wp/v2/users' + payload } );
return apiRequest( { path: '/wp/v2/users' + payload } );
},
isDebounced: true,
getOptionKeywords( user ) {
Expand Down
7 changes: 4 additions & 3 deletions editor/components/post-taxonomies/flat-term-selector.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { __, _x, sprintf } from '@wordpress/i18n';
import { Component, compose } from '@wordpress/element';
import { FormTokenField, withAPIData } from '@wordpress/components';
import { withSelect, withDispatch } from '@wordpress/data';
import apiRequest from '@wordpress/api-request';

/**
* Module constants
Expand Down Expand Up @@ -75,7 +76,7 @@ class FlatTermSelector extends Component {
fetchTerms( params = {} ) {
const query = { ...DEFAULT_QUERY, ...params };
const basePath = wp.api.getTaxonomyRoute( this.props.slug );
const request = wp.apiRequest( { path: `/wp/v2/${ basePath }?${ stringify( query ) }` } );
const request = apiRequest( { path: `/wp/v2/${ basePath }?${ stringify( query ) }` } );
request.then( ( terms ) => {
this.setState( ( state ) => ( {
availableTerms: state.availableTerms.concat(
Expand Down Expand Up @@ -106,15 +107,15 @@ class FlatTermSelector extends Component {
return new Promise( ( resolve, reject ) => {
// Tries to create a term or fetch it if it already exists
const basePath = wp.api.getTaxonomyRoute( this.props.slug );
wp.apiRequest( {
apiRequest( {
path: `/wp/v2/${ basePath }`,
method: 'POST',
data: { name: termName },
} ).then( resolve, ( xhr ) => {
const errorCode = xhr.responseJSON && xhr.responseJSON.code;
if ( errorCode === 'term_exists' ) {
// search the new category created since last fetch
this.addRequest = wp.apiRequest( {
this.addRequest = apiRequest( {
path: `/wp/v2/${ basePath }?${ stringify( { ...DEFAULT_QUERY, search: termName } ) }`,
} );
return this.addRequest.then( ( searchResult ) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { Component, compose } from '@wordpress/element';
import { TreeSelect, withAPIData, withInstanceId, withSpokenMessages, Button } from '@wordpress/components';
import { buildTermsTree } from '@wordpress/utils';
import { withSelect, withDispatch } from '@wordpress/data';
import apiRequest from '@wordpress/api-request';

/**
* Module Constants
Expand Down Expand Up @@ -103,7 +104,7 @@ class HierarchicalTermSelector extends Component {
} );
// Tries to create a term or fetch it if it already exists
const basePath = wp.api.getTaxonomyRoute( this.props.slug );
this.addRequest = wp.apiRequest( {
this.addRequest = apiRequest( {
path: `/wp/v2/${ basePath }`,
method: 'POST',
data: {
Expand All @@ -116,7 +117,7 @@ class HierarchicalTermSelector extends Component {
const errorCode = xhr.responseJSON && xhr.responseJSON.code;
if ( errorCode === 'term_exists' ) {
// search the new category created since last fetch
this.addRequest = wp.apiRequest( {
this.addRequest = apiRequest( {
path: `/wp/v2/${ basePath }?${ stringify( { ...DEFAULT_QUERY, parent: formParent || 0, search: formName } ) }`,
} );
return this.addRequest.then( ( searchResult ) => {
Expand Down Expand Up @@ -161,7 +162,7 @@ class HierarchicalTermSelector extends Component {

componentDidMount() {
const basePath = wp.api.getTaxonomyRoute( this.props.slug );
this.fetchRequest = wp.apiRequest( { path: `/wp/v2/${ basePath }?${ stringify( DEFAULT_QUERY ) }` } );
this.fetchRequest = apiRequest( { path: `/wp/v2/${ basePath }?${ stringify( DEFAULT_QUERY ) }` } );
this.fetchRequest.then(
( terms ) => { // resolve
const availableTermsTree = buildTermsTree( terms );
Expand Down
3 changes: 2 additions & 1 deletion editor/components/url-input/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { __, sprintf, _n } from '@wordpress/i18n';
import { Component, Fragment } from '@wordpress/element';
import { keycodes, decodeEntities } from '@wordpress/utils';
import { Spinner, withInstanceId, withSpokenMessages, Popover } from '@wordpress/components';
import apiRequest from '@wordpress/api-request';

const { UP, DOWN, ENTER } = keycodes;

Expand Down Expand Up @@ -68,7 +69,7 @@ class UrlInput extends Component {
selectedSuggestion: null,
loading: true,
} );
this.suggestionsRequest = wp.apiRequest( {
this.suggestionsRequest = apiRequest( {
path: `/wp/v2/posts?${ stringify( {
search: value,
per_page: 20,
Expand Down
17 changes: 9 additions & 8 deletions editor/store/effects.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
} from '@wordpress/blocks';
import { __ } from '@wordpress/i18n';
import { speak } from '@wordpress/a11y';
import apiRequest from '@wordpress/api-request';

/**
* Internal dependencies
Expand Down Expand Up @@ -130,7 +131,7 @@ export default {
parent: post.id,
};

request = wp.apiRequest( {
request = apiRequest( {
path: `/wp/v2/${ basePath }/${ post.id }/autosaves`,
method: 'POST',
data: toSend,
Expand All @@ -145,7 +146,7 @@ export default {
dispatch( removeNotice( SAVE_POST_NOTICE_ID ) );
dispatch( removeNotice( AUTOSAVE_POST_NOTICE_ID ) );

request = wp.apiRequest( {
request = apiRequest( {
path: `/wp/v2/${ basePath }/${ post.id }`,
method: 'PUT',
data: toSend,
Expand Down Expand Up @@ -251,7 +252,7 @@ export default {
const { postId } = action;
const basePath = wp.api.getPostTypeRoute( getCurrentPostType( getState() ) );
dispatch( removeNotice( TRASH_POST_NOTICE_ID ) );
wp.apiRequest( { path: `/wp/v2/${ basePath }/${ postId }`, method: 'DELETE' } ).then(
apiRequest( { path: `/wp/v2/${ basePath }/${ postId }`, method: 'DELETE' } ).then(
() => {
dispatch( {
...action,
Expand Down Expand Up @@ -294,7 +295,7 @@ export default {
context: 'edit',
};

wp.apiRequest( { path: `/wp/v2/${ basePath }/${ post.id }`, data } ).then(
apiRequest( { path: `/wp/v2/${ basePath }/${ post.id }`, data } ).then(
( newPost ) => {
dispatch( resetPost( newPost ) );
}
Expand Down Expand Up @@ -439,9 +440,9 @@ export default {

let result;
if ( id ) {
result = wp.apiRequest( { path: `/wp/v2/${ basePath }/${ id }` } );
result = apiRequest( { path: `/wp/v2/${ basePath }/${ id }` } );
} else {
result = wp.apiRequest( { path: `/wp/v2/${ basePath }?per_page=-1` } );
result = apiRequest( { path: `/wp/v2/${ basePath }?per_page=-1` } );
}

result.then(
Expand Down Expand Up @@ -494,7 +495,7 @@ export default {
const path = isTemporary ? `/wp/v2/${ basePath }` : `/wp/v2/${ basePath }/${ id }`;
const method = isTemporary ? 'POST' : 'PUT';

wp.apiRequest( { path, data, method } ).then(
apiRequest( { path, data, method } ).then(
( updatedSharedBlock ) => {
dispatch( {
type: 'SAVE_SHARED_BLOCK_SUCCESS',
Expand Down Expand Up @@ -550,7 +551,7 @@ export default {
sharedBlock.uid,
] ) );

wp.apiRequest( { path: `/wp/v2/${ basePath }/${ id }`, method: 'DELETE' } ).then(
apiRequest( { path: `/wp/v2/${ basePath }/${ id }`, method: 'DELETE' } ).then(
() => {
dispatch( {
type: 'DELETE_SHARED_BLOCK_SUCCESS',
Expand Down
Loading

0 comments on commit 8ec748a

Please sign in to comment.