Skip to content
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

Core Data: Stop sending duplicate requests in canUser resolver #43480

Merged
merged 6 commits into from
Aug 30, 2022

Conversation

adamziel
Copy link
Contributor

What?

The following snippet issues three identical HTTP requests:

canUser( 'pages', 'update', 10 );
canUser( 'pages', 'read', 10 );
canUser( 'pages', 'delete', 10 );

Each time, the canUser resolver sends a simple OPTIONS request to the /wp/v2/pages/10.

This PR caches and reuses the results retrieved the first time. It follows up on an observation @Mamaduka got after stabilizing the useResourcePermissions hook:

When using this hook, even if you only check for single permission, it will still make multiple calls to the same endpoint.

Testing Instructions

It's hard to test this in a browser so I added a test case to check how many API calls are issued. Confirm it makes sense and passes.

cc @Mamaduka @gziolo

@adamziel adamziel added the [Package] Core data /packages/core-data label Aug 22, 2022
@adamziel adamziel self-assigned this Aug 22, 2022
@adamziel adamziel requested a review from nerrad as a code owner August 22, 2022 12:28
@Mamaduka Mamaduka added the [Type] Performance Related to performance efforts label Aug 22, 2022
@Mamaduka Mamaduka self-requested a review August 22, 2022 12:37
@gziolo gziolo added the REST API Interaction Related to REST API label Aug 22, 2022
@github-actions
Copy link

github-actions bot commented Aug 22, 2022

Size Change: +690 B (0%)

Total Size: 1.24 MB

