- 
                Notifications
    
You must be signed in to change notification settings  - Fork 532
 
Support for experimental @defer & @stream #583
Conversation
| 
           looks great, thanks @robrichard! once we get one of the graphql-js proposals merged for 15.0.0 we can revisit the tests here. saw there are two proposal PRs for graphql-js  | 
    
2492b68    to
    8dc8565      
    Compare
  
    46b3ff3    to
    3505ce2      
    Compare
  
            
          
                src/index.ts
              
                Outdated
          
        
      | if (isAsyncIterable(executeResult)) { | ||
| response.setHeader('Content-Type', 'multipart/mixed; boundary="-"'); | ||
| sendPartialResponse(pretty, response, formattedResult); | ||
| for await (let payload of executeResult) { | 
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.
@robrichard What happens when the request is terminated by the client (i.e. I navigate away from the page or close the browser)? Would it make sense to add an event listener to response for the close event and call the AsyncIterator's return method inside?
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.
Yes, I think that makes sense. I will implement that.
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 added a handler for the close event to call return on the underlying async iterable.
@IvanGoncharov this required disabling some lint rules (see d883ae7#diff-a2a171449d862fe29692ce031981047d7ab755ae7f84c707aef80701b3ea0c80R419). Do you think this is ok or do you have a better way to implement this?
7c2e919    to
    06f9ded      
    Compare
  
    | 
           I got a bit too excited so I created a playground making it easier for people to test this new stuff! https://github.com/n1ru4l/graphql-bleeding-edge-playground Awesome work!!!  | 
    
| 
           @n1ru4l awesome! it looks great in graphiql as well. we are going to archive playground soon though :(  | 
    
| 
           ah wait it is graphiql 😂 playground ist just the name of the repo it uses graphiql :D Please check out the GraphiQL fetchers 😇  | 
    
| 
           @n1ru4l oh awesome I see, thanks for that! did you see this? graphql/graphiql#1700 (comment)  | 
    
| 
           @n1ru4l are you interested in helping me create this PR in graphiql monorepo for the new fetcher patterns? Otherwise I might not have time until next weekend :/  | 
    
| 
           @robrichard Would it be possible for you to do single commits instead of force-pushing, I am having a hard time following the changes 😅 I also updated the playground to the latest commit.  | 
    
| 
           I've been force pushing because it's harder to keep rebasing when there are a lot of commits and this PR has been open for a long time.  | 
    
        
          
                src/index.ts
              
                Outdated
          
        
      | 
               | 
          ||
| // Collect and apply any metadata extensions if a function was provided. | ||
| // https://graphql.github.io/graphql-spec/#sec-Response-Format | ||
| if (isAsyncIterable(executeResult)) { | 
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.
Since executeFn is typed to return an AsyncIterableIterator, it would make sense to instead use a isAsyncIterableIterator function. That way it is also possible to call executeResult.return?.() in case the request is aborted without adding ts-ignores.
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.
Nevermind, if you use the isAsyncIterable function the type checker already is aware of the actual type (AsyncIterableIterator), making it easy to call .return()
| 
           It would also make sense to adjust the   | 
    
        
          
                src/index.ts
              
                Outdated
          
        
      | // Get first payload from AsyncIterator. http status will reflect status | ||
| // of this payload. | ||
| const asyncIterator = getAsyncIterator<ExecutionResult>(executeResult); | ||
| const { value } = await asyncIterator.next(); | 
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.
await can throw and should be inside try 🔼
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.
test for that would be great. You can do that by using custom executeFn that return an async iterator.
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.
@IvanGoncharov do you think it makes sense for the try/catch that is currently wrapping await executeFn({...}) to be expanded to also wrap this?
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.
@robrichard Yes, I think it would work 👍
df074c9    to
    aa62e24      
    Compare
  
    | result: FormattedExecutionResult | FormattedExecutionPatchResult, | ||
| ): void { | ||
| const json = JSON.stringify(result, null, pretty ? 2 : 0); | ||
| const chunk = Buffer.from(json, 'utf8'); | 
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.
will this always be utf8?
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 has me wanting to bring up protocolbuffers, messagepack and other binary formats, as well as yaml, however that seems way out of scope for this PR, and should probably begin as an HTTP transport RFC proposal. GraphiQL users have on multiple occasions requested support for these formats, especially for server-to-server transmissions and iot
back to this discussion, though, would it work to use a binary encoding format latin1 with JSON? I've never tried that myself. if someone was returning a binary format like BSON for example, then we should be returning content type of application/bson, right?  Is there a case where someone would be sending application/json and not using utf8 encoding?
if there are indeed more ways to mix and match charset and content type with JSON than I'm aware of, maybe this should be controlled by the request headers then, and fall back to utf8 as default?
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.
Worth noting that the transport RFC spec doesn't require utf8 necessarily (yet):
https://github.com/graphql/graphql-over-http/blob/master/rfcs/IncrementalDelivery.md
and the reference client implementation expects utf8:
https://github.com/relay-tools/fetch-multipart-graphql/blob/dfa54d0c649ecbbedac3e9764998f63894367505/src/fetch.js#L26
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.
meros also at this time uses UTF8. It's a force of habit. But there might be people out there needing some out of the ordinary encodings.
Maybe it's a cross that bridge when we get there?
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.
express-graphql already only sends utf8 so I don't think there's any change in behavior here: https://github.com/graphql/express-graphql/blob/master/src/index.ts#L531
As far as the spec, I'm not sure if it's worth specifying what encodings are required. FWIW it seems like JSON requires either UTF-8, UTF-16, or UTF-32 but recommends UTF8 for maximum interoperablity.
| 
           Wish github had stacked PR's 😔 robrichard#1  | 
    
b060480    to
    d883ae7      
    Compare
  
    78fdee3    to
    e303a2c      
    Compare
  
    e303a2c    to
    ce8429e      
    Compare
  
    
Support for streaming multi-part http responses as implemented by
graphql/graphql-js#2319
https://github.com/relay-tools/fetch-multipart-graphql