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

Update to Fastify v4 #224

Merged
merged 4 commits into from
May 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,9 @@ jobs:
strategy:
matrix:
node-version:
- 10
- 12
- 14
- 16
- 17
- 18
os:
- macos-latest
- ubuntu-latest
Expand Down
64 changes: 31 additions & 33 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ The plugin automatically decides if a payload should be compressed based on its
### Global hook
The global compression hook is enabled by default. To disable it, pass the option `{ global: false }`:
```javascript
fastify.register(
require('@fastify/compress'),
await fastify.register(
import('@fastify/compress'),
{ global: false }
)
```
Expand All @@ -46,8 +46,8 @@ Important note! If you are using `@fastify/compress` plugin together with `@fast
### Per Route options
You can specify different options for compression per route by passing in the `compress` options on the route's configuration.
```javascript
fastify.register(
require('@fastify/compress'),
await fastify.register(
import('@fastify/compress'),
climba03003 marked this conversation as resolved.
Show resolved Hide resolved
{ global: false }
)

Expand All @@ -74,47 +74,45 @@ Note that the compress method is configured with either the per route parameters
the plugin was defined as global.

```javascript
const fs = require('fs')
const fastify = require('fastify')()
import fs from 'fs'
import fastify from 'fastify'

fastify.register(require('@fastify/compress'), { global: false })
const app = fastify()
await app.register(import('@fastify/compress'), { global: false })

fastify.get('/', (req, reply) => {
app.get('/', (req, reply) => {
reply
.type('text/plain')
.compress(fs.createReadStream('./package.json'))
})

fastify.listen(3000, function (err) {
if (err) throw err
console.log(`server listening on ${fastify.server.address().port}`)
})
await app.listen(3000)
```

## Compress Options

### threshold
The minimum byte size for a response to be compressed. Defaults to `1024`.
```javascript
fastify.register(
require('@fastify/compress'),
await fastify.register(
import('@fastify/compress'),
{ threshold: 2048 }
)
```
### customTypes
[mime-db](https://github.com/jshttp/mime-db) is used to determine if a `content-type` should be compressed. You can compress additional content types via regular expression.
```javascript
fastify.register(
require('@fastify/compress'),
await fastify.register(
import('@fastify/compress'),
{ customTypes: /x-protobuf$/ }
)
```

### onUnsupportedEncoding
When the encoding is not supported, a custom error response can be sent in place of the uncompressed payload by setting the `onUnsupportedEncoding(encoding, request, reply)` option to be a function that can modify the reply and return a `string | Buffer | Stream | Error` payload.
```javascript
fastify.register(
require('@fastify/compress'),
await fastify.register(
import('@fastify/compress'),
{
onUnsupportedEncoding: (encoding, request, reply) => {
reply.code(406)
Expand All @@ -130,8 +128,8 @@ You can selectively disable response compression by using the `x-no-compression`
### Inflate pre-compressed bodies for clients that do not support compression
Optional feature to inflate pre-compressed data if the client does not include one of the supported compression types in its `accept-encoding` header.
```javascript
fastify.register(
require('@fastify/compress'),
await fastify.register(
import('@fastify/compress'),
{ inflateIfDeflated: true }
)

Expand All @@ -146,8 +144,8 @@ fastify.get('/file', (req, reply) =>
By default, `@fastify/compress` prioritizes compression as described [at the beginning of §Usage - Compress replies](#usage). You can change that by passing an array of compression tokens to the `encodings` option:

```javascript
fastify.register(
require('@fastify/compress'),
await fastify.register(
import('@fastify/compress'),
// Only support gzip and deflate, and prefer deflate to gzip
{ encodings: ['deflate', 'gzip'] }
)
Expand Down Expand Up @@ -176,7 +174,7 @@ By default, `@fastify/compress` removes the reply `Content-Length` header. You c

```javascript
// Global plugin scope
server.register(fastifyCompress, { global: true, removeContentLengthHeader: false });
await server.register(fastifyCompress, { global: true, removeContentLengthHeader: false });

// Route specific scope
fastify.get('/file', {
Expand Down Expand Up @@ -204,8 +202,8 @@ If the request header is missing, the plugin will not do anything and yield to t

The global request decompression hook is enabled by default. To disable it, pass the option `{ global: false }`:
```javascript
fastify.register(
require('@fastify/compress'),
await fastify.register(
import('@fastify/compress'),
{ global: false }
)
```
Expand All @@ -216,8 +214,8 @@ Remember that thanks to the Fastify encapsulation model, you can set a global de

You can specify different options for decompression per route by passing in the `decompress` options on the route's configuration.
```javascript
fastify.register(
require('@fastify/compress'),
await fastify.register(
import('@fastify/compress'),
{ global: false }
)

Expand All @@ -241,8 +239,8 @@ fastify.get('/custom-route', {
By default, `@fastify/compress` accepts all encodings specified [at the beginning of §Usage - Decompress request payloads](#usage). You can change that by passing an array of compression tokens to the `requestEncodings` option:

```javascript
fastify.register(
require('@fastify/compress'),
await fastify.register(
import('@fastify/compress'),
// Only support gzip
{ requestEncodings: ['gzip'] }
)
Expand All @@ -261,8 +259,8 @@ Note that if the request payload is not compressed, `@fastify/compress` will try
When the request payload encoding is not supported, you can customize the response error by setting the `onUnsupportedEncoding(request, encoding)` option to be a function that returns an error.

```javascript
fastify.register(
require('@fastify/compress'),
await fastify.register(
import('@fastify/compress'),
{
 onUnsupportedRequestEncoding: (request, encoding) => {
return {
Expand All @@ -281,8 +279,8 @@ fastify.register(
When the request payload cannot be decompressed using the detected algorithm, you can customize the response error setting the `onInvalidRequestPayload(request, encoding)` option to be a function that returns an error.

```javascript
fastify.register(
require('@fastify/compress'),
await fastify.register(
import('@fastify/compress'),
{
onInvalidRequestPayload: (request, encoding, error) => {
return {
Expand Down
20 changes: 10 additions & 10 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,8 @@ function processCompressParams (opts) {

params.encodings = Array.isArray(opts.encodings)
? supportedEncodings
.filter(encoding => opts.encodings.includes(encoding))
.sort((a, b) => opts.encodings.indexOf(a) - supportedEncodings.indexOf(b))
.filter(encoding => opts.encodings.includes(encoding))
.sort((a, b) => opts.encodings.indexOf(a) - supportedEncodings.indexOf(b))
: supportedEncodings

return params
Expand Down Expand Up @@ -175,8 +175,8 @@ function processDecompressParams (opts) {

params.encodings = Array.isArray(opts.requestEncodings)
? supportedEncodings
.filter(encoding => opts.requestEncodings.includes(encoding))
.sort((a, b) => opts.requestEncodings.indexOf(a) - supportedEncodings.indexOf(b))
.filter(encoding => opts.requestEncodings.includes(encoding))
.sort((a, b) => opts.requestEncodings.indexOf(a) - supportedEncodings.indexOf(b))
: supportedEncodings

if (opts.forceRequestEncoding) {
Expand Down Expand Up @@ -268,8 +268,8 @@ function buildRouteCompress (fastify, params, routeOptions, decorateOnly) {

params.removeContentLengthHeader
? reply
.header('Content-Encoding', encoding)
.removeHeader('content-length')
.header('Content-Encoding', encoding)
.removeHeader('content-length')
: reply.header('Content-Encoding', encoding)

stream = zipStream(params.compressStream, encoding)
Expand Down Expand Up @@ -393,8 +393,8 @@ function compress (params) {

params.removeContentLengthHeader
? this
.header('Content-Encoding', encoding)
.removeHeader('content-length')
.header('Content-Encoding', encoding)
.removeHeader('content-length')
: this.header('Content-Encoding', encoding)

stream = zipStream(params.compressStream, encoding)
Expand Down Expand Up @@ -551,6 +551,6 @@ function createError (code, message, statusCode) {
}

module.exports = fp(compressPlugin, {
fastify: '3.x',
name: 'fastify-compress'
fastify: '4.x',
Copy link
Member

Choose a reason for hiding this comment

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

I think here we can keep ≥3, as the plugin code doesn't change. It only changes how plugin users are registering it. But this code as is could still work in v3.x

Suggested change
fastify: '4.x',
fastify: '>=3.x',

Copy link
Member Author

Choose a reason for hiding this comment

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

From past experiences, maintaining that is a nightmare. We need separate tests for v3 and v4. I prefer to bump the major so we can avoid any compatibility issues down the line.

name: '@fastify/compress'
})
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@
"@typescript-eslint/eslint-plugin": "^5.9.0",
"@typescript-eslint/parser": "^5.9.0",
"adm-zip": "^0.5.9",
"fastify": "^3.25.3",
"fastify": "^4.0.0-rc.2",
"jsonstream": "^1.0.3",
"pre-commit": "^1.2.2",
"standard": "^16.0.4",
"standard": "^17.0.0",
"tap": "^16.0.0",
"tsd": "^0.20.0",
"typescript": "^4.5.4"
Expand Down
26 changes: 14 additions & 12 deletions test/global-compress.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const AdmZip = require('adm-zip')
const JSONStream = require('jsonstream')
const Fastify = require('fastify')
const compressPlugin = require('../index')
const { once } = require('events')

test('When `global` is not set, it is `true` by default :', async (t) => {
t.test('it should compress Buffer data using brotli when `Accept-Encoding` request header is `br`', async (t) => {
Expand Down Expand Up @@ -343,7 +344,7 @@ test('It should send compressed Buffer data when `global` is `true` :', async (t
t.plan(1)

const fastify = Fastify()
fastify.register(compressPlugin, { global: true, threshold: 0 })
await fastify.register(compressPlugin, { global: true, threshold: 0 })

const buf = Buffer.from('hello world')
fastify.get('/', (request, reply) => {
Expand Down Expand Up @@ -1639,31 +1640,32 @@ test('It should return a serialized payload when `inflateIfDeflated` is `true` a
t.equal(two.payload, compressedBufferPayload.toString())
})

test('It should close the stream', (t) => {
t.plan(4)
test('It should close the stream', async (t) => {
t.plan(3)

const fastify = Fastify()
fastify.register(compressPlugin, { global: true })
await fastify.register(compressPlugin, { global: true })

const stream = createReadStream('./package.json')
const closed = once(stream, 'close')

fastify.get('/', (request, reply) => {
const stream = createReadStream('./package.json')
stream.on('close', () => t.ok('stream closed'))

reply
.type('text/plain')
.compress(stream)
})

fastify.inject({
const response = await fastify.inject({
url: '/',
method: 'GET'
}, (err, response) => {
t.error(err)

const file = readFileSync('./package.json', 'utf8')
t.equal(response.statusCode, 200)
t.equal(file, response.payload)
})

const file = readFileSync('./package.json', 'utf8')
t.equal(response.statusCode, 200)
t.equal(file, response.payload)
await closed
})

test('It should log an existing error with stream onEnd handler', async (t) => {
Expand Down
60 changes: 23 additions & 37 deletions test/routes-compress.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -225,27 +225,20 @@ test('When using routes `compress` settings :', async (t) => {
})

t.test('it should throw an error on invalid route `compress` settings', async (t) => {
t.plan(2)
t.plan(1)

const fastify = Fastify()
await fastify.register(compressPlugin, { global: false })

fastify.get('/', {
compress: 'bad config'
}, (request, reply) => {
reply.send('')
})

await fastify.inject({
url: '/',
method: 'GET',
headers: {
'accept-encoding': 'gzip'
}
}).catch((err) => {
t.type(err, Error)
try {
fastify.get('/', {
compress: 'bad config'
}, (request, reply) => {
reply.send('')
})
} catch (err) {
t.equal(err.message, 'Unknown value for route compress configuration')
})
}
})
})

Expand Down Expand Up @@ -385,32 +378,25 @@ test('When using the old routes `{ config: compress }` option :', async (t) => {
})

t.test('it should use the old routes `{ config: compress }` options over routes `compress` options', async (t) => {
t.plan(2)
t.plan(1)

const fastify = Fastify()
await fastify.register(compressPlugin, { global: false })

fastify.get('/', {
compress: {
zlib: { createGzip: () => zlib.createGzip() }
},
config: {
compress: 'bad config'
}
}, (request, reply) => {
reply.send('')
})

await fastify.inject({
url: '/',
method: 'GET',
headers: {
'accept-encoding': 'gzip'
}
}).catch((err) => {
t.type(err, Error)
try {
fastify.get('/', {
compress: {
zlib: { createGzip: () => zlib.createGzip() }
},
config: {
compress: 'bad config'
}
}, (request, reply) => {
reply.send('')
})
} catch (err) {
t.equal(err.message, 'Unknown value for route compress configuration')
})
}
})
})

Expand Down
Loading