Filename Size Change
build/block-editor/index.min.js 159 kB +391 B (0%)
build/block-editor/style-rtl.css 15.1 kB +17 B (0%)
build/block-editor/style.css 15 kB +16 B (0%)
build/block-library/blocks/media-text/style-rtl.css 507 B +14 B (+3%)
build/block-library/blocks/media-text/style.css 505 B +15 B (+3%)
build/block-library/blocks/navigation/editor-rtl.css 2.05 kB +23 B (+1%)
build/block-library/blocks/navigation/editor.css 2.06 kB +18 B (+1%)
build/block-library/blocks/post-title/style-rtl.css 100 B +20 B (+25%) 🚨
build/block-library/blocks/post-title/style.css 100 B +20 B (+25%) 🚨
build/block-library/editor-rtl.css 11 kB +31 B (0%)
build/block-library/editor.css 11 kB +31 B (0%)
build/block-library/index.min.js 186 kB +326 B (0%)
build/block-library/style-rtl.css 11.9 kB +15 B (0%)
build/block-library/style.css 11.9 kB +15 B (0%)
build/blocks/index.min.js 49.5 kB +5 B (0%)
build/components/index.min.js 198 kB -403 B (0%)
build/components/style-rtl.css 11.6 kB -13 B (0%)
build/components/style.css 11.6 kB -14 B (0%)
build/core-data/index.min.js 15.5 kB +124 B (+1%)
build/customize-widgets/style-rtl.css 1.38 kB -24 B (-2%)
build/customize-widgets/style.css 1.38 kB -24 B (-2%)
build/data/index.min.js 8.05 kB +24 B (0%)
build/date/index.min.js 32 kB -5 B (0%)
build/edit-navigation/index.min.js 16 kB +8 B (0%)
build/edit-site/index.min.js 57.4 kB -11 B (0%)
build/element/index.min.js 4.68 kB +6 B (0%)
build/redux-routine/index.min.js 2.74 kB -1 B (0%)
build/widgets/index.min.js 7.2 kB +11 B (0%)
build/widgets/style-rtl.css 1.18 kB +27 B (+2%)
build/widgets/style.css 1.19 kB +28 B (+2%)
ℹ️ View Unchanged
Filename Size
build/a11y/index.min.js 982 B
build/annotations/index.min.js 2.76 kB
build/api-fetch/index.min.js 2.26 kB
build/autop/index.min.js 2.14 kB
build/blob/index.min.js 475 B
build/block-directory/index.min.js 7.06 kB
build/block-directory/style-rtl.css 990 B
build/block-directory/style.css 991 B
build/block-editor/default-editor-styles-rtl.css 378 B
build/block-editor/default-editor-styles.css 378 B
build/block-library/blocks/archives/editor-rtl.css 61 B
build/block-library/blocks/archives/editor.css 60 B
build/block-library/blocks/archives/style-rtl.css 65 B
build/block-library/blocks/archives/style.css 65 B
build/block-library/blocks/audio/editor-rtl.css 150 B
build/block-library/blocks/audio/editor.css 150 B
build/block-library/blocks/audio/style-rtl.css 122 B
build/block-library/blocks/audio/style.css 122 B
build/block-library/blocks/audio/theme-rtl.css 110 B
build/block-library/blocks/audio/theme.css 110 B
build/block-library/blocks/avatar/editor-rtl.css 116 B
build/block-library/blocks/avatar/editor.css 116 B
build/block-library/blocks/avatar/style-rtl.css 59 B
build/block-library/blocks/avatar/style.css 59 B
build/block-library/blocks/block/editor-rtl.css 161 B
build/block-library/blocks/block/editor.css 161 B
build/block-library/blocks/button/editor-rtl.css 441 B
build/block-library/blocks/button/editor.css 441 B
build/block-library/blocks/button/style-rtl.css 539 B
build/block-library/blocks/button/style.css 539 B
build/block-library/blocks/buttons/editor-rtl.css 292 B
build/block-library/blocks/buttons/editor.css 292 B
build/block-library/blocks/buttons/style-rtl.css 275 B
build/block-library/blocks/buttons/style.css 275 B
build/block-library/blocks/calendar/style-rtl.css 207 B
build/block-library/blocks/calendar/style.css 207 B
build/block-library/blocks/categories/editor-rtl.css 84 B
build/block-library/blocks/categories/editor.css 83 B
build/block-library/blocks/categories/style-rtl.css 79 B
build/block-library/blocks/categories/style.css 79 B
build/block-library/blocks/code/style-rtl.css 103 B
build/block-library/blocks/code/style.css 103 B
build/block-library/blocks/code/theme-rtl.css 124 B
build/block-library/blocks/code/theme.css 124 B
build/block-library/blocks/columns/editor-rtl.css 108 B
build/block-library/blocks/columns/editor.css 108 B
build/block-library/blocks/columns/style-rtl.css 406 B
build/block-library/blocks/columns/style.css 406 B
build/block-library/blocks/comment-author-avatar/editor-rtl.css 125 B
build/block-library/blocks/comment-author-avatar/editor.css 125 B
build/block-library/blocks/comment-content/style-rtl.css 92 B
build/block-library/blocks/comment-content/style.css 92 B
build/block-library/blocks/comment-template/style-rtl.css 187 B
build/block-library/blocks/comment-template/style.css 185 B
build/block-library/blocks/comments-pagination-numbers/editor-rtl.css 123 B
build/block-library/blocks/comments-pagination-numbers/editor.css 121 B
build/block-library/blocks/comments-pagination/editor-rtl.css 222 B
build/block-library/blocks/comments-pagination/editor.css 209 B
build/block-library/blocks/comments-pagination/style-rtl.css 235 B
build/block-library/blocks/comments-pagination/style.css 231 B
build/block-library/blocks/comments-title/editor-rtl.css 75 B
build/block-library/blocks/comments-title/editor.css 75 B
build/block-library/blocks/comments/editor-rtl.css 834 B
build/block-library/blocks/comments/editor.css 832 B
build/block-library/blocks/comments/style-rtl.css 632 B
build/block-library/blocks/comments/style.css 630 B
build/block-library/blocks/cover/editor-rtl.css 615 B
build/block-library/blocks/cover/editor.css 616 B
build/block-library/blocks/cover/style-rtl.css 1.55 kB
build/block-library/blocks/cover/style.css 1.55 kB
build/block-library/blocks/embed/editor-rtl.css 293 B
build/block-library/blocks/embed/editor.css 293 B
build/block-library/blocks/embed/style-rtl.css 410 B
build/block-library/blocks/embed/style.css 410 B
build/block-library/blocks/embed/theme-rtl.css 110 B
build/block-library/blocks/embed/theme.css 110 B
build/block-library/blocks/file/editor-rtl.css 300 B
build/block-library/blocks/file/editor.css 300 B
build/block-library/blocks/file/style-rtl.css 253 B
build/block-library/blocks/file/style.css 254 B
build/block-library/blocks/file/view.min.js 346 B
build/block-library/blocks/freeform/editor-rtl.css 2.44 kB
build/block-library/blocks/freeform/editor.css 2.44 kB
build/block-library/blocks/gallery/editor-rtl.css 948 B
build/block-library/blocks/gallery/editor.css 950 B
build/block-library/blocks/gallery/style-rtl.css 1.53 kB
build/block-library/blocks/gallery/style.css 1.53 kB
build/block-library/blocks/gallery/theme-rtl.css 108 B
build/block-library/blocks/gallery/theme.css 108 B
build/block-library/blocks/group/editor-rtl.css 412 B
build/block-library/blocks/group/editor.css 412 B
build/block-library/blocks/group/style-rtl.css 57 B
build/block-library/blocks/group/style.css 57 B
build/block-library/blocks/group/theme-rtl.css 78 B
build/block-library/blocks/group/theme.css 78 B
build/block-library/blocks/heading/style-rtl.css 76 B
build/block-library/blocks/heading/style.css 76 B
build/block-library/blocks/html/editor-rtl.css 327 B
build/block-library/blocks/html/editor.css 329 B
build/block-library/blocks/image/editor-rtl.css 876 B
build/block-library/blocks/image/editor.css 873 B
build/block-library/blocks/image/style-rtl.css 627 B
build/block-library/blocks/image/style.css 630 B
build/block-library/blocks/image/theme-rtl.css 110 B
build/block-library/blocks/image/theme.css 110 B
build/block-library/blocks/latest-comments/style-rtl.css 284 B
build/block-library/blocks/latest-comments/style.css 284 B
build/block-library/blocks/latest-posts/editor-rtl.css 213 B
build/block-library/blocks/latest-posts/editor.css 212 B
build/block-library/blocks/latest-posts/style-rtl.css 463 B
build/block-library/blocks/latest-posts/style.css 462 B
build/block-library/blocks/list/style-rtl.css 88 B
build/block-library/blocks/list/style.css 88 B
build/block-library/blocks/media-text/editor-rtl.css 266 B
build/block-library/blocks/media-text/editor.css 263 B
build/block-library/blocks/more/editor-rtl.css 431 B
build/block-library/blocks/more/editor.css 431 B
build/block-library/blocks/navigation-link/editor-rtl.css 705 B
build/block-library/blocks/navigation-link/editor.css 703 B
build/block-library/blocks/navigation-link/style-rtl.css 115 B
build/block-library/blocks/navigation-link/style.css 115 B
build/block-library/blocks/navigation-submenu/editor-rtl.css 296 B
build/block-library/blocks/navigation-submenu/editor.css 295 B
build/block-library/blocks/navigation-submenu/view.min.js 423 B
build/block-library/blocks/navigation/style-rtl.css 1.98 kB
build/block-library/blocks/navigation/style.css 1.97 kB
build/block-library/blocks/navigation/view-modal.min.js 2.78 kB
build/block-library/blocks/navigation/view.min.js 443 B
build/block-library/blocks/nextpage/editor-rtl.css 395 B
build/block-library/blocks/nextpage/editor.css 395 B
build/block-library/blocks/page-list/editor-rtl.css 363 B
build/block-library/blocks/page-list/editor.css 363 B
build/block-library/blocks/page-list/style-rtl.css 175 B
build/block-library/blocks/page-list/style.css 175 B
build/block-library/blocks/paragraph/editor-rtl.css 174 B
build/block-library/blocks/paragraph/editor.css 174 B
build/block-library/blocks/paragraph/style-rtl.css 260 B
build/block-library/blocks/paragraph/style.css 260 B
build/block-library/blocks/post-author/style-rtl.css 175 B
build/block-library/blocks/post-author/style.css 176 B
build/block-library/blocks/post-comments-form/editor-rtl.css 96 B
build/block-library/blocks/post-comments-form/editor.css 96 B
build/block-library/blocks/post-comments-form/style-rtl.css 493 B
build/block-library/blocks/post-comments-form/style.css 493 B
build/block-library/blocks/post-date/style-rtl.css 61 B
build/block-library/blocks/post-date/style.css 61 B
build/block-library/blocks/post-excerpt/editor-rtl.css 73 B
build/block-library/blocks/post-excerpt/editor.css 73 B
build/block-library/blocks/post-excerpt/style-rtl.css 69 B
build/block-library/blocks/post-excerpt/style.css 69 B
build/block-library/blocks/post-featured-image/editor-rtl.css 507 B
build/block-library/blocks/post-featured-image/editor.css 505 B
build/block-library/blocks/post-featured-image/style-rtl.css 166 B
build/block-library/blocks/post-featured-image/style.css 166 B
build/block-library/blocks/post-template/editor-rtl.css 99 B
build/block-library/blocks/post-template/editor.css 98 B
build/block-library/blocks/post-template/style-rtl.css 282 B
build/block-library/blocks/post-template/style.css 282 B
build/block-library/blocks/post-terms/style-rtl.css 73 B
build/block-library/blocks/post-terms/style.css 73 B
build/block-library/blocks/preformatted/style-rtl.css 103 B
build/block-library/blocks/preformatted/style.css 103 B
build/block-library/blocks/pullquote/editor-rtl.css 135 B
build/block-library/blocks/pullquote/editor.css 135 B
build/block-library/blocks/pullquote/style-rtl.css 326 B
build/block-library/blocks/pullquote/style.css 325 B
build/block-library/blocks/pullquote/theme-rtl.css 167 B
build/block-library/blocks/pullquote/theme.css 167 B
build/block-library/blocks/query-pagination-numbers/editor-rtl.css 122 B
build/block-library/blocks/query-pagination-numbers/editor.css 121 B
build/block-library/blocks/query-pagination/editor-rtl.css 221 B
build/block-library/blocks/query-pagination/editor.css 211 B
build/block-library/blocks/query-pagination/style-rtl.css 282 B
build/block-library/blocks/query-pagination/style.css 278 B
build/block-library/blocks/query-title/style-rtl.css 63 B
build/block-library/blocks/query-title/style.css 63 B
build/block-library/blocks/query/editor-rtl.css 439 B
build/block-library/blocks/query/editor.css 439 B
build/block-library/blocks/quote/style-rtl.css 213 B
build/block-library/blocks/quote/style.css 213 B
build/block-library/blocks/quote/theme-rtl.css 223 B
build/block-library/blocks/quote/theme.css 226 B
build/block-library/blocks/read-more/style-rtl.css 132 B
build/block-library/blocks/read-more/style.css 132 B
build/block-library/blocks/rss/editor-rtl.css 202 B
build/block-library/blocks/rss/editor.css 204 B
build/block-library/blocks/rss/style-rtl.css 289 B
build/block-library/blocks/rss/style.css 288 B
build/block-library/blocks/search/editor-rtl.css 165 B
build/block-library/blocks/search/editor.css 165 B
build/block-library/blocks/search/style-rtl.css 396 B
build/block-library/blocks/search/style.css 393 B
build/block-library/blocks/search/theme-rtl.css 114 B
build/block-library/blocks/search/theme.css 114 B
build/block-library/blocks/separator/editor-rtl.css 146 B
build/block-library/blocks/separator/editor.css 146 B
build/block-library/blocks/separator/style-rtl.css 233 B
build/block-library/blocks/separator/style.css 233 B
build/block-library/blocks/separator/theme-rtl.css 194 B
build/block-library/blocks/separator/theme.css 194 B
build/block-library/blocks/shortcode/editor-rtl.css 464 B
build/block-library/blocks/shortcode/editor.css 464 B
build/block-library/blocks/site-logo/editor-rtl.css 455 B
build/block-library/blocks/site-logo/editor.css 455 B
build/block-library/blocks/site-logo/style-rtl.css 192 B
build/block-library/blocks/site-logo/style.css 192 B
build/block-library/blocks/site-tagline/editor-rtl.css 86 B
build/block-library/blocks/site-tagline/editor.css 86 B
build/block-library/blocks/site-title/editor-rtl.css 84 B
build/block-library/blocks/site-title/editor.css 84 B
build/block-library/blocks/social-link/editor-rtl.css 184 B
build/block-library/blocks/social-link/editor.css 184 B
build/block-library/blocks/social-links/editor-rtl.css 674 B
build/block-library/blocks/social-links/editor.css 673 B
build/block-library/blocks/social-links/style-rtl.css 1.39 kB
build/block-library/blocks/social-links/style.css 1.38 kB
build/block-library/blocks/spacer/editor-rtl.css 322 B
build/block-library/blocks/spacer/editor.css 322 B
build/block-library/blocks/spacer/style-rtl.css 48 B
build/block-library/blocks/spacer/style.css 48 B
build/block-library/blocks/table/editor-rtl.css 494 B
build/block-library/blocks/table/editor.css 494 B
build/block-library/blocks/table/style-rtl.css 611 B
build/block-library/blocks/table/style.css 609 B
build/block-library/blocks/table/theme-rtl.css 175 B
build/block-library/blocks/table/theme.css 175 B
build/block-library/blocks/tag-cloud/style-rtl.css 239 B
build/block-library/blocks/tag-cloud/style.css 239 B
build/block-library/blocks/template-part/editor-rtl.css 235 B
build/block-library/blocks/template-part/editor.css 235 B
build/block-library/blocks/template-part/theme-rtl.css 101 B
build/block-library/blocks/template-part/theme.css 101 B
build/block-library/blocks/text-columns/editor-rtl.css 95 B
build/block-library/blocks/text-columns/editor.css 95 B
build/block-library/blocks/text-columns/style-rtl.css 166 B
build/block-library/blocks/text-columns/style.css 166 B
build/block-library/blocks/verse/style-rtl.css 87 B
build/block-library/blocks/verse/style.css 87 B
build/block-library/blocks/video/editor-rtl.css 561 B
build/block-library/blocks/video/editor.css 563 B
build/block-library/blocks/video/style-rtl.css 174 B
build/block-library/blocks/video/style.css 174 B
build/block-library/blocks/video/theme-rtl.css 110 B
build/block-library/blocks/video/theme.css 110 B
build/block-library/common-rtl.css 1.01 kB
build/block-library/common.css 1 kB
build/block-library/editor-elements-rtl.css 75 B
build/block-library/editor-elements.css 75 B
build/block-library/elements-rtl.css 54 B
build/block-library/elements.css 54 B
build/block-library/reset-rtl.css 478 B
build/block-library/reset.css 478 B
build/block-library/theme-rtl.css 695 B
build/block-library/theme.css 700 B
build/block-serialization-default-parser/index.min.js 1.11 kB
build/block-serialization-spec-parser/index.min.js 2.83 kB
build/compose/index.min.js 12 kB
build/customize-widgets/index.min.js 11.3 kB
build/data-controls/index.min.js 653 B
build/deprecated/index.min.js 507 B
build/dom-ready/index.min.js 324 B
build/dom/index.min.js 4.69 kB
build/edit-navigation/style-rtl.css 4 kB
build/edit-navigation/style.css 4.01 kB
build/edit-post/classic-rtl.css 546 B
build/edit-post/classic.css 547 B
build/edit-post/index.min.js 30.5 kB
build/edit-post/style-rtl.css 6.94 kB
build/edit-post/style.css 6.94 kB
build/edit-site/style-rtl.css 8.22 kB
build/edit-site/style.css 8.2 kB
build/edit-widgets/index.min.js 16.5 kB
build/edit-widgets/style-rtl.css 4.35 kB
build/edit-widgets/style.css 4.35 kB
build/editor/index.min.js 41.5 kB
build/editor/style-rtl.css 3.66 kB
build/editor/style.css 3.65 kB
build/escape-html/index.min.js 537 B
build/format-library/index.min.js 6.75 kB
build/format-library/style-rtl.css 571 B
build/format-library/style.css 571 B
build/hooks/index.min.js 1.64 kB
build/html-entities/index.min.js 448 B
build/i18n/index.min.js 3.77 kB
build/is-shallow-equal/index.min.js 527 B
build/keyboard-shortcuts/index.min.js 1.78 kB
build/keycodes/index.min.js 1.81 kB
build/list-reusable-blocks/index.min.js 1.74 kB
build/list-reusable-blocks/style-rtl.css 835 B
build/list-reusable-blocks/style.css 835 B
build/media-utils/index.min.js 2.93 kB
build/notices/index.min.js 953 B
build/nux/index.min.js 2.05 kB
build/nux/style-rtl.css 732 B
build/nux/style.css 728 B
build/plugins/index.min.js 1.94 kB
build/preferences-persistence/index.min.js 2.22 kB
build/preferences/index.min.js 1.3 kB
build/primitives/index.min.js 933 B
build/priority-queue/index.min.js 612 B
build/react-i18n/index.min.js 696 B
build/react-refresh-entry/index.min.js 8.44 kB
build/react-refresh-runtime/index.min.js 7.31 kB
build/reusable-blocks/index.min.js 2.21 kB
build/reusable-blocks/style-rtl.css 256 B
build/reusable-blocks/style.css 256 B
build/rich-text/index.min.js 11.2 kB
build/server-side-render/index.min.js 1.61 kB
build/shortcode/index.min.js 1.53 kB
build/token-list/index.min.js 644 B
build/url/index.min.js 3.61 kB
build/vendors/react-dom.min.js 38.5 kB
build/vendors/react.min.js 4.34 kB
build/viewport/index.min.js 1.08 kB
build/warning/index.min.js 268 B
build/wordcount/index.min.js 1.06 kB

