Skip to content

feat(response-cache): isPersistedDocumentContext helper #3951

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

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

n1ru4l
Copy link
Collaborator

@n1ru4l n1ru4l commented Apr 2, 2025

Closes #3955

Add helper function isPersistedDocumentContext.

This function can help you determine whether the GraphQL execution is done within the context of a
persisted document and for example apply additional plugins or security measures conditionally.

Usage Example: Enable max depth rule conditionally

import { createYoga } from 'graphql-yoga'
import { maxDepthRule } from '@escape.tech/graphql-armor-max-depth'
import { usePersistedOperations, isPersistedDocumentContext } from '@graphql-yoga/plugin-persisted-operations'
import schema from './schema.js'
import store from './store.js'

const yoga = createYoga({
  plugins: [
    usePersistedOperations({
      getPersistedOperation(key: string) {
        return store.get(key) || null
      },
      allowArbitraryOperations: true
    }),
    {
      onValidate(ctx) {
        if (isPersistedDocumentContext(ctx.context)) {
          return
        }

        ctx.addValidationRule(
          maxDepthRule({
            n: 20
          })
        )
      }
    }
  ],
  schema
})

Copy link
Contributor

github-actions bot commented Apr 2, 2025

Apollo Federation Subgraph Compatibility Results

Federation 1 Support Federation 2 Support
_service🟢
@key (single)🟢
@key (multi)🟢
@key (composite)🟢
repeatable @key🟢
@requires🟢
@provides🟢
federated tracing🟢
@link🟢
@shareable🟢
@tag🟢
@override🟢
@inaccessible🟢
@composeDirective🟢
@interfaceObject🟢

Learn more:

Copy link
Contributor

github-actions bot commented Apr 2, 2025

💻 Website Preview

The latest changes are available as preview in: https://pr-3951.graphql-yoga.pages.dev

Copy link
Contributor

github-actions bot commented Apr 2, 2025

✅ Benchmark Results

     ✓ no_errors{mode:graphql}
     ✓ expected_result{mode:graphql}
     ✓ no_errors{mode:graphql-jit}
     ✓ expected_result{mode:graphql-jit}
     ✓ no_errors{mode:graphql-response-cache}
     ✓ expected_result{mode:graphql-response-cache}
     ✓ no_errors{mode:graphql-no-parse-validate-cache}
     ✓ expected_result{mode:graphql-no-parse-validate-cache}
     ✓ no_errors{mode:uws}
     ✓ expected_result{mode:uws}

     checks.......................................: 100.00% ✓ 462956      ✗ 0     
     data_received................................: 1.9 GB  12 MB/s
     data_sent....................................: 93 MB   620 kB/s
     http_req_blocked.............................: avg=1.52µs   min=981ns    med=1.35µs   max=257.89µs p(90)=1.99µs   p(95)=2.16µs  
     http_req_connecting..........................: avg=2ns      min=0s       med=0s       max=129.39µs p(90)=0s       p(95)=0s      
     http_req_duration............................: avg=427.77µs min=286.51µs med=392.23µs max=19.11ms  p(90)=555.64µs p(95)=582.86µs
       { expected_response:true }.................: avg=427.77µs min=286.51µs med=392.23µs max=19.11ms  p(90)=555.64µs p(95)=582.86µs
     ✓ { mode:graphql-jit }.......................: avg=368.09µs min=294.77µs med=350.09µs max=19.11ms  p(90)=385.9µs  p(95)=400.88µs
     ✓ { mode:graphql-no-parse-validate-cache }...: avg=582.5µs  min=487.23µs med=557.85µs max=5.97ms   p(90)=615.39µs p(95)=674.92µs
     ✓ { mode:graphql-response-cache }............: avg=425.56µs min=337.03µs med=407.59µs max=7.09ms   p(90)=441.15µs p(95)=453.58µs
     ✓ { mode:graphql }...........................: avg=443.41µs min=352.1µs  med=413.23µs max=17.67ms  p(90)=469.46µs p(95)=517.19µs
     ✓ { mode:uws }...............................: avg=363.79µs min=286.51µs med=344.53µs max=6.01ms   p(90)=380.74µs p(95)=406.06µs
     http_req_failed..............................: 0.00%   ✓ 0           ✗ 231478
     http_req_receiving...........................: avg=32.92µs  min=16.79µs  med=32.47µs  max=3.05ms   p(90)=39.2µs   p(95)=41.74µs 
     http_req_sending.............................: avg=8.68µs   min=5.99µs   med=7.66µs   max=1.43ms   p(90)=11.03µs  p(95)=12.14µs 
     http_req_tls_handshaking.....................: avg=0s       min=0s       med=0s       max=0s       p(90)=0s       p(95)=0s      
     http_req_waiting.............................: avg=386.16µs min=251.65µs med=351.51µs max=19.02ms  p(90)=512.89µs p(95)=538.77µs
     http_reqs....................................: 231478  1543.140425/s
     iteration_duration...........................: avg=643.12µs min=450.56µs med=603.52µs max=19.63ms  p(90)=775.66µs p(95)=809.16µs
     iterations...................................: 231478  1543.140425/s
     vus..........................................: 1       min=1         max=1   
     vus_max......................................: 2       min=2         max=2   

}

function markContextAsPersistedOperationContext<TContext extends object>(context: TContext) {
(context as Record<string | symbol, unknown>)[isPersistedOperationContextSymbol] = true;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you use a WeakMap with the context as key to mark it as persisted operation ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants