Fastify plugin providing compression and decompression utilities for HTTP responses and requests.
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Automatic decompression of compressed request payloads with support for multiple encoding algorithms, forced encoding modes, and comprehensive error handling.
When enabled globally or per-route, the plugin automatically decompresses incoming request payloads based on Content-Encoding headers.
// Automatic decompression is enabled via plugin registration
// Handled by preParsing hooks - no additional API calls neededDecompression Process:
Content-Encoding header in incoming requestsUsage Examples:
const fastify = require('fastify')({ logger: true });
// Enable request decompression globally
await fastify.register(require('@fastify/compress'), {
global: true,
requestEncodings: ['gzip', 'deflate', 'br']
});
// This route will automatically decompress compressed request bodies
fastify.post('/api/data', async (request, reply) => {
// request.body is automatically decompressed
console.log('Received data:', request.body);
return { received: Object.keys(request.body).length };
});
// Send compressed request:
// curl -X POST http://localhost:3000/api/data \
// -H "Content-Encoding: gzip" \
// -H "Content-Type: application/json" \
// --data-binary @<(echo '{"large":"data"}' | gzip)The plugin supports the same algorithms for request decompression as response compression.
/**
* Supported decompression encoding identifiers
*/
type EncodingToken = 'zstd' | 'br' | 'gzip' | 'deflate' | 'identity';Algorithm Support:
gzip - Gzip decompression using Node.js zlib.createGunzip()deflate - Deflate decompression using Node.js zlib.createInflate()br - Brotli decompression using Node.js zlib.createBrotliDecompress()zstd - Zstandard decompression (Node.js 22.15+/23.8+) using zlib.createZstdDecompress()identity - No decompression (passthrough)Usage Examples:
// Configure supported decompression algorithms
await fastify.register(require('@fastify/compress'), {
requestEncodings: ['gzip', 'deflate'] // Only support gzip and deflate for requests
});
// Different encodings will be handled automatically:
// Content-Encoding: gzip -> uses createGunzip()
// Content-Encoding: deflate -> uses createInflate()
// Content-Encoding: br -> rejected (not in requestEncodings)Force decompression using a specific algorithm regardless of Content-Encoding header.
/**
* Force specific encoding for request decompression
*/
interface ForcedEncodingOptions {
/** Force specific encoding for decompression, ignoring Content-Encoding header */
forceRequestEncoding?: EncodingToken;
}Usage Examples:
// Force all requests to be treated as gzip-compressed
await fastify.register(require('@fastify/compress'), {
forceRequestEncoding: 'gzip',
requestEncodings: ['gzip'] // Must include forced encoding
});
// Route-level forced encoding
fastify.post('/api/gzip-only', {
decompress: {
forceRequestEncoding: 'gzip'
}
}, async (request, reply) => {
// All request bodies treated as gzip-compressed
// regardless of Content-Encoding header
return { decompressed: request.body };
});Configure decompression behavior on a per-route basis, overriding global settings.
/**
* Route-level decompression configuration
*/
interface RouteOptions {
/** Route-specific decompression options, or false to disable */
decompress?: RouteDecompressOptions | false;
}
type RouteDecompressOptions = Pick<FastifyCompressOptions,
| 'forceRequestEncoding'
| 'onInvalidRequestPayload'
| 'onUnsupportedRequestEncoding'
| 'requestEncodings'
| 'zlib'
>;Usage Examples:
// Route with custom decompression settings
fastify.post('/api/secure-upload', {
decompress: {
requestEncodings: ['br'], // Only accept Brotli compression
onUnsupportedRequestEncoding: (encoding, request) => {
return new Error(`Secure endpoint requires Brotli compression, got: ${encoding}`);
}
}
}, async (request, reply) => {
return { received: 'secure data' };
});
// Route with decompression disabled
fastify.post('/api/raw', {
decompress: false
}, async (request, reply) => {
// request.body will be the raw compressed data
return { size: request.body.length };
});
// Route with forced encoding and custom error handling
fastify.post('/api/legacy', {
decompress: {
forceRequestEncoding: 'deflate',
onInvalidRequestPayload: (encoding, request, error) => {
request.log.error(`Legacy endpoint decompression failed: ${error.message}`);
return new Error('Invalid legacy format payload');
}
}
}, async (request, reply) => {
return { processed: request.body };
});Comprehensive error handling for unsupported encodings and decompression failures.
/**
* Handler for unsupported request Content-Encoding values
* @param encoding - The unsupported encoding from Content-Encoding header
* @param request - Fastify request object
* @param reply - Fastify reply object
* @returns Error to throw, or null/undefined to use default error
*/
type UnsupportedRequestEncodingHandler = (
encoding: string,
request: FastifyRequest,
reply: FastifyReply
) => Error | undefined | null;
/**
* Handler for invalid compressed request payloads
* @param encoding - The encoding that failed to decompress
* @param request - Fastify request object
* @param error - The decompression error
* @returns Error to throw, or null/undefined to use default error
*/
type InvalidRequestPayloadHandler = (
encoding: string,
request: FastifyRequest,
error: Error
) => Error | undefined | null;Default Error Responses:
/**
* Default error for unsupported Content-Encoding
*/
class InvalidRequestEncodingError extends Error {
name: 'FastifyCompressError';
code: 'FST_CP_ERR_INVALID_CONTENT_ENCODING';
statusCode: 415;
message: 'Unsupported Content-Encoding: {encoding}';
}
/**
* Default error for invalid compressed payload
*/
class InvalidRequestCompressedPayloadError extends Error {
name: 'FastifyCompressError';
code: 'FST_CP_ERR_INVALID_CONTENT';
statusCode: 400;
message: 'Could not decompress the request payload using the provided encoding';
}Usage Examples:
// Custom error handling
await fastify.register(require('@fastify/compress'), {
requestEncodings: ['gzip', 'deflate', 'br'],
onUnsupportedRequestEncoding: (encoding, request) => {
// Log unsupported encoding attempts
request.log.warn(`Rejected unsupported encoding: ${encoding} from ${request.ip}`);
// Return custom error
const error = new Error(`Compression format '${encoding}' is not supported`);
error.statusCode = 415;
return error;
},
onInvalidRequestPayload: (encoding, request, error) => {
// Log decompression failures with context
request.log.error({
encoding,
contentLength: request.headers['content-length'],
error: error.message
}, 'Request decompression failed');
// Return custom error with details
const customError = new Error(`Invalid ${encoding} compressed data: ${error.message}`);
customError.statusCode = 400;
customError.code = 'INVALID_COMPRESSED_PAYLOAD';
return customError;
}
});
// Handle errors in routes
fastify.post('/api/upload', async (request, reply) => {
try {
// Process decompressed request body
return { processed: request.body };
} catch (error) {
if (error.code === 'FST_CP_ERR_INVALID_CONTENT_ENCODING') {
return reply.status(415).send({
error: 'Unsupported compression format',
supported: ['gzip', 'deflate', 'br']
});
}
throw error;
}
});The plugin handles streaming decompression for large request payloads efficiently.
Stream Processing Features:
Usage Examples:
// Handle large compressed uploads
fastify.post('/api/large-upload', {
decompress: {
requestEncodings: ['gzip', 'br']
}
}, async (request, reply) => {
// Plugin automatically handles streaming decompression
// request.body contains the fully decompressed payload
console.log(`Received ${request.body.length} bytes after decompression`);
return { status: 'received' };
});
// Monitor decompression progress (advanced usage)
fastify.addHook('preParsing', async (request, reply, payload) => {
if (request.headers['content-encoding']) {
// Track original compressed size
const originalSize = parseInt(request.headers['content-length'] || '0');
request.log.info(`Decompressing ${originalSize} bytes of ${request.headers['content-encoding']} data`);
}
});Request decompression works independently of Content-Type headers, focusing purely on Content-Encoding.
Usage Examples:
// Decompress various content types
fastify.post('/api/json', async (request, reply) => {
// Content-Type: application/json
// Content-Encoding: gzip
// -> Decompressed JSON in request.body
return { received: request.body };
});
fastify.post('/api/form', async (request, reply) => {
// Content-Type: application/x-www-form-urlencoded
// Content-Encoding: deflate
// -> Decompressed form data in request.body
return { fields: Object.keys(request.body) };
});
fastify.post('/api/binary', async (request, reply) => {
// Content-Type: application/octet-stream
// Content-Encoding: br
// -> Decompressed binary data in request.body
return { size: request.body.length };
});Request decompression integrates seamlessly with Fastify's built-in body parsing through the preParsing hook.
Processing Order:
request.bodyUsage Examples:
// JSON payload decompression and parsing
fastify.post('/api/json-data', async (request, reply) => {
// 1. Plugin decompresses gzip/deflate/br payload
// 2. Fastify parses JSON from decompressed data
// 3. request.body contains parsed JavaScript object
console.log('Parsed object:', request.body);
return { keys: Object.keys(request.body) };
});
// Multipart form decompression
fastify.register(require('@fastify/multipart'));
fastify.post('/api/form-upload', async (request, reply) => {
// 1. Plugin decompresses compressed multipart data
// 2. @fastify/multipart parses form fields and files
// 3. request.body contains multipart data
const parts = request.parts();
for await (const part of parts) {
console.log('Form field:', part.fieldname);
}
return { status: 'processed' };
});