compressed-size-action

@adamziel
Copy link
Contributor Author

The e2e failures are the same as in trunk. I think this is good to be merged as soon as anyone dares to review :D cc @noisysocks @jorgefilipecosta @jsnajdr @draganescu

@gziolo gziolo changed the title Stop sending duplicate requests in canUser resolver Core Data: Stop sending duplicate requests in canUser resolver Aug 23, 2022
@Mamaduka
Copy link
Member

Mamaduka commented Aug 24, 2022

@adamziel, I just pushed a minor fix when checking resources without an ID + minor refactor and unit tests for this new case.

Suppose anyone is looking for a way to test this fix manually. You can run the following snippet in the DevTools console and confirm that it only triggers one REST API request.

wp.data.select('core').canUser('read', 'template-parts');
wp.data.select('core').canUser('create', 'template-parts');

@adamziel
Copy link
Contributor Author

Yay @Mamaduka, thank you! It looks good and makes sense to me.

Copy link
Member

@Mamaduka Mamaduka left a comment

Choose a reason for hiding this comment

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

Let's merge this, improvements work well in my tests 👍

@adamziel
Copy link
Contributor Author

@Mamaduka I pushed one more bugfix and unit test. The site title block calls canUser( 'update', 'settings' ) which means that update and delete permissions needs to be stored regardless of whether the ID is passed.

