From 8ec46b8912dadbb823bc0fbdf50a895655011b9f Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Wed, 30 May 2018 11:50:06 +0100 Subject: [PATCH] Add a wordpress/api-request package --- .eslintrc.js | 4 ++ lib/client-assets.php | 13 +++++ packages/api-request/.npmrc | 1 + packages/api-request/README.md | 23 +++++++++ packages/api-request/package.json | 28 +++++++++++ packages/api-request/src/index.js | 84 +++++++++++++++++++++++++++++++ test/unit/jest.config.json | 2 +- webpack.config.js | 6 +-- 8 files changed, 155 insertions(+), 6 deletions(-) create mode 100644 packages/api-request/.npmrc create mode 100644 packages/api-request/README.md create mode 100644 packages/api-request/package.json create mode 100644 packages/api-request/src/index.js diff --git a/.eslintrc.js b/.eslintrc.js index cba3ab35ac3868..ce011836119688 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -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.', diff --git a/lib/client-assets.php b/lib/client-assets.php index 71be6a780ef12e..7afeffad4da25b 100644 --- a/lib/client-assets.php +++ b/lib/client-assets.php @@ -115,6 +115,19 @@ function gutenberg_register_scripts_and_styles() { ); // Editor Scripts. + wp_deregister_script( 'wp-api-request' ); + wp_register_script( + 'wp-api-request', + gutenberg_url( 'build/api-request/index.js' ), + array(), + filemtime( gutenberg_dir_path() . 'build/api-request/index.js' ), + true + ); + wp_localize_script( 'wp-api-request', 'wpApiSettings', array( + 'root' => esc_url_raw( get_rest_url() ), + 'nonce' => ( wp_installing() && ! is_multisite() ) ? '' : wp_create_nonce( 'wp_rest' ), + 'versionString' => 'wp/v2/', + ) ); wp_register_script( 'wp-deprecated', gutenberg_url( 'build/deprecated/index.js' ), diff --git a/packages/api-request/.npmrc b/packages/api-request/.npmrc new file mode 100644 index 00000000000000..43c97e719a5a82 --- /dev/null +++ b/packages/api-request/.npmrc @@ -0,0 +1 @@ +package-lock=false diff --git a/packages/api-request/README.md b/packages/api-request/README.md new file mode 100644 index 00000000000000..6e6a708834e8dd --- /dev/null +++ b/packages/api-request/README.md @@ -0,0 +1,23 @@ +# @wordpress/blob + +Wrapper around `jQuery.ajax` to call WordPress REST APIs. + +## Installation + +Install the module + +```bash +npm install @wordpress/api-request --save +``` + +## Usage + +```js +import apiRequest from '@wordpress/api-request'; + +apiRequest( { path: '/wp/v2/posts' } ).then( posts => { + console.log( posts ); +} ); +``` + +

Code is Poetry.

