### Install @fastify/reply-from Source: https://github.com/fastify/fastify-reply-from/blob/main/README.md Install the plugin using npm. ```bash npm i @fastify/reply-from ``` -------------------------------- ### Forward GET as POST Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/usage-examples.md This example illustrates forwarding an incoming GET request to an upstream server, overriding the method to POST and sending data in the request body. ```javascript // Forward GET as POST proxy.get('/api/action', (request, reply) => { reply.from('/api/action', { method: 'POST', body: { action: request.query.action } }) }) ``` -------------------------------- ### Basic Setup Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/quick-reference.md Demonstrates how to register the @fastify/reply-from plugin and use the `reply.from()` method to forward requests. ```APIDOC ## Basic Setup ```javascript const Fastify = require('fastify') const fastifyReplyFrom = require('@fastify/reply-from') const fastify = Fastify() fastify.register(fastifyReplyFrom, { base: 'http://api.example.com/' }) fastify.get('*', (request, reply) => { reply.from(request.url) }) fastify.listen({ port: 3000 }) ``` ``` -------------------------------- ### CommonJS Usage Example Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/exports-reference.md Demonstrates how to register and use the fastify-reply-from plugin in a CommonJS environment. Requires importing Fastify and the plugin. ```javascript const Fastify = require('fastify') const fastifyReplyFrom = require('@fastify/reply-from') const fastify = Fastify() fastify.register(fastifyReplyFrom, { base: 'http://upstream.com/' }) fastify.get('/', (request, reply) => { reply.from('/') }) ``` -------------------------------- ### TypeScript Usage Example Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/exports-reference.md Illustrates using the fastify-reply-from plugin in a TypeScript project. It includes importing types and configuring the plugin with options. ```typescript import Fastify from 'fastify' import fastifyReplyFrom, { FastifyReplyFromOptions } from '@fastify/reply-from' const fastify = Fastify() const opts: FastifyReplyFromOptions = { base: 'http://upstream.com/' } fastify.register(fastifyReplyFrom, opts) fastify.get('/', (request, reply) => { reply.from('/') }) fastify.listen({ port: 3000 }) ``` -------------------------------- ### Forward POST as GET Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/usage-examples.md This snippet shows how to forward an incoming POST request to an upstream server, but with the method overridden to GET. It also demonstrates passing query parameters and setting the request body to null. ```javascript proxy.register(fastifyReplyFrom, { base: 'http://api.example.com/' }) // Forward POST as GET proxy.post('/api/search', (request, reply) => { reply.from('/api/search', { method: 'GET', queryString: { q: request.body.query }, body: null }) }) ``` -------------------------------- ### Basic Proxy Setup Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/usage-examples.md Sets up a Fastify server to proxy all incoming requests to a specified base URL. Ensure the Fastify server is running on port 3000. ```javascript const Fastify = require('fastify') const fastifyReplyFrom = require('@fastify/reply-from') const proxy = Fastify({ logger: true }) proxy.register(fastifyReplyFrom, { base: 'http://api.example.com/' }) proxy.get('*', (request, reply) => { reply.from(request.url) }) proxy.listen({ port: 3000 }) ``` -------------------------------- ### Basic Fastify Setup with Reply From Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/quick-reference.md Register the @fastify/reply-from plugin and set a base URL for forwarding requests. All incoming requests to the Fastify server will be forwarded to the configured upstream base URL. ```javascript const Fastify = require('fastify') const fastifyReplyFrom = require('@fastify/reply-from') const fastify = Fastify() fastify.register(fastifyReplyFrom, { base: 'http://api.example.com/' }) fastify.get('*', (request, reply) => { reply.from(request.url) }) fastify.listen({ port: 3000 }) ``` -------------------------------- ### Use Global Agents with Proxy Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/api-reference.md Enable the use of global HTTP/HTTPS agents or the global undici dispatcher. This example configures a proxy agent. ```javascript const { setGlobalDispatcher, ProxyAgent } = require('undici') setGlobalDispatcher(new ProxyAgent('http://my-proxy:8080')) fastify.register(fastifyReplyFrom, { base: 'http://localhost:3001/', globalAgent: true }) ``` -------------------------------- ### TypeScript Usage with Options and Hooks Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/usage-examples.md Example demonstrating TypeScript usage with `fastify-reply-from`, including plugin options for connection pooling and hooks for rewriting request headers. ```typescript import Fastify from 'fastify' import fastifyReplyFrom, { FastifyReplyFromOptions, FastifyReplyFromHooks } from '@fastify/reply-from' const fastify = Fastify() const pluginOpts: FastifyReplyFromOptions = { base: 'http://api.example.com/', undici: { connections: 256, pipelining: 2 } } fastify.register(fastifyReplyFrom, pluginOpts) fastify.get<{ Params: { '*': string } }>('/api/*', (request, reply) => { const hookOpts: FastifyReplyFromHooks = { rewriteRequestHeaders: (request, headers) => { headers['x-request-id'] = request.id return headers } } reply.from('/api/' + request.params['*'], hookOpts) }) fastify.listen({ port: 3000 }) ``` -------------------------------- ### ESM Usage Example Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/exports-reference.md Shows how to use the fastify-reply-from plugin with ECMAScript Modules (ESM). This involves using import statements and async/await for registration. ```javascript import Fastify from 'fastify' import fastifyReplyFrom from '@fastify/reply-from' const fastify = Fastify() await fastify.register(fastifyReplyFrom, { base: 'http://upstream.com/' }) fastify.get('/', (request, reply) => { reply.from('/') }) await fastify.listen({ port: 3000 }) ``` -------------------------------- ### Proxy with Authentication Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/quick-reference.md Add authentication headers to proxied requests. This example shows how to dynamically set the 'authorization' header using an environment variable. ```javascript reply.from('/api/users', { rewriteRequestHeaders: (request, headers) => { headers['authorization'] = 'Bearer ' + process.env.TOKEN return headers } }) ``` -------------------------------- ### Full Example: Fastify Reply From Plugin Registration and Usage Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/api-reference.md Demonstrates registering the Fastify Reply From plugin with custom Undici options and setting up a route to forward requests. The plugin is configured with a base URL and specific Undici connection settings. ```javascript const Fastify = require('fastify') const fastifyReplyFrom = require('@fastify/reply-from') const fastify = Fastify({ logger: true }) fastify.register(fastifyReplyFrom, { base: 'http://localhost:3001/', undici: { connections: 128, keepAliveTimeout: 60000 } }) fastify.get('/api/*', (request, reply) => { reply.from('/api/' + request.params['*']) }) fastify.listen({ port: 3000 }) ``` -------------------------------- ### Basic Request Forwarding Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/api-reference.md Forward a request to a specific path on the target server. This example forwards requests from '/proxy/*' to '/api/*' on the upstream server. ```javascript fastify.get('/proxy/*', (request, reply) => { // Forward to /api/ path on target server reply.from('/api/' + request.params['*']) }) ``` -------------------------------- ### Enable Request Logging Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/usage-examples.md Configure `fastify-reply-from` to keep request logging enabled. This example also shows how to log response details within hooks. ```javascript proxy.register(fastifyReplyFrom, { base: 'http://api.example.com/', disableRequestLogging: false // Keep logging enabled }) // Also log in hooks proxy.get('/api/*', (request, reply) => { const startTime = Date.now() reply.from('/api/' + request.params['*'], { onResponse: (request, reply, res) => { const duration = Date.now() - startTime request.log.info({ status: res.statusCode, duration }, 'Response received') reply.send(res.stream) }, onError: (reply, { error }) => { request.log.error(error, 'Upstream error') reply.code(error.statusCode || 500).send(error) } }) }) ``` -------------------------------- ### Example Usage of QueryStringFunction Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/types.md Demonstrates how to implement a QueryStringFunction to add custom parameters to the query string based on the request object. ```typescript const handler: QueryStringFunction = (search, reqUrl, request) => { // Add custom parameters based on request return 'key=value&custom=' + request.query.filter } ``` -------------------------------- ### Configure Retry Methods Source: https://github.com/fastify/fastify-reply-from/blob/main/README.md Specify HTTP methods for which connection retries should occur on socket hang up. Default methods are ['GET', 'HEAD', 'OPTIONS', 'TRACE']. Retries on 503 errors are always performed unless 'GET' is excluded from retryMethods. ```javascript ['GET', 'HEAD', 'OPTIONS', 'TRACE'] ``` -------------------------------- ### Performance Monitoring with Response Time Header Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/usage-examples.md Measure and report the upstream response time by adding an `x-response-time` header. This example uses `process.hrtime` for precise timing. ```javascript proxy.register(fastifyReplyFrom, { base: 'http://api.example.com/' }) proxy.all('/api/*', (request, reply) => { const startTime = process.hrtime.bigint() reply.from('/api/' + request.params['*'], { onResponse: (request, reply, res) => { const endTime = process.hrtime.bigint() const duration = Number(endTime - startTime) / 1_000_000 // Convert to ms reply.header('x-response-time', duration) reply.send(res.stream) } }) }) ``` -------------------------------- ### Conditional Upstream Selection Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/usage-examples.md This example shows how to conditionally select an upstream server based on request headers or user roles. It allows routing specific requests to different servers, such as beta testers or administrators. ```javascript proxy.register(fastifyReplyFrom, { base: 'http://production.internal/' }) proxy.all('/api/*', (request, reply) => { reply.from('/api/' + request.params['*'], { getUpstream: (request, base) => { // Route beta users to beta server if (request.headers['x-beta-tester']) { return 'http://beta.internal/' } // Route admin to special server if (request.user?.role === 'admin') { return 'http://admin.internal/' } return base } }) }) ``` -------------------------------- ### API Gateway Proxy Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/quick-reference.md Configure fastify-reply-from as an API gateway to proxy requests starting with '/api/'. It dynamically constructs the target URL. ```javascript fastify.all('/api/*', (request, reply) => { reply.from('/api/' + request.params['*']) }) ``` -------------------------------- ### Production Fastify Reply From Configuration Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/README.md Configure the plugin for production with multiple API endpoints, advanced Undici options for connection pooling and pipelining, disabled request logging, and URL caching. This setup optimizes performance and reliability. ```javascript fastify.register(fastifyReplyFrom, { base: [ 'http://api-1.internal:8080', 'http://api-2.internal:8080', 'http://api-3.internal:8080' ], undici: { connections: 256, pipelining: 2, keepAliveTimeout: 120000 }, disableRequestLogging: true, cacheURLs: 1000, destroyAgent: true }) ``` -------------------------------- ### method Option Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/api-reference.md The method option allows overriding the HTTP method of the forwarded request. This can be used to change a request from POST to GET, for example, or to adapt an API. ```APIDOC ## method ### Description Overrides the HTTP method of the forwarded request. ### Type `string` (HTTPMethods) ### Default Original request method ### Required No ### Example ```javascript reply.from('/api/cache', { method: 'GET' // Convert POST to GET }) ``` ``` -------------------------------- ### Override HTTP Method with method Option Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/api-reference.md The `method` option allows overriding the HTTP method of the forwarded request. This can be used, for example, to convert a POST request to a GET request. ```javascript reply.from('/api/cache', { method: 'GET' // Convert POST to GET }) ``` -------------------------------- ### Configure Max Retries on 503 Errors Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/api-reference.md Set the maximum number of retry attempts for 503 Service Unavailable errors on GET requests. This is only effective if GET is included in 'retryMethods'. ```javascript fastify.register(fastifyReplyFrom, { base: 'http://localhost:3001/', maxRetriesOn503: 5 }) ``` -------------------------------- ### Check Configuration at Startup Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/quick-reference.md Register the fastifyReplyFrom plugin and log success or error messages to verify its configuration at startup. This ensures the plugin is ready before application use. ```javascript fastify.register(fastifyReplyFrom, opts) .then(() => console.log('Plugin registered successfully')) .catch((err) => console.error('Plugin error:', err)) ``` -------------------------------- ### Minimal Configuration for Reply From Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/configuration-guide.md Sets up the plugin to forward all requests to a specified base URL using undici with default settings. ```javascript fastify.register(fastifyReplyFrom, { base: 'http://api.example.com/' }) ``` -------------------------------- ### Custom Response Handling During Forwarding Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/api-reference.md Handle the response from the forwarded request, for example, by removing headers or transforming the response body. This example removes 'content-length' and sends a custom JSON object. ```javascript fastify.get('/data', (request, reply) => { reply.from('/upstream/data', { onResponse: (request, reply, res) => { reply.removeHeader('content-length') reply.send({ proxied: true, data: res.stream }) } }) }) ``` -------------------------------- ### Pseudo-Header Filtering Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/implementation-details.md Removes HTTP/2 pseudo-headers, which start with a colon (':'), from a headers object. ```javascript filterPseudoHeaders(headers) // Removes HTTP/2 pseudo-headers (starting with ':') ``` -------------------------------- ### Importing Fastify Reply From Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/exports-reference.md Demonstrates various ways to import the fastifyReplyFrom plugin using CommonJS and ESM module systems. ```javascript // CommonJS - Default import const fastifyReplyFrom = require('@fastify/reply-from') // CommonJS - Named import const { fastifyReplyFrom } = require('@fastify/reply-from') // ESM - Default import import fastifyReplyFrom from '@fastify/reply-from' // ESM - Named import import { fastifyReplyFrom } from '@fastify/reply-from' ``` -------------------------------- ### Filter HTTP/2 Pseudo-Headers Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/api-reference.md Remove HTTP/2 pseudo-headers (those starting with ':') from a headers object. This is useful for preparing headers for forwarding or processing. ```javascript const { filterPseudoHeaders } = require('@fastify/reply-from/lib/utils') const filtered = filterPseudoHeaders({ ':status': 200, 'content-type': 'application/json', ':path': '/api' }) // Returns: { 'content-type': 'application/json' } ``` -------------------------------- ### Global Configuration Options Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/quick-reference.md Configure the @fastify/reply-from plugin globally during registration. Options include setting the base URL, enabling HTTP/2, configuring agents, and controlling caching and logging. ```json { "base": "http://api.example.com/", // Single or multiple origins "http2": true | Http2Options, // Enable HTTP/2 "http": HttpOptions, // Node.js http agent config "undici": UndiciOptions | Pool | Client, // Undici client config "contentTypesToEncode": ['application/json'], // Auto-JSON-encode these types "retryMethods": ['GET', 'HEAD', 'OPTIONS'], // Methods to retry on socket error "maxRetriesOn503": 10, // Max retries on 503 "cacheURLs": 100, // URL cache size "disableCache": false, // Disable URL caching "disableRequestLogging": false, // Disable request logging "globalAgent": false, // Use global agents "destroyAgent": false // Destroy agents on close } ``` -------------------------------- ### Retry on 503 Service Unavailable Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/implementation-details.md Automatically retries GET requests that return a 503 status code, up to a maximum number of retries. ```javascript if (res && res.statusCode === 503 && req.method === 'GET') { if (retriesCount === 0 && retries < maxRetriesOn503) { return retryAfter // Trigger retry } } ``` -------------------------------- ### Global Configuration Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/quick-reference.md Lists the available global configuration options when registering the plugin. ```APIDOC ## Global Configuration (at registration) ```javascript { base: 'http://api.example.com/', // Single or multiple origins http2: true | Http2Options, // Enable HTTP/2 http: HttpOptions, // Node.js http agent config undici: UndiciOptions | Pool | Client, // Undici client config contentTypesToEncode: ['application/json'], // Auto-JSON-encode these types retryMethods: ['GET', 'HEAD', 'OPTIONS'], // Methods to retry on socket error maxRetriesOn503: 10, // Max retries on 503 cacheURLs: 100, // URL cache size disableCache: false, // Disable URL caching disableRequestLogging: false, // Disable request logging globalAgent: false, // Use global agents destroyAgent: false // Destroy agents on close } ``` ``` -------------------------------- ### Proxy with Stream Transformation Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/usage-examples.md Process a streaming response from a proxied request by piping it through a transform stream. This example converts the stream content to uppercase. ```javascript const { Transform } = require('stream') proxy.get('/api/stream', (request, reply) => { reply.from('/api/stream', { onResponse: (request, reply, res) => { const transform = new Transform({ transform(chunk, encoding, callback) { // Process each chunk const modified = chunk.toString().toUpperCase() callback(null, modified) } }) reply.type('text/plain') res.stream.pipe(transform).pipe(reply.raw) } }) }) ``` -------------------------------- ### Register Fastify Reply From Plugin Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/configuration-guide.md Register the plugin with Fastify. All global configuration is applied at registration time. ```javascript const Fastify = require('fastify') const fastifyReplyFrom = require('@fastify/reply-from') const fastify = Fastify() fastify.register(fastifyReplyFrom, { // Configuration options go here }) ``` -------------------------------- ### Transform Request Body Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/usage-examples.md Transform the incoming request body into a different format or structure. This example converts form data to a JSON object. ```javascript proxy.post('/api/submit', (request, reply) => { // Convert form data to JSON const jsonBody = { username: request.body.user, email: request.body.email_address, role: 'user' } reply.from('/api/register', { body: jsonBody }) }) ``` -------------------------------- ### Basic Usage: Forward Request Between Fastify Servers Source: https://github.com/fastify/fastify-reply-from/blob/main/README.md Set up two Fastify servers and forward a request from a proxy server to a target server. Ensure the target server is listening before the proxy server attempts to forward requests. ```javascript 'use strict' const Fastify = require('fastify') const target = Fastify({ logger: true }) target.get('/', (request, reply) => { reply.send('hello world') }) const proxy = Fastify({ logger: true }) proxy.register(require('@fastify/reply-from'), { base: 'http://localhost:3001/' }) proxy.get('/', (request, reply) => { reply.from('/') }) target.listen({ port: 3001 }, (err) => { if (err) { throw err } proxy.listen({ port: 3000 }, (err) => { if (err) { throw err } }) }) ``` -------------------------------- ### TypeScript Configuration and Usage Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/configuration-guide.md Configure Fastify Reply From with TypeScript, including advanced HTTP/2 session and request timeouts. Demonstrates setting up custom hooks for requests, such as rewriting headers. ```typescript import Fastify from 'fastify' import fastifyReplyFrom, { FastifyReplyFromOptions, Http2Options, FastifyReplyFromHooks } from '@fastify/reply-from' const fastify = Fastify() const options: FastifyReplyFromOptions = { base: 'http://api.example.com/', http2: { sessionTimeout: 30000, requestTimeout: 10000 } } fastify.register(fastifyReplyFrom, options) fastify.get('/data', (request, reply) => { const hookOptions: FastifyReplyFromHooks = { timeout: 5000, rewriteHeaders: (headers) => { delete headers['authorization'] return headers } } reply.from('/api/data', hookOptions) }) ``` -------------------------------- ### Get Connection Headers for Removal Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/api-reference.md Parse the 'Connection' header to identify and extract a list of header names that should be removed. This is useful for managing connection-specific headers. ```javascript const { getConnectionHeaders } = require('@fastify/reply-from/lib/utils') const toRemove = getConnectionHeaders({ 'connection': 'upgrade, keep-alive, custom-header' }) // Returns: ['upgrade', 'keep-alive', 'custom-header'] ``` -------------------------------- ### Round-Robin Load Balancing Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/usage-examples.md This snippet demonstrates setting up round-robin load balancing across multiple upstream servers. Requests to '/api/*' will be distributed automatically across the provided server list. ```javascript const proxy = Fastify() proxy.register(fastifyReplyFrom, { base: [ 'http://server1.internal:8080', 'http://server2.internal:8080', 'http://server3.internal:8080' ], undici: { connections: 256, pipelining: 2 } }) proxy.all('/api/*', (request, reply) => { reply.from('/api/' + request.params['*']) }) proxy.listen({ port: 3000 }) ``` -------------------------------- ### Enable HTTP/2 with Default Settings Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/api-reference.md Enable HTTP/2 support for forwarded requests using default configuration. This requires the 'base' option to be set. ```javascript fastify.register(fastifyReplyFrom, { base: 'http://localhost:3001/', http2: true }) ``` -------------------------------- ### Per-Request Custom Header Configuration Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/configuration-guide.md Modify or add headers to a specific outgoing request. This example adds an 'x-api-key' header using an environment variable. ```javascript fastify.get('/custom-headers', (request, reply) => { reply.from('/api/data', { rewriteRequestHeaders: (req, headers) => { headers['x-api-key'] = process.env.API_KEY return headers } }) }) ``` -------------------------------- ### Configure Undici Client with Proxy Source: https://github.com/fastify/fastify-reply-from/blob/main/README.md Set up a proxy server for the undici client to use when forwarding requests. This is configured within the `undici` options object. ```javascript proxy.register(require('@fastify/reply-from'), { base: 'http://localhost:3001/', undici: { proxy: 'http://my.proxy.server:8080', } }) ``` -------------------------------- ### Register Fastify Reply From Plugin Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/api-reference.md Register the plugin with Fastify, providing a base URL for forwarding requests. Ensure the plugin is registered using fastify.register(). ```javascript const fastifyReplyFrom = require('@fastify/reply-from') fastify.register(fastifyReplyFrom, { base: 'http://target-server.com/' }) ``` -------------------------------- ### Proxy with Custom Response Transformation Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/usage-examples.md Process and transform the response from a proxied request before sending it to the client. This example parses JSON, adds a timestamp, and modifies headers. ```javascript proxy.register(fastifyReplyFrom, { base: 'http://api.example.com/' }) proxy.get('/api/data', (request, reply) => { reply.from('/api/data', { onResponse: (request, reply, res) => { // Transform response before sending reply.removeHeader('content-length') const chunks = [] res.stream.on('data', chunk => chunks.push(chunk)) res.stream.on('end', () => { const data = JSON.parse(Buffer.concat(chunks)) reply.code(res.statusCode) reply.send({ ...data, processedAt: new Date(), proxy: true }) }) } }) }) ``` -------------------------------- ### Configure Fastify Reply From for Production Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/configuration-guide.md This configuration is optimized for production. It reduces logging overhead, increases connection pooling and pipelining for better performance, and enables agent destruction for clean shutdowns. ```javascript fastify.register(fastifyReplyFrom, { base: process.env.UPSTREAM_URL || 'http://api.internal:8080/', undici: { connections: 256, pipelining: 2, keepAliveTimeout: 120000 }, disableRequestLogging: true, // Reduce logging overhead cacheURLs: 1000, // Larger cache maxRetriesOn503: 3, // Limit retries destroyAgent: true // Clean shutdown }) ``` -------------------------------- ### Proxy Configuration with Global Dispatcher Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/configuration-guide.md Sets a global proxy dispatcher using undici's ProxyAgent, then registers the plugin with 'globalAgent: true'. ```javascript const { setGlobalDispatcher, ProxyAgent } = require('undici') setGlobalDispatcher( new ProxyAgent({ uri: 'http://my-proxy.com:8080', auth: 'user:password' }) ) fastify.register(fastifyReplyFrom, { base: 'http://api.example.com/', globalAgent: true }) ``` -------------------------------- ### Circuit Breaker Pattern Implementation Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/usage-examples.md Implement a circuit breaker pattern to prevent cascading failures. This example opens the circuit after a threshold of failures and resets it after a specified delay. ```javascript let failureCount = 0 let circuitOpen = false const isCircuitOpen = () => failureCount > 5 proxy.get('/api/critical', (request, reply) => { if (isCircuitOpen()) { return reply.code(503).send({ error: 'Service temporarily unavailable' }) } reply.from('/api/critical', { onError: (reply, { error }) => { failureCount++ if (failureCount > 5) { circuitOpen = true // Reset circuit after delay setTimeout(() => { circuitOpen = false failureCount = 0 }, 60000) } reply.code(error.statusCode || 500).send(error) } }) }) ``` -------------------------------- ### Configure Undici Client Options Source: https://github.com/fastify/fastify-reply-from/blob/main/README.md Customize the undici client settings for improved throughput. This includes options like `connections`, `pipelining`, `keepAliveTimeout`, and TLS settings. Ensure undici is enabled for these configurations. ```javascript proxy.register(require('@fastify/reply-from'), { base: 'http://localhost:3001/', // default settings undici: { connections: 128, pipelining: 1, keepAliveTimeout: 60 * 1000, tls: { rejectUnauthorized: false } } }) ``` -------------------------------- ### Protocol Selection Logic Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/implementation-details.md Determines which HTTP client to use based on configuration options like http2, undici, and base. ```javascript if (opts.http2) { // Use HTTP/2 client // Single persistent connection per session return { request: handleHttp2Req, ... } } else if (shouldUseUndici(opts)) { // Use Undici (undici by default for HTTP/1.1) // Check for BalancedPool (array base) // Check for custom instance // Check for unix sockets // Check for proxy configuration return { request: handleUndici, ... } } else { // Fall back to Node.js http/https agents return { request: handleHttp1Req, ... } } ``` -------------------------------- ### Handle Service Unavailable Error Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/errors.md Catch and handle the `FST_REPLY_FROM_SERVICE_UNAVAILABLE` error when the upstream service is unavailable. This example demonstrates checking the `statusCode` in the `onError` callback and responding with a custom error message. ```javascript fastify.get('/', (request, reply) => { reply.from('/api/data', { onError: (reply, { error }) => { if (error.statusCode === 503) { reply.send({ error: 'Service unavailable', retrying: true }) } } }) }) ``` -------------------------------- ### Filter HTTP/2 Pseudo-Headers Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/exports-reference.md Use this function to remove HTTP/2 pseudo-headers (those starting with ':') from a headers object. It also lowercases the remaining header names. This is essential when converting HTTP/2 requests to HTTP/1.1. ```javascript function filterPseudoHeaders(headers) { // Returns headers object without HTTP/2 pseudo-headers } ``` ```javascript const { filterPseudoHeaders } = require('@fastify/reply-from/lib/utils') const headers = { ':method': 'GET', ':path': '/api/users', 'content-type': 'application/json' } const filtered = filterPseudoHeaders(headers) // Returns: { 'content-type': 'application/json' } ``` -------------------------------- ### Configure Custom Undici Instance Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/api-reference.md Use a pre-instantiated undici Pool or Client for advanced control over the HTTP client. Ensure the pool's base URL matches the plugin's base option. ```javascript const { Pool } = require('undici') const pool = new Pool('http://localhost:3001/', { connections: 256, pipelining: 2 }) fastify.register(fastifyReplyFrom, { base: 'http://localhost:3001/', undici: pool }) ``` -------------------------------- ### Per-Request Configuration Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/quick-reference.md Details the configuration options available for individual `reply.from()` calls. ```APIDOC ## Per-Request Configuration (in reply.from) ```javascript reply.from(source, { method: 'GET', // Override HTTP method body: { ... }, // Replace request body contentType: 'application/json', // Override content-type timeout: 10000, // Request timeout in ms retriesCount: 0, // Retries on socket error queryString: {...} | function, // Replace/rewrite query string rewriteRequestHeaders: (request, headers) => headers, // Modify request headers rewriteHeaders: (headers, request) => headers, // Modify response headers getUpstream: (request, base) => base, // Dynamic upstream selection onResponse: (request, reply, res) => {...}, // Custom response handling onError: (reply, { error }) => {...} // Custom error handling }) ``` ``` -------------------------------- ### Get Connection Headers to Remove Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/exports-reference.md Parses the 'Connection' header to identify which other headers should be removed according to RFC 7230 Section 6.1. Returns an empty array if the 'Connection' header is absent or empty. ```javascript function getConnectionHeaders(headers) { // Returns array of header names referenced in Connection header } ``` ```javascript const { getConnectionHeaders } = require('@fastify/reply-from/lib/utils') const headers = { 'connection': 'upgrade, keep-alive, x-custom' } const toRemove = getConnectionHeaders(headers) // Returns: ['upgrade', 'keep-alive', 'x-custom'] ``` -------------------------------- ### Handle HTTP Request Timeout Error Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/errors.md Catch and handle the `FST_REPLY_FROM_HTTP_REQUEST_TIMEOUT` error when an upstream HTTP request times out. This example shows how to configure a request timeout and handle the error in the `onError` callback. ```javascript fastify.register(fastifyReplyFrom, { base: 'http://localhost:3001/', http: { requestOptions: { timeout: 5000 // Timeout after 5 seconds } } }) fastify.get('/', (request, reply) => { reply.from('/slow-endpoint', { onError: (reply, { error }) => { if (error.code === 'FST_REPLY_FROM_HTTP_REQUEST_TIMEOUT') { reply.code(504).send({ error: 'Upstream timeout' }) } } }) }) ``` -------------------------------- ### Validate Configuration Options Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/configuration-guide.md The plugin validates configuration at registration time. Ensure required options like 'base' are provided when 'http2' is enabled, and avoid mixing 'unix' sockets with 'http2'. ```javascript // Error: http2 enabled without base fastify.register(fastifyReplyFrom, { http2: true // Missing base - will throw error }) // Error: unix socket with http2 fastify.register(fastifyReplyFrom, { base: 'unix+http://socket/', http2: true // Will throw error }) ``` -------------------------------- ### RetryDetails Type Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/types.md Defines the structure of the object passed to the `retryDelay` callback function. This object contains details about the error, request, response, and retry attempt, along with a helper function to get the default delay. ```typescript type RetryDetails = { err: Error; req: any; res: any; attempt: number; retriesCount: number; getDefaultDelay: ( req: any, res: any, err: Error, retries: number, ) => number | null; } ``` -------------------------------- ### reply.from(source, [opts]) Source: https://github.com/fastify/fastify-reply-from/blob/main/README.md The `from` method is added to the Fastify Reply instance, allowing you to reply to the original request by fetching content from a specified source. Options can be provided to override various aspects of the request and response. ```APIDOC ## reply.from(source, [opts]) ### Description This method decorates the Fastify Reply instance with a `from` method, which will reply to the original request from the desired source. The options allow overrides of any part of the request or response being sent or received to/from the source. **Note**: If `base` is specified in plugin options, the `source` here should not override the host/origin. ### Parameters #### Options (`opts`) - **`onResponse`** (function) - Called when an HTTP response is received from the source. It receives `request`, `reply`, and `response` as arguments. The default behavior is `reply.send(response.stream)`. If you need to modify the response body or headers, you can override this function. For example, to change the body or remove the `content-length` header: ```javascript { onResponse: (request, reply, res) => { reply.removeHeader('content-length'); reply.send('New body of different length'); } } ``` **Note**: `onResponse` is called after headers have already been sent. If you want to modify response headers, use the `rewriteHeaders` hook. - **`onError`** (function) - Called when an HTTP response is received with an error from the source. It receives `reply` and `error` as arguments. The default behavior is `reply.send(error)`. This function must reply with the error. - **`rewriteHeaders`** (function) - Called to rewrite the headers of the response before they are copied over to the outer response. Parameters are the original headers and the Fastify request. It must return the new headers object. - **`rewriteRequestHeaders`** (function) - Called to rewrite the headers of the request before they are sent to the other server. Parameters are the Fastify request and the original request headers. It must return the new headers object. ### Request Example ```javascript fastify.get('/source-data', async (request, reply) => { try { const response = await reply.from('http://example.com/data', { rewriteRequestHeaders: (req, headers) => { headers['x-custom-header'] = 'value'; return headers; } }); return response; } catch (error) { reply.send(error); } }); ``` ### Response Example (Response depends on the source and any transformations applied via options.) ``` -------------------------------- ### TypeScript Support Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/quick-reference.md Import necessary types and modules for using @fastify/reply-from with TypeScript. Define options and hook options as needed. ```typescript import fastifyReplyFrom, { FastifyReplyFromOptions, FastifyReplyFromHooks } from '@fastify/reply-from' const opts: FastifyReplyFromOptions = { ... } const hookOpts: FastifyReplyFromHooks = { ... } ``` -------------------------------- ### Configure Fastify Reply From for Load Testing Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/configuration-guide.md This configuration is tailored for load testing and high-performance scenarios. It increases the number of connections and pipelining, expands the cache size, and allows for more retries on 503 errors. ```javascript fastify.register(fastifyReplyFrom, { base: [ 'http://api-1.internal:8080', 'http://api-2.internal:8080', 'http://api-3.internal:8080' ], undici: { connections: 512, pipelining: 4, keepAliveTimeout: 180000 }, cacheURLs: 2000, disableRequestLogging: true, retryMethods: ['GET', 'HEAD', 'OPTIONS'], maxRetriesOn503: 10 }) ``` -------------------------------- ### Error Logging in onError Hook Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/errors.md This example shows how to log upstream errors within the onError hook using Fastify's request logger. It captures error code, status code, and message for debugging purposes before sending a response. ```javascript fastify.register(fastifyReplyFrom, { base: 'http://localhost:3001/' }) fastify.get('/', (request, reply) => { reply.from('/api/data', { onError: (reply, { error }) => { request.log.error({ code: error.code, statusCode: error.statusCode, message: error.message }, 'Upstream error occurred') reply.code(error.statusCode || 500).send(error) } }) }) ``` -------------------------------- ### Registering Fastify Reply From with Options Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/README.md Register the plugin with custom options. Ensure FastifyReplyFromOptions is imported. ```typescript import fastifyReplyFrom, { FastifyReplyFromOptions, FastifyReplyFromHooks } from '@fastify/reply-from' const opts: FastifyReplyFromOptions = { ... } fastify.register(fastifyReplyFrom, opts) ``` -------------------------------- ### HTTP/2 Options Normalization Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/implementation-details.md Normalizes and prepares configuration options specifically for HTTP/2 requests. ```javascript getHttp2Opts(opts) // Normalizes HTTP/2 configuration ``` -------------------------------- ### Replace Request Body with body Option Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/api-reference.md The `body` option allows replacing the request body. It can be any data type, which will be JSON.stringified by default unless `contentType` is specified. Setting `body` to `null` removes the body entirely. This option cannot be used with GET or HEAD methods. ```javascript // Replace with JSON object reply.from('/api/create', { body: { id: 123, active: true } }) ``` ```javascript // Replace with custom content type reply.from('/api/upload', { body: csvData, contentType: 'text/csv' }) ``` ```javascript // Strip body entirely reply.from('/api/delete', { body: null }) ``` -------------------------------- ### Catching Various Errors in onError Hook Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/errors.md This example demonstrates a comprehensive error handling strategy within the onError hook using a switch statement. It maps specific Fastify Reply From errors and common network errors to appropriate HTTP status codes and messages. ```javascript reply.from('/api/data', { onError: (reply, { error }) => { switch (error.code) { case 'FST_REPLY_FROM_GATEWAY_TIMEOUT': reply.code(504).send({ error: 'Gateway timeout' }) break case 'ECONNRESET': reply.code(503).send({ error: 'Connection reset, retry later' }) break case 'FST_REPLY_FROM_SERVICE_UNAVAILABLE': reply.code(503).send({ error: 'Service unavailable' }) break default: reply.code(error.statusCode || 500).send({ error: error.message }) } } }) ``` -------------------------------- ### Instantiate Custom Error Classes Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/exports-reference.md Demonstrates how to import and instantiate custom error classes exported from the '@fastify/reply-from/lib/errors' module. These errors include properties like 'code', 'statusCode', and 'message'. ```javascript const { TimeoutError, GatewayTimeoutError, ConnectionResetError } = require('@fastify/reply-from/lib/errors') const err = new GatewayTimeoutError() console.log(err.code) // 'FST_REPLY_FROM_GATEWAY_TIMEOUT' console.log(err.statusCode) // 504 console.log(err.message) // 'Gateway Timeout' ``` -------------------------------- ### FastifyReplyFromOptions Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/types.md The main configuration object passed to `fastify.register(fastifyReplyFrom, options)`. This interface defines various settings for controlling how requests are forwarded to other services. ```APIDOC ## FastifyReplyFromOptions ### Description Main configuration object passed to `fastify.register(fastifyReplyFrom, options)`. ### Interface Definition ```typescript interface FastifyReplyFromOptions { base?: string | string[]; cacheURLs?: number; disableCache?: boolean; http?: HttpOptions; http2?: Http2Options | boolean; undici?: Pool.Options & { proxy?: string | URL | ProxyAgent.Options } | { request: Dispatcher['request'] }; contentTypesToEncode?: string[]; retryMethods?: (HTTPMethods | 'TRACE')[]; maxRetriesOn503?: number; disableRequestLogging?: boolean; globalAgent?: boolean; destroyAgent?: boolean; } ``` ### Fields #### base - **Type**: `string | string[]` - **Required**: No - **Default**: `—` - **Description**: Base URL for forwarding; required for http2 #### cacheURLs - **Type**: `number` - **Required**: No - **Default**: `100` - **Description**: Number of parsed URLs to cache #### disableCache - **Type**: `boolean` - **Required**: No - **Default**: `false` - **Description**: Disable URL caching entirely #### http - **Type**: `HttpOptions` - **Required**: No - **Default**: `—` - **Description**: Node.js http/https agent configuration #### http2 - **Type**: `Http2Options | boolean` - **Required**: No - **Default**: `—` - **Description**: HTTP/2 session configuration #### undici - **Type**: `undici options or instance` - **Required**: No - **Default**: `—` - **Description**: Undici client configuration #### contentTypesToEncode - **Type**: `string[]` - **Required**: No - **Default**: `['application/json']` - **Description**: Content types to JSON encode #### retryMethods - **Type**: `(HTTPMethods | 'TRACE')[]` - **Required**: No - **Default**: `['GET','HEAD','OPTIONS','TRACE']` - **Description**: Methods to retry on socket error #### maxRetriesOn503 - **Type**: `number` - **Required**: No - **Default**: `10` - **Description**: Max retries on 503 error #### disableRequestLogging - **Type**: `boolean` - **Required**: No - **Default**: `false` - **Description**: Disable request logging #### globalAgent - **Type**: `boolean` - **Required**: No - **Default**: `false` - **Description**: Use global HTTP/HTTPS agents #### destroyAgent - **Type**: `boolean` - **Required**: No - **Default**: `false` - **Description**: Destroy agents on Fastify close ``` -------------------------------- ### Http2Options Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/types.md Configuration for HTTP/2 sessions and requests. ```APIDOC ## Http2Options Configuration for HTTP/2 sessions and requests. ### Interface Definition ```typescript interface Http2Options { sessionTimeout?: number; requestTimeout?: number; sessionOptions?: ClientSessionOptions | SecureClientSessionOptions; requestOptions?: ClientSessionRequestOptions; } ``` ### Field Descriptions | Field | Type | Default | Description | |-------|------|---------|-------------| | sessionTimeout | number | 60000 | HTTP/2 session timeout in ms (0 = disabled) | | requestTimeout | number | 10000 | HTTP/2 request timeout in ms (0 = disabled) | | sessionOptions | object | {} | http2.connect() options | | requestOptions | object | {} | session.request() options | ``` -------------------------------- ### Register Upstreams with Content-Type Constraints Source: https://github.com/fastify/fastify-reply-from/blob/main/README.md Configure multiple Fastify Reply From instances, each with a specific upstream target and a Content-Type constraint. This allows routing requests to different backend services based on their content type. ```javascript // grpc-web / http1 server.register(fastifyHttpProxy, { // Although most browsers send with http2, nodejs cannot handle this http2 request // therefore we have to transport to the grpc-web-proxy via http1 http2: false, upstream: 'http://grpc-web-proxy', constraints: { "contentType": "application/grpc-web+proto" } }); // grpc / http2 server.register(fastifyHttpProxy, { http2: true, upstream: 'http://grpc.server', constraints: { "contentType": "application/grpc+proto" } }); ``` -------------------------------- ### Enable Undici Global Agent Source: https://github.com/fastify/fastify-reply-from/blob/main/README.md Opt-in to using undici's global agent by setting globalAgent to true and configuring an undici ProxyAgent. This requires importing setGlobalDispatcher and ProxyAgent from 'undici'. ```javascript import { setGlobalDispatcher, ProxyAgent } from 'undici' const proxyAgent = new ProxyAgent('my.proxy.server') setGlobalDispatcher(proxyAgent) fastify.register(FastifyReplyFrom, { base: 'http://localhost:3001/', globalAgent: true }) ``` -------------------------------- ### Enable HTTP/2 with Custom Timeouts Source: https://github.com/fastify/fastify-reply-from/blob/main/_autodocs/api-reference.md Enable HTTP/2 support with custom session and request timeouts, as well as specific session and request options. Ensure 'base' is configured. ```javascript fastify.register(fastifyReplyFrom, { base: 'http://localhost:3001/', http2: { sessionTimeout: 30000, requestTimeout: 10000, sessionOptions: { rejectUnauthorized: true }, requestOptions: { endStream: true } } }) ```