@Mamaduka
Copy link
Member

Nice catch, @adamziel. The third-party code might also use update and delete without IDs for custom endpoints.

@TimothyBJacobs
Copy link
Member

These may both be for another ticket.

Making an OPTIONS request isn't required to get the Allow header, any request to that entity will have the Allow header included in the response. It seems like we should be storing the headers of our entity fetch responses in core-data somewhere. That way a separate OPTIONS query would be avoidable if the item was already loaded.

When a request does need to be made, we should probably also explore a Core ticket around building specific HEAD responses. While an OPTIONS response is cheaper than a full GET, a proper HEAD should be even faster. Right now, the REST API server will just throw away the response body. But we could register a specific no-op HEAD callback, or potentially have a register_rest_route flag that would let the REST API server only call permission_callback and skip callback.

Why does canUser take a resource instead of a kind and name? It looks like this selector doesn't account for namespaces other than wp/v2 which means the behavior is potentially broken for CPTs and Taxonomies since 5.9. But it also means it can't be used for any non-core entities.

@adamziel adamziel merged commit e97cfa1 into trunk Aug 30, 2022
@adamziel adamziel deleted the update/canUser-only-run-once-per-resource branch August 30, 2022 08:17
@github-actions github-actions bot added this to the Gutenberg 14.1 milestone Aug 30, 2022
@adamziel
Copy link
Contributor Author

