Skip to content

Commit

Permalink
add the next multipart delimiter at the end of the chunk (#1596)
Browse files Browse the repository at this point in the history
deferred responses come as multipart elements, send as individual HTTP
response chunks. When a client receives one chunk, it should contain the
next delimiter, so the client knows that the response can be processed,
instead of waiting for the next chunk to see the delimiter.

Side note: fixed the format of the last delimiter that was missing a
trailing --
  • Loading branch information
Geoffroy Couprie authored Aug 25, 2022
1 parent 5cb0065 commit 670601a
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 13 deletions.
7 changes: 7 additions & 0 deletions NEXT_CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,13 @@ Remove the closed parenthesis at the end of error messages resulting from HTTP e

By [@nmoutschen](https://github.com/nmoutschen) in https://github.com/apollographql/router/pull/1593

### Only send one report for a response with deferred responses ([PR #1596](https://github.com/apollographql/router/issues/1596))

deferred responses come as multipart elements, send as individual HTTP response chunks. When a client receives one chunk,
it should contain the next delimiter, so the client knows that the response can be processed, instead of waiting for the
next chunk to see the delimiter.

By [@Geal](https://github.com/Geal) in https://github.com/apollographql/router/pull/1596

## 🛠 Maintenance
## 📚 Documentation
38 changes: 25 additions & 13 deletions apollo-router/src/axum_http_server_factory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -533,19 +533,31 @@ where
}
Some(response) => {
if response.has_next.unwrap_or(false) {
let stream = once(ready(response)).chain(stream);

let body = stream
.flat_map(|res| {
once(ready(Bytes::from_static(
b"--graphql\r\ncontent-type: application/json\r\n\r\n",
)))
.chain(once(ready(
serde_json::to_vec(&res).unwrap().into(),
)))
.chain(once(ready(Bytes::from_static(b"\r\n"))))
})
.map(Ok::<_, BoxError>);
// each chunk contains a response and the next delimiter, to let client parsers
// know that they can process the response right away
let mut first_buf = Vec::from(
&b"\r\n--graphql\r\ncontent-type: application/json\r\n\r\n"[..],
);
serde_json::to_writer(&mut first_buf, &response).unwrap();
first_buf.extend_from_slice(b"\r\n--graphql\r\n");

let body = once(ready(Ok(Bytes::from(first_buf)))).chain(
stream.map(|res| {
let mut buf = Vec::from(
&b"content-type: application/json\r\n\r\n"[..],
);
serde_json::to_writer(&mut buf, &res).unwrap();

// the last chunk has a different end delimiter
if res.has_next.unwrap_or(false) {
buf.extend_from_slice(b"\r\n--graphql\r\n");
} else {
buf.extend_from_slice(b"\r\n--graphql--\r\n");
}

Ok::<_, BoxError>(buf.into())
}),
);

(parts, StreamBody::new(body)).into_response()
} else {
Expand Down

0 comments on commit 670601a

Please sign in to comment.