-
Notifications
You must be signed in to change notification settings - Fork 3
Description
If you are looking for Traffic Shaping categorization, see the note here
Introduction
HTTP Compression is a technique in HTTP connections to pass over the data compressed in a specific algorithm or algorithms.
There are two headers used for the negotiation between the client and the server.
Accept-Encoding which contains the list of algorithms that are supported by the peer(client/server)
Content-Encoding which contains the list of algorithms(usually a single one) applied to the data. So the consumer peer should decompress the body using that or those algorithms before processing it.
Here are some problems we need to keep on mind before continue;
When an initial request is sent to a server, you don't know which encoding types are supported by the server. So the algorithm you set in Content-Encoding in your request headers might not be supported. So you have to be careful on that.
An initial request should always be sent uncompressed, and Accept-Encoding should be waited to know which algorithms are supported.
Also while sending the request, you should set Accept-Encoding with a list of algorithms you support such as gzip, br, deflate. The order is important because the peer will pick the first compliant one from left to right.
Gateway's use case
In a GraphQL gateway, there are 4 different ways of HTTP communication when the compression can take place.
From the gateway to the client
When the client sends a request to the gateway, it can specify the compression algorithm that it supports using the Accept-Encoding header. Then the gateway can compress the response using the specified algorithm before sending it back to the client with the Content-Encoding header, so that the client can decompress it.
const res = await fetch('http://localhost:4000/graphql', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept-Encoding': 'gzip'
},
body: JSON.stringify({
query: `
query {
hello
}
`
})
})
console.assert(res.headers.get('Content-Encoding') === 'gzip', 'Response is compressed')When you send this request, you tell the server that the client supports gzip. So the server CAN send it as gzip. But you should always check the header because it is not guaranteed that the server sends it gzip.
From the client to the gateway
When the client sends a request to the gateway, it can be compressed and the algorithm MUST be defined in Content-Encoding so the gateway respects it and decompresses it before processing it. But it is risky because the gateway might not support that algorithm and return an HTTP error because there is no way to check if the server supports compression from the consumer side. Before configuring this feature on the client side, make sure that the gateway supports the compression algorithm that the client supports.
This doesn't need ANY EXTRA configuration on the gateway side, and should be supported by default. Maybe the supported algorithms can be configured so that the gateway can send those back in Accept-Encoding.
const res = await fetch('http://localhost:4000/graphql', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Encoding': 'gzip'
},
// Compress the request body
body: gzip(
JSON.stringify({
query: `
query {
hello
}
`
})
)
})From the subgraph to the gateway
When the subgraph sends a response to the gateway, it can be compressed by the subgraph so the gateway should decompress it by using the algorithms defined in the Content-Encoding header.
But the subgraph should respect the list of the algorithms provided in Accept-Encoding header before.
So only when a subgraph receives a request with Accept-Encoding header, it CAN compress and send that compressed data.
However, that having that Accept-Encoding doesn't mean that subgraph will always send a compressed body.
This feature doesn't need ANY EXTRA configuration, and should be supported by the gateway already. Maybe the supported algorithms can be configured so that the gateway can send those back in Accept-Encoding as in the case above.
From the gateway to the subgraph
The gateway can compress the payload with a specified algorithm in the CONFIGURATION. If the subgraph does not support compression, the gateway will receive an unexpected error. So make sure that the subgraph supports the compression algorithm that the gateway supports. Because there is no way to check the subgraph’s support for compression since the gateway is acting like a client here.
That's when we need a configuration to specify supported subgraphs or enable compression for all subgraphs.
The configuration is something like below in Cosmo, Apollo and Hive Gateways and Routers.
compression:
subgraphs: ['*'] # Enable compression for all subgraphs
# or
subgraphs: ['subgraph1', 'subgraph2'] # Enable compression for specific subgraphs