adamziel commented Aug 30, 2022

Making an OPTIONS request isn't required to get the Allow header, any request to that entity will have the Allow header included in the response. It seems like we should be storing the headers of our entity fetch responses in core-data somewhere. That way a separate OPTIONS query would be avoidable if the item was already loaded.

I think this is happening since #35527

When a request does need to be made, we should probably also explore a Core ticket around building specific HEAD responses. While an OPTIONS response is cheaper than a full GET, a proper HEAD should be even faster. Right now, the REST API server will just throw away the response body. But we could register a specific no-op HEAD callback, or potentially have a register_rest_route flag that would let the REST API server only call permission_callback and skip callback.

I like the HEAD request idea! It just worked for a few dummy requests I made, so here's a PR to see what will the CI checks look like: #43703

Why does canUser take a resource instead of a kind and name? It looks like this selector doesn't account for namespaces other than wp/v2 which means the behavior is potentially broken for CPTs and Taxonomies since 5.9. But it also means it can't be used for any non-core entities.

My first thought was that it takes a resource to check more than just entity records permissions, but then I didn't find any instances of that. Good call about supporting other namespaces – would you please create a separate ticket for that?

@Mamaduka
Copy link
Member

Actually, we already have canUserEditEntityRecord that works with kind and name. It's a tiny wrapper around canUser.

