diff --git a/README.md b/README.md index f4eb3fe..154a61d 100644 --- a/README.md +++ b/README.md @@ -193,6 +193,16 @@ Note that the [rewriteHeaders](https://github.com/fastify/fastify-reply-from#rew An array that contains the types of the methods. Default: `['DELETE', 'GET', 'HEAD', 'PATCH', 'POST', 'PUT', 'OPTIONS']`. +### `routes` + +An array that contains the routes to handle. Default: `['/', '/*']`. + +### `preRewrite` + +A function that will be executed before rewriting the URL. It receives the URL, the request parameters and the prefix and must return the new URL. + +The function cannot return a promise. + ### `websocket` This module has _partial_ support for forwarding websockets by passing a diff --git a/index.js b/index.js index f8f7c4f..10375c9 100644 --- a/index.js +++ b/index.js @@ -8,7 +8,8 @@ const fp = require('fastify-plugin') const qs = require('fast-querystring') const { validateOptions } = require('./src/options') -const httpMethods = ['DELETE', 'GET', 'HEAD', 'PATCH', 'POST', 'PUT', 'OPTIONS'] +const defaultRoutes = ['/', '/*'] +const defaultHttpMethods = ['DELETE', 'GET', 'HEAD', 'PATCH', 'POST', 'PUT', 'OPTIONS'] const urlPattern = /^https?:\/\// const kWs = Symbol('ws') const kWsHead = Symbol('wsHead') @@ -82,6 +83,10 @@ function isExternalUrl (url) { function noop () { } +function noopPreRewrite (url) { + return url +} + function createContext (logger) { return { log: logger } } @@ -518,6 +523,7 @@ async function fastifyHttpProxy (fastify, opts) { opts = validateOptions(opts) const preHandler = opts.preHandler || opts.beforeHandler + const preRewrite = typeof opts.preRewrite === 'function' ? opts.preRewrite : noopPreRewrite const rewritePrefix = generateRewritePrefix(fastify.prefix, opts) const fromOpts = Object.assign({}, opts) @@ -555,22 +561,13 @@ async function fastifyHttpProxy (fastify, opts) { done(null, payload) } - fastify.route({ - url: '/', - method: opts.httpMethods || httpMethods, - preHandler, - config: opts.config || {}, - constraints: opts.constraints || {}, - handler - }) - fastify.route({ - url: '/*', - method: opts.httpMethods || httpMethods, - preHandler, - config: opts.config || {}, - constraints: opts.constraints || {}, - handler - }) + const method = opts.httpMethods || defaultHttpMethods + const config = opts.config || {} + const constraints = opts.constraints || {} + + for (const url of opts.routes || defaultRoutes) { + fastify.route({ url, method, preHandler, config, constraints, handler }) + } let wsProxy @@ -593,6 +590,8 @@ async function fastifyHttpProxy (fastify, opts) { } function fromParameters (url, params = {}, prefix = '/') { + url = preRewrite(url, params, prefix) + const { path, queryParams } = extractUrlComponents(url) let dest = path @@ -646,4 +645,6 @@ module.exports = fp(fastifyHttpProxy, { encapsulate: true }) module.exports.default = fastifyHttpProxy +module.exports.defaultRoutes = defaultRoutes +module.exports.defaultHttpMethods = defaultHttpMethods module.exports.fastifyHttpProxy = fastifyHttpProxy diff --git a/test/test.js b/test/test.js index 2b8880a..f7d07d2 100644 --- a/test/test.js +++ b/test/test.js @@ -751,6 +751,29 @@ async function run () { t.assert.fail() }) + test('settings of routes', async t => { + const server = Fastify() + server.register(proxy, { + upstream: `http://localhost:${origin.server.address().port}`, + routes: ['/a'] + }) + + await server.listen({ port: 0 }) + t.after(() => server.close()) + + const resultRoot = await got(`http://localhost:${server.server.address().port}/a`) + t.assert.deepStrictEqual(resultRoot.statusCode, 200) + + let errored = false + try { + await await got(`http://localhost:${server.server.address().port}/api2/a`) + } catch (err) { + t.assert.strictEqual(err.response.statusCode, 404) + errored = true + } + t.assert.ok(errored) + }) + test('settings of method types', async t => { const server = Fastify() server.register(proxy, { @@ -958,6 +981,34 @@ async function run () { t.assert.strictEqual(body, 'this is a') } }) + + test('preRewrite handler', async t => { + const proxyServer = Fastify() + + proxyServer.register(proxy, { + upstream: `http://localhost:${origin.server.address().port}`, + prefix: '/api', + rewritePrefix: '/api2/', + preRewrite (url, params, prefix) { + t.assert.strictEqual(url, '/api/abc') + t.assert.ok(typeof params, 'object') + t.assert.strictEqual(params['*'], 'abc') + t.assert.strictEqual(prefix, '/api') + return url.replace('abc', 'a') + } + }) + + await proxyServer.listen({ port: 0 }) + + t.after(() => { + proxyServer.close() + }) + + const firstProxyPrefix = await got( + `http://localhost:${proxyServer.server.address().port}/api/abc` + ) + t.assert.strictEqual(firstProxyPrefix.body, 'this is /api2/a') + }) } run()