Skip to content

Commit

Permalink
feat: move to compress and decompress route options and typescrip…
Browse files Browse the repository at this point in the history
…t improvements (#199)

* test (types): move `index.test-d.ts` file to `test/types` folder

* feat!: add `compress` and `decompress` route shorthand configuration properties

* test: update routes related tests

* types: update typescript types

* test (types): actually test typescript types

* docs: update documentation

* chore: add new npm scripts

* test: make sure the old `(de)compress` route option won't break

* fix: make sure the old `(de)compress` route option won't break

* fix: typo

* types: add `package.json` types entry

* refactor: use `request` instead of `req`

* fix (types): mark `config.(de)compress` use as deprecated
  • Loading branch information
darkgl0w authored Dec 1, 2021
1 parent 2fb87c7 commit c5919b0
Show file tree
Hide file tree
Showing 8 changed files with 437 additions and 161 deletions.
27 changes: 16 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,18 +51,20 @@ fastify.register(

// only compress if the payload is above a certain size and use brotli
fastify.get('/custom-route', {
config: {
compress: {
threshold: 128
brotli: brotli
}
compress: {
inflateIfDeflated: true,
threshold: 128,
zlib: {
createBrotliCompress: () => createYourCustomBrotliCompress(),
createGzip: () => createYourCustomGzip(),
createDeflate: () => createYourCustomDeflate()
}
}, (req, reply) => {
// ...
})
```
Note: Setting `config.compress = false` on any route will disable compression on the route even if global compression is enabled.
Note: Setting `compress = false` on any route will disable compression on the route even if global compression is enabled.
### `reply.compress`
This plugin adds a `compress` method to `reply` that accepts a stream or a string, and compresses it based on the `accept-encoding` header. If a JS object is passed in, it will be stringified to JSON.
Expand Down Expand Up @@ -204,12 +206,15 @@ fastify.register(

// Always decompress using gzip
fastify.get('/custom-route', {
config: {
decompress: {
forceRequestEncoding: 'gzip'
}
decompress: {
forceRequestEncoding: 'gzip',
zlib: {
createBrotliDecompress: () => createYourCustomBrotliDecompress(),
createGunzip: () => createYourCustomGunzip(),
createInflate: () => createYourCustomInflate()
}
}, (req, reply) => {
}
}, (req, reply) => {
// ...
})
```
Expand Down
96 changes: 72 additions & 24 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,79 @@
import { FastifyPlugin, FastifyReply, FastifyRequest } from 'fastify';
import { Input, InputObject } from 'into-stream';
import { Stream } from 'stream';
import { BrotliOptions, ZlibOptions } from 'zlib';
import {
FastifyPluginCallback,
FastifyReply,
FastifyRequest,
RawServerBase,
RawServerDefault
} from 'fastify'
import * as fastify from 'fastify'
import { Input, InputObject } from 'into-stream'
import { Stream } from 'stream'
import { BrotliOptions, ZlibOptions } from 'zlib'

type EncodingToken = 'br' | 'deflate' | 'gzip' | 'identity';

export interface FastifyCompressOptions {
brotliOptions?: BrotliOptions;
customTypes?: RegExp;
encodings?: EncodingToken[];
forceRequestEncoding?: EncodingToken;
global?: boolean;
inflateIfDeflated?: boolean;
onInvalidRequestPayload?: (encoding: string, request: FastifyRequest, error: Error) => Error | undefined | null;
onUnsupportedEncoding?: (encoding: string, request: FastifyRequest, reply: FastifyReply) => string | Buffer | Stream;
onUnsupportedRequestEncoding?: (encoding: string, request: FastifyRequest, reply: FastifyReply) => Error | undefined | null;
requestEncodings?: EncodingToken[];
threshold?: number;
zlib?: unknown;
zlibOptions?: ZlibOptions;
}

interface RouteCompressOptions extends Pick<FastifyCompressOptions,
| 'brotliOptions'
| 'customTypes'
| 'encodings'
| 'inflateIfDeflated'
| 'onUnsupportedEncoding'
| 'threshold'
| 'zlib'
| 'zlibOptions'
> {}

interface RouteDecompressOptions extends Pick<FastifyCompressOptions,
| 'forceRequestEncoding'
| 'onInvalidRequestPayload'
| 'onUnsupportedRequestEncoding'
| 'requestEncodings'
| 'zlib'
> {}

interface FastifyCompressRouteOptions {
compress?: RouteCompressOptions | false;
decompress?: RouteDecompressOptions | false;
}

export interface RouteOptions extends fastify.RouteOptions, FastifyCompressRouteOptions {}

export interface RoutesConfigCompressOptions {
/** @deprecated `config.compress` is deprecated, use `compress` shorthand option instead */
compress?: RouteCompressOptions | false;
/** @deprecated `config.decompress` is deprecated, use `decompress` shorthand option instead */
decompress?: RouteDecompressOptions | false;
}

declare module 'fastify' {
export interface FastifyContextConfig extends RoutesConfigCompressOptions {}

export interface RouteShorthandOptions<
RawServer extends RawServerBase = RawServerDefault
> extends FastifyCompressRouteOptions {}

declare module "fastify" {
interface FastifyReply {
compress(input: Stream | Input | InputObject): void;
}
}

type EncodingToken = 'br' | 'deflate' | 'gzip' | 'identity'

export interface FastifyCompressOptions {
global?: boolean
threshold?: number
customTypes?: RegExp
zlib?: NodeModule
brotliOptions?: BrotliOptions
zlibOptions?: ZlibOptions
inflateIfDeflated?: boolean
onUnsupportedEncoding?: (encoding: string, request: FastifyRequest, reply: FastifyReply) => string | Buffer | Stream
encodings?: Array<EncodingToken>
requestEncodings?: Array<EncodingToken>
forceRequestEncoding?: EncodingToken
  onUnsupportedRequestEncoding?: (encoding: string, request: FastifyRequest, reply: FastifyReply) => Error | undefined | null
onInvalidRequestPayload?: (encoding: string, request: FastifyRequest, error: Error) => Error | undefined | null
export interface RouteOptions extends FastifyCompressRouteOptions {}
}

declare const fastifyCompress: FastifyPlugin<FastifyCompressOptions>
export default fastifyCompress;
declare const fastifyCompress: FastifyPluginCallback<FastifyCompressOptions>
export default fastifyCompress
26 changes: 18 additions & 8 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,21 @@ function compressPlugin (fastify, opts, next) {

// add onSend hook onto each route as needed
fastify.addHook('onRoute', (routeOptions) => {
// Manage compression options
// If route config.compress has been set it takes precedence over compress
if (routeOptions.config && typeof routeOptions.config.compress !== 'undefined') {
if (typeof routeOptions.config.compress === 'object') {
routeOptions.compress = routeOptions.config.compress
}

// Manage compression options
if (typeof routeOptions.compress !== 'undefined') {
if (typeof routeOptions.compress === 'object') {
const mergedCompressParams = Object.assign(
{}, globalCompressParams, processCompressParams(routeOptions.config.compress)
{}, globalCompressParams, processCompressParams(routeOptions.compress)
)

// if the current endpoint has a custom compress configuration ...
buildRouteCompress(fastify, mergedCompressParams, routeOptions)
} else if (routeOptions.config.compress === false) {
} else if (routeOptions.compress === false) {
// don't apply any compress settings
} else {
throw new Error('Unknown value for route compress configuration')
Expand All @@ -76,16 +81,21 @@ function compressPlugin (fastify, opts, next) {
buildRouteCompress(fastify, globalCompressParams, routeOptions, true)
}

// Manage decompression options
// If route config.decompress has been set it takes precedence over compress
if (routeOptions.config && typeof routeOptions.config.decompress !== 'undefined') {
if (typeof routeOptions.config.decompress === 'object') {
routeOptions.decompress = routeOptions.config.decompress
}

// Manage decompression options
if (typeof routeOptions.decompress !== 'undefined') {
if (typeof routeOptions.decompress === 'object') {
// if the current endpoint has a custom compress configuration ...
const mergedDecompressParams = Object.assign(
{}, globalDecompressParams, processDecompressParams(routeOptions.config.decompress)
{}, globalDecompressParams, processDecompressParams(routeOptions.decompress)
)

buildRouteDecompress(fastify, mergedDecompressParams, routeOptions)
} else if (routeOptions.config.decompress === false) {
} else if (routeOptions.decompress === false) {
// don't apply any decompress settings
} else {
throw new Error('Unknown value for route decompress configuration')
Expand Down
18 changes: 12 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"version": "3.6.1",
"description": "Fastify compression utils",
"main": "index.js",
"types": "index.d.ts",
"dependencies": {
"encoding-negotiator": "^2.0.1",
"fastify-plugin": "^3.0.0",
Expand Down Expand Up @@ -34,11 +35,16 @@
},
"scripts": {
"coverage": "npm run unit -- --cov",
"coverage-report": "npm run coverage && tap --coverage-report=lcov",
"lint:typescript": "standard --fix --parser @typescript-eslint/parser --plugin typescript test/types/*.ts",
"test": "standard && npm run unit && npm run typescript",
"typescript": "tsd",
"unit": "tap -J test/*.js"
"coverage-report": "npm run coverage -- --coverage-report=lcov",
"lint": "standard",
"lint:fix": "npm run lint -- --fix",
"lint:typescript": "npm run lint:fix -- --parser @typescript-eslint/parser --plugin typescript test/types/*.ts",
"lint:types": "npm run lint:fix -- --parser @typescript-eslint/parser --plugin typescript *.d.ts",
"test": "npm run lint && npm run unit && npm run test:typescript",
"test:typescript": "tsd",
"unit": "tap -J test/*.js",
"unit:report": "npm run unit -- --cov --coverage-report=html",
"unit:verbose": "npm run unit -- -Rspec"
},
"keywords": [
"fastify",
Expand All @@ -61,6 +67,6 @@
"node": ">=10.16"
},
"tsd": {
"directory": "test"
"directory": "test/types"
}
}
35 changes: 0 additions & 35 deletions test/index.test-d.ts

This file was deleted.

Loading

0 comments on commit c5919b0

Please sign in to comment.