export function canUserEditEntityRecord(
state: State,
kind: string,
name: string,
recordId: EntityRecordKey
): boolean | undefined {
const entityConfig = getEntityConfig( state, kind, name );
if ( ! entityConfig ) {
return false;
}
const resource = entityConfig.__unstable_rest_base;
return canUser( state, 'update', resource, recordId );
}

@TimothyBJacobs
Copy link
Member

I think this is happening since #35527

Right, when the OPTIONS endpoint is preloaded, no fetch will happen. But in a situation where I have called getEntityRecord, and then want to present the user an option to delete or update it, that shouldn't need a separate apiFetch because the correct Allow header will have been returned when I called getEntityRecord. Similarly, if I fetch a collection response, I already have the Allow header to know if I can create resources for that collection.

Thanks @Mamaduka. I'm going to spin up a new ticket. That makes the DUX a bit nicer, but doesn't actually solve the issue of canUser using the hardcoded namespaces. It also will only work for post types, not other entitiy kinds.

@Mamaduka
Copy link
Member

I like the idea of not throwing away Allow headers when resolving getEntityRecord(s). @adamziel, want to team up on this PR? 😄

Another thing we should probably look into is combining canUserEditEntityRecord and canUser. Probably deprecate one.

@TimothyBJacobs, how can we help with adding HEAD request support to the REST API server?

