The BinaryResponse class handles binary data responses including files, images, PDFs, and streaming content.
Binary Type
Supported binary data types:
type Binary = Blob | ArrayBuffer | Uint8Array | ReadableStream;
BinaryResponse.Base
A response class that extends the native Response class for binary content.
import { BinaryResponse } from '@apisr/response';
const blob = new Blob(['Hello, World!'], { type: 'text/plain' });
const response = new BinaryResponse.Base(blob, {
status: 200,
headers: {
'Content-Type': 'text/plain',
'Content-Disposition': 'attachment; filename="hello.txt"'
}
});
Constructor Parameters
Binary payload: Blob, ArrayBuffer, Uint8Array, or ReadableStream
Response initialization options
status - HTTP status code (default: 200)
statusText - HTTP status text
headers - HTTP headers
BinaryResponse.Options
Type alias for binary response initialization options:
interface Options {
headers?: HeadersInput;
status?: number;
statusText?: string;
}
Usage with ResponseHandler
The preferred way to create binary responses is through ResponseHandler.binary():
import { createResponseHandler } from '@apisr/response';
const handler = createResponseHandler({});
const blob = new Blob(['PDF content'], { type: 'application/pdf' });
const response = handler.binary(blob, {
headers: {
'Content-Type': 'application/pdf',
'Content-Disposition': 'attachment; filename="document.pdf"'
}
});
Common Use Cases
Serving PDF Files
import { createResponseHandler } from '@apisr/response';
const handler = createResponseHandler({});
export const GET = async () => {
const pdfBuffer = await generatePDF();
return handler.binary(pdfBuffer, {
headers: {
'Content-Type': 'application/pdf',
'Content-Disposition': 'attachment; filename="report.pdf"'
}
});
};
Serving Images
import { createResponseHandler } from '@apisr/response';
const handler = createResponseHandler({});
export const GET = async ({ params }) => {
const imageBuffer = await db.images.getById(params.id);
return handler.binary(imageBuffer, {
headers: {
'Content-Type': 'image/png',
'Cache-Control': 'public, max-age=31536000'
}
});
};
Streaming Large Files
import { createResponseHandler } from '@apisr/response';
const handler = createResponseHandler({});
export const GET = async ({ params }) => {
const stream = await getFileStream(params.id);
return handler.binary(stream, {
headers: {
'Content-Type': 'video/mp4',
'Content-Disposition': 'inline'
}
});
};
CSV Export
import { createResponseHandler } from '@apisr/response';
const handler = createResponseHandler({});
export const GET = async () => {
const data = await db.users.findMany();
const csv = convertToCSV(data);
const blob = new Blob([csv], { type: 'text/csv' });
return handler.binary(blob, {
headers: {
'Content-Type': 'text/csv',
'Content-Disposition': 'attachment; filename="users.csv"'
}
});
};
Excel Export
import { createResponseHandler } from '@apisr/response';
import * as XLSX from 'xlsx';
const handler = createResponseHandler({});
export const GET = async () => {
const data = await db.sales.findMany();
const worksheet = XLSX.utils.json_to_sheet(data);
const workbook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(workbook, worksheet, 'Sales');
const buffer = XLSX.write(workbook, { type: 'buffer', bookType: 'xlsx' });
return handler.binary(buffer, {
headers: {
'Content-Type': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'Content-Disposition': 'attachment; filename="sales.xlsx"'
}
});
};
Custom Binary Data Mapping
Configure how binary data is processed before sending:
import { createResponseHandler, options } from '@apisr/response';
const handler = createResponseHandler((opts) => ({
binary: opts.binary({
mapData: (data) => {
// Compress or transform binary data
return compressBinary(data);
},
headers: (data) => ({
'Content-Length': data.byteLength?.toString() ?? '0',
'X-Processed': 'true'
})
})
}));
Working with Different Binary Types
From Blob
const blob = new Blob(['content'], { type: 'text/plain' });
const response = handler.binary(blob);
From ArrayBuffer
const buffer = new ArrayBuffer(8);
const response = handler.binary(buffer, {
headers: { 'Content-Type': 'application/octet-stream' }
});
From Uint8Array
const uint8 = new Uint8Array([72, 101, 108, 108, 111]);
const response = handler.binary(uint8, {
headers: { 'Content-Type': 'application/octet-stream' }
});
From ReadableStream
const stream = new ReadableStream({
start(controller) {
controller.enqueue(new Uint8Array([1, 2, 3]));
controller.close();
}
});
const response = handler.binary(stream);
Inline Display
Display content in the browser (e.g., images, PDFs):
const response = handler.binary(imageBlob, {
headers: {
'Content-Type': 'image/jpeg',
'Content-Disposition': 'inline'
}
});
Force Download
Force browser to download the file:
const response = handler.binary(pdfBlob, {
headers: {
'Content-Type': 'application/pdf',
'Content-Disposition': 'attachment; filename="document.pdf"'
}
});
With Custom Filename
const filename = `report-${new Date().toISOString()}.pdf`;
const response = handler.binary(pdfBlob, {
headers: {
'Content-Disposition': `attachment; filename="${filename}"`
}
});
Common MIME Types
const mimeTypes = {
pdf: 'application/pdf',
jpeg: 'image/jpeg',
png: 'image/png',
gif: 'image/gif',
webp: 'image/webp',
svg: 'image/svg+xml',
mp4: 'video/mp4',
mp3: 'audio/mpeg',
zip: 'application/zip',
csv: 'text/csv',
xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
};
Security Considerations
Validate File Types
export const GET = async ({ params }) => {
const file = await db.files.getById(params.id);
const allowedTypes = ['image/jpeg', 'image/png', 'application/pdf'];
if (!allowedTypes.includes(file.mimeType)) {
return handler.fail('badRequest');
}
return handler.binary(file.data, {
headers: { 'Content-Type': file.mimeType }
});
};
Sanitize Filenames
function sanitizeFilename(filename: string): string {
return filename.replace(/[^a-zA-Z0-9.-]/g, '_');
}
const safeFilename = sanitizeFilename(userProvidedFilename);
const response = handler.binary(blob, {
headers: {
'Content-Disposition': `attachment; filename="${safeFilename}"`
}
});