diff --git a/packages/api-request/package.json b/packages/api-request/package.json new file mode 100644 index 00000000000000..50d0f35614ce27 --- /dev/null +++ b/packages/api-request/package.json @@ -0,0 +1,28 @@ +{ + "name": "@wordpress/api-request", + "version": "1.0.0", + "description": "Utility to call WordPress REST APIs", + "author": "WordPress", + "license": "GPL-2.0-or-later", + "keywords": [ + "wordpress", + "rest-api", + "fetch" + ], + "homepage": "https://github.com/WordPress/gutenberg/tree/master/packages/api-request/README.md", + "repository": { + "type": "git", + "url": "https://github.com/WordPress/gutenberg.git" + }, + "bugs": { + "url": "https://github.com/WordPress/gutenberg/issues" + }, + "main": "build/index.js", + "module": "build-module/index.js", + "publishConfig": { + "access": "public" + }, + "dependencies": { + "jquery": "^3.3.1" + } +} diff --git a/packages/api-request/src/index.js b/packages/api-request/src/index.js new file mode 100644 index 00000000000000..2641359d9b08bd --- /dev/null +++ b/packages/api-request/src/index.js @@ -0,0 +1,84 @@ +/** + * External dependencies + */ +import jQuery from 'jquery'; + +const wpApiSettings = window.wpApiSettings; + +function apiRequest( options ) { + options = apiRequest.buildAjaxOptions( options ); + return apiRequest.transport( options ); +} + +apiRequest.buildAjaxOptions = function( options ) { + let url = options.url; + let path = options.path; + let namespaceTrimmed, endpointTrimmed, apiRoot; + let headers, addNonceHeader, headerName; + + if ( + typeof options.namespace === 'string' && + typeof options.endpoint === 'string' + ) { + namespaceTrimmed = options.namespace.replace( /^\/|\/$/g, '' ); + endpointTrimmed = options.endpoint.replace( /^\//, '' ); + if ( endpointTrimmed ) { + path = namespaceTrimmed + '/' + endpointTrimmed; + } else { + path = namespaceTrimmed; + } + } + if ( typeof path === 'string' ) { + apiRoot = wpApiSettings.root; + path = path.replace( /^\//, '' ); + + // API root may already include query parameter prefix if site is + // configured to use plain permalinks. + if ( 'string' === typeof apiRoot && -1 !== apiRoot.indexOf( '?' ) ) { + path = path.replace( '?', '&' ); + } + + url = apiRoot + path; + } + + // If ?_wpnonce=... is present, no need to add a nonce header. + addNonceHeader = ! ( options.data && options.data._wpnonce ); + + headers = options.headers || {}; + + // If an 'X-WP-Nonce' header (or any case-insensitive variation + // thereof) was specified, no need to add a nonce header. + if ( addNonceHeader ) { + for ( headerName in headers ) { + if ( headers.hasOwnProperty( headerName ) ) { + if ( headerName.toLowerCase() === 'x-wp-nonce' ) { + addNonceHeader = false; + break; + } + } + } + } + + if ( addNonceHeader ) { + // Do not mutate the original headers object, if any. + headers = jQuery.extend( { + 'X-WP-Nonce': wpApiSettings.nonce, + }, headers ); + } + + // Do not mutate the original options object. + options = jQuery.extend( {}, options, { + headers: headers, + url: url, + } ); + + delete options.path; + delete options.namespace; + delete options.endpoint; + + return options; +}; + +apiRequest.transport = jQuery.ajax; + +export default apiRequest; diff --git a/test/unit/jest.config.json b/test/unit/jest.config.json index 1bd5665d0ba99c..563d83dd46cb9b 100644 --- a/test/unit/jest.config.json +++ b/test/unit/jest.config.json @@ -6,7 +6,7 @@ ], "moduleNameMapper": { "@wordpress\\/(blocks|components|editor|data|utils|edit-post|viewport|plugins|core-data|core-blocks)$": "$1", - "@wordpress\\/(blob|date|dom|deprecated|element)$": "packages/$1/src" + "@wordpress\\/(api-request|blob|date|dom|deprecated|element)$": "packages/$1/src" }, "preset": "@wordpress/jest-preset-default", "setupFiles": [ diff --git a/webpack.config.js b/webpack.config.js index 3e4d766f0f1ded..c7f497475ab451 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -141,6 +141,7 @@ const gutenbergPackages = [ 'deprecated', 'dom', 'element', + 'api-request', ]; const wordPressPackages = [ @@ -151,10 +152,6 @@ const wordPressPackages = [ 'is-shallow-equal', ]; -const coreGlobals = [ - 'api-request', -]; - const externals = { react: 'React', 'react-dom': 'ReactDOM', @@ -169,7 +166,6 @@ const externals = { ...entryPointNames, ...gutenbergPackages, ...wordPressPackages, - ...coreGlobals, ].forEach( ( name ) => { externals[ `@wordpress/${ name }` ] = { this: [ 'wp', camelCaseDash( name ) ],