@adamziel
Copy link
Contributor Author

I like the idea of not throwing away Allow headers when resolving getEntityRecord(s). @adamziel, want to team up on this PR? 😄

Sure – let's do that!

@TimothyBJacobs
Copy link
Member

I'm going to spin up a new ticket. That makes the DUX a bit nicer, but doesn't actually solve the issue of canUser using the hardcoded namespaces. It also will only work for post types, not other entitiy kinds.

I've created #43751.

@TimothyBJacobs, how can we help with adding HEAD request support to the REST API server?

Core has built-in support, but I'm now less sure it is a good idea. Going to comment in #43703.

@adamziel
Copy link
Contributor Author

adamziel commented Sep 2, 2022

@Mamaduka here's two places to refactor to use the allow header we're already receiving via getEntityRecord(s):

const record = await apiFetch( { path } );

let records = Object.values( await apiFetch( { path } ) );

The key is using the apiFetch's parse: false option:

wp.apiFetch({
   path: '...',
   method: 'HEAD',
   parse: false
})
   .then(response => response.headers.get('allow'))
   .then(console.log)

Would you like to start that PR?

@Mamaduka
Copy link
Member

Mamaduka commented Sep 2, 2022

Do you suggest making another API request with parse: false in getEntityRecord(s) resolvers?

I thought @TimothyBJacobs, the recommendation was to use the header from the GET request. But now I see that parse: true throws away everything besides the body.

I wonder if adding requests to these resolvers defeats the whole purpose of this optimization.

In any case, I can start on this next week, and we'll see how the results.

@adamziel
Copy link
Contributor Author

adamziel commented Sep 2, 2022

Do you suggest making another API request with parse: false in getEntityRecord(s) resolvers?

Not at all! I suggest making just one API request and make sure it uses parse: false so that we can process both the response body and the headers. Right now the parse: false isn't in place and the response headers aren't accessible. Let's add parse: false to the existing request and adjust the surrounding code accordingly.

@Mamaduka
Copy link
Member

Mamaduka commented Sep 2, 2022

I think that would break the current fetchAllMiddleware for entity records. Let's see if we can find a workaround 😃

const fetchAllMiddleware = async ( options, next ) => {
if ( options.parse === false ) {
// If a consumer has opted out of parsing, do not apply middleware.
return next( options );
}

@TimothyBJacobs
Copy link
Member

I think the fetchAllMiddleware could be updated to work with parse: false. I presume it was omitted because we couldn't return headers for every nested request. But I think we could use the first response's headers safely.

if ( isAlreadyResolving ) {
return;
}
}
Copy link
Member

Choose a reason for hiding this comment

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

Shouldn't this be built into resolvers, instead of modifying a specific resolver? Or is that not possible?

Copy link
Member

Choose a reason for hiding this comment

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

Ah, got it, you're matching similar resolvers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Package] Core data /packages/core-data REST API Interaction Related to REST API [Type] Performance Related to performance efforts
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants