-
Notifications
You must be signed in to change notification settings - Fork 4.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add a new @wordpress/api-request
package
#7018
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm really excited about the direction of moving wp global pieces into packages. However, I'm thinking it might be good to create a corresponding trac ticket so there's visibility there as well and also ensures that's being tracked for eventual merge from here?
packages/api-request/src/index.js
Outdated
*/ | ||
import jQuery from 'jquery'; | ||
|
||
const wpApiSettings = window.wpApiSettings; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would there be value in having a package that's dedicated to all options/settings etc passed through from the server? I'm thinking then you'd just do something like:
import { API_SETTINGS } from '@wordpress/settings';
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a leftover, I killed this global :)
Aside, I don't think a settings package would be a good thing, these settings are server-side data. An endpoint for these would be good, but until then. Providing config using wp_add_inline_script
calls is the way to go to keep the packages generic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OOh you're reviewing the first commit only ;)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lol ya I jumped on a bit early ha!
b4a2563
to
caa9ae9
Compare
da95f14
to
395286e
Compare
I'm not certain I understand why the e2e tests are completely failing in this PR. Locally they work, can someone take a look? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice work, I left some comments. I will try to run e2e test locally and is if they work.
.eslintrc.js
Outdated
@@ -26,7 +26,7 @@ module.exports = { | |||
'jest/globals': true, | |||
}, | |||
globals: { | |||
wpApiSettings: true, | |||
wpApiSchema: true, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any way to avoid using this global?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not at the moment, I believe the need for this will go away once we refactor our code to move away from withApiData
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, thanks for making it clear :)
@@ -0,0 +1,34 @@ | |||
import namespaceAndEndpointMiddleware from './namespace-endpoint'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: missing Internal dependencies
comment
@@ -0,0 +1,21 @@ | |||
import httpV1Middleware from '../http-v1'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: missing Internal dependencies comment
@@ -0,0 +1,18 @@ | |||
import namespaceEndpointMiddleware from '../namespace-endpoint'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: missing Internal dependencies comment
expect( options.endpoint ).toBeUndefined(); | ||
}; | ||
|
||
namespaceEndpointMiddleware( requestOptions, callback ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should add expect.hasAssertions call to make sure that callback
was executed.
expect( options ).toEqual( requestOptions ); | ||
}; | ||
|
||
httpV1Middleware( requestOptions, callback ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should add expect.hasAssertions call to both tests to make sure that callback
was executed.
expect( options.headers[ 'X-WP-Nonce' ] ).toBe( 'existing nonce' ); | ||
}; | ||
|
||
nonceMiddleware( requestOptions, callback ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should add expect.hasAssertions call to both tests to make sure that callback
was executed.
}; | ||
|
||
const response = prelooadingMiddleware( requestOptions ); | ||
response.then( ( value ) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think returning this statement will ensure that Promise got completed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not a regular promise (jQuery), so I went with the done
trick
expect( options.url ).toBe( 'http://wp.org/wp-admin/rest/wp/v2/posts' ); | ||
}; | ||
|
||
rootURLMiddleware( requestOptions, callback ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should add expect.hasAssertions call to make sure that callback
was executed.
I was able to reproduce it locally by running |
|
I took a look at this and am seeing a large blank space where the editor should be. In case it helps, I noticed a difference between this branch and master when executing the following line: On master, |
73114d2
to
5fd5112
Compare
Thanks for the hint @brandonpayton, so it looks like the On another topic, I tried to shim The Also, if we want to provide a way forward for people using I think we should merge this PR as is and tackle the deprecated in follow-ups. I also think It's not possible to accomodate both APIs at the same time. the best way to do it is to use another name for cc @aduth |
df19150
to
3767199
Compare
beforeEach( () => { | ||
getStablePath.clear(); | ||
for ( const key in cache ) { | ||
delete cache[ key ]; | ||
} | ||
|
||
wpApiRequest = wp.apiRequest; | ||
wp.apiRequest = jest.fn( () => ( { | ||
apiRequest.mockReturnValue = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This part becomes a bit magic since this module is being mocked in the setup file. Have you tried to use Manual Mocks using __mocks__
folder? If you do so you need to explicitly call jest.mock('./moduleName')
in your test file which is easier to follow.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried jest.mock('./moduleName', () => {})
but It didn't work. I'll take a look at the manual mocks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What seems to work for me is I put a __mocks__/moduleName
within the same path as the test (so test/__mocks__/moduleName/index.js
) and the mock is in the file then anything importing that module being tested will use the mock instead. Seems to work well for me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not that important at the moment, to be honest. Just wanted to make sure you are aware of other options. We can refactor later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I checked generated HTML for the page, it looks like wpApiSettings.schema
and wp.apiRequest.createPreloadingMiddleware
contain the same data. We probably should only use one of them.
packages/api-request/package.json
Outdated
"main": "build/index.js", | ||
"module": "build-module/index.js", | ||
"dependencies": { | ||
"jquery": "^3.3.1" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We use 3.2.1
version in the top level package.json
. We should align those two or Lerna will install another copy in the package subfolder.
wp_localize_script( 'wp-api', 'wpApiSettings', array( | ||
'root' => esc_url_raw( get_rest_url() ), | ||
'nonce' => ( wp_installing() && ! is_multisite() ) ? '' : wp_create_nonce( 'wp_rest' ), | ||
'versionString' => 'wp/v2/', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we ever use it? I think it might be useful, but I don't see any code occurrence inside Gutenberg.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This global is the reason the tests were failing, I just left it as is, it's being used by Core's wp-api
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okey 👍
Yes, it looks like it is a known issue: #6539. Let's address it separately. I wasn't aware it was already reported. In that case, everything works well in my testing. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Travis has some issues. I cleared cache and triggered another build. It works locally as expected, e2e tests pass to. Let's make sure Travis is happy and it should be good to go 🚢
@@ -0,0 +1,19 @@ | |||
function httpV1Middleware( options, next ) { | |||
const newOptions = { ...options }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we create a shallow clone before the if
condition where it becomes relevant? Wasted effort for the majority of cases?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const createNonceMiddleware = ( nonce ) => ( options, next ) => { | ||
let usedNonce = nonce; | ||
/** | ||
* This is not ideal but it's fine for now. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment seems to imply some self-evident flaw. What's not ideal? What's the action item for some future maintainer to make it better?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It didn't feel right to me to tie apiRequest
/fetch to heartbeat specific events. I think it's better in the last versions using hooks. I don't have an ideal solution without complexity though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at it some more, I think I could see a couple things:
- There's an
X-WP-Nonce
on the response of a fetch request; should we not assume that as a fresh one and use it? - Maybe this (the heartbeat tick handling) should be pulled out and added as an inline script in the WordPress-specific usage of
api-request
, with some way to inform the middleware of a new nonce.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Both these suggestion seem good to me, I just worry about the complexity especially about this:
with some way to inform the middleware of a new nonce.
If we manage to keep it simple in terms of API and implementation, all good for me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One idea: optionally allow, instead of an initial nonce, a function which receives as an argument the "inform" callback:
createNonceMiddleware( ( setNonce ) => {
setNonce( initialNonce );
addAction(
'heartbeat.tick',
'core/api-fetch/create-nonce-middleware',
( response ) => response[ 'rest_nonce' ] && setNonce( response[ 'rest_nonce' ] ),
);
} );
Lazy man's observable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or, just have the nonce as a property of the created middleware.
const nonceMiddleware = createNonceMiddleware( initialNonce );
wp.apiFetch.use( nonceMiddleware );
wp.hooks.addAction(
'heartbeat.tick',
'core/api-fetch/create-nonce-middleware',
( response ) => response[ 'rest_nonce' ] && nonceMiddleware.nonce = response[ 'rest_nonce' ]
);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With that in mind, should there be an optional callback that is passed in that can be used to update the nonce when its observed in the response of a fetch?
What's the use-case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking there might be some global reference to the current nonce but I'm guessing there's not (and doesn't need to be obviously).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think of the options given, I prefer the callback approach. Exposing nonce as a property on nonceMiddleware seems potentially fragile because third party code could clobber it right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They'd need a reference to the created middleware (not likely to be exposed). Could even be argued to be a good thing to allow someone to update it themselves if they want, though. I don't see it likely to be an issue.
This PR creates a new package
@wordpress/api-request
I don't know about you but I love this PR :P
Testing instructions