feat(proxy-backend): more proxy config tweaks and docs
This commit is contained in:
+3
-9
@@ -14,21 +14,15 @@ backend:
|
||||
client: sqlite3
|
||||
connection: ':memory:'
|
||||
|
||||
# See README.md in the proxy-backend plugin for information on the configuration format
|
||||
proxy:
|
||||
'/circleci/api':
|
||||
target: 'https://circleci.com/api/v1.1'
|
||||
changeOrigin: true
|
||||
pathRewrite:
|
||||
'^/proxy/circleci/api/': '/'
|
||||
'/circleci/api': https://circleci.com/api/v1.1
|
||||
'/jenkins/api':
|
||||
target: 'http://localhost:8080'
|
||||
changeOrigin: true
|
||||
target: http://localhost:8080
|
||||
headers:
|
||||
Authorization:
|
||||
$secret:
|
||||
env: JENKINS_BASIC_AUTH_HEADER
|
||||
pathRewrite:
|
||||
'^/proxy/jenkins/api/': '/'
|
||||
|
||||
organization:
|
||||
name: Spotify
|
||||
|
||||
@@ -82,7 +82,7 @@ async function main() {
|
||||
.addRouter('/auth', await auth(authEnv))
|
||||
.addRouter('/identity', await identity(identityEnv))
|
||||
.addRouter('/techdocs', await techdocs(techdocsEnv))
|
||||
.addRouter('/proxy', await proxy(proxyEnv))
|
||||
.addRouter('/proxy', await proxy(proxyEnv, '/proxy'))
|
||||
.addRouter('/graphql', await graphql(graphqlEnv));
|
||||
|
||||
await service.start().catch(err => {
|
||||
|
||||
@@ -13,13 +13,14 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// @ts-ignore
|
||||
import { createRouter } from '@backstage/plugin-proxy-backend';
|
||||
import { PluginEnvironment } from '../types';
|
||||
|
||||
export default async function createPlugin({
|
||||
logger,
|
||||
config,
|
||||
}: PluginEnvironment) {
|
||||
return await createRouter({ logger, config });
|
||||
export default async function createPlugin(
|
||||
{ logger, config }: PluginEnvironment,
|
||||
pathPrefix: string,
|
||||
) {
|
||||
return await createRouter({ logger, config, pathPrefix });
|
||||
}
|
||||
|
||||
@@ -19,8 +19,8 @@ const proxyEnv = useHotMemoize(module, () => createEnv('proxy'));
|
||||
|
||||
const service = createServiceBuilder(module)
|
||||
.loadConfig(configReader)
|
||||
/** several different routers */
|
||||
.addRouter('/', await proxy(proxyEnv));
|
||||
/** ... other routers ... */
|
||||
.addRouter('/proxy', await proxy(proxyEnv, '/proxy'));
|
||||
```
|
||||
|
||||
2. Start the backend
|
||||
@@ -31,6 +31,48 @@ yarn workspace example-backend start
|
||||
|
||||
This will launch the full example backend.
|
||||
|
||||
## Configuration
|
||||
|
||||
Example:
|
||||
|
||||
```yaml
|
||||
# in app-config.yaml
|
||||
proxy:
|
||||
'/simple-example': http://simple.example.com:8080
|
||||
'/larger-example/v1':
|
||||
target: http://larger.example.com:8080/svc.v1
|
||||
headers:
|
||||
Authorization:
|
||||
$secret:
|
||||
env: EXAMPLE_AUTH_HEADER
|
||||
```
|
||||
|
||||
Each key under the proxy configuration entry is a route to match, below the prefix that the proxy
|
||||
plugin is mounted on. For example, if the backend mounts the proxy plugin as `/proxy`,
|
||||
the above configuration will lead to the proxy acting on backend requests to
|
||||
`/proxy/simple-example/...` and `/proxy/larger-example/v1/...`.
|
||||
|
||||
The value inside each route is either a simple URL string, or an object on the format accepted by
|
||||
[http-proxy-middleware](https://www.npmjs.com/package/http-proxy-middleware).
|
||||
|
||||
If the value is a string, it is assumed to correspond to:
|
||||
|
||||
```yaml
|
||||
target: <the string>
|
||||
changeOrigin: true
|
||||
pathRewrite:
|
||||
'^<url prefix><the string>/': '/'
|
||||
```
|
||||
|
||||
When the target is an object, it is given verbatim to `http-proxy-middleware` except with the
|
||||
following caveats for convenience:
|
||||
|
||||
- If `changeOrigin` is not specified, it is set to `true`. This is the most commonly useful value.
|
||||
- If `pathRewrite` is not specified, it is set to a single rewrite that removes the entire route. In the
|
||||
above example, a rewrite of `'^/proxy/larger-example/v1/': '/'` is added. That means that a request to
|
||||
`/proxy/larger-example/v1/some/path` will be translated to a request to
|
||||
`http://larger.example.com:8080/svc.v1/some/path`.
|
||||
|
||||
## Links
|
||||
|
||||
- [http-proxy-middleware](https://www.npmjs.com/package/http-proxy-middleware)
|
||||
|
||||
@@ -26,6 +26,7 @@ describe('createRouter', () => {
|
||||
const router = await createRouter({
|
||||
config,
|
||||
logger,
|
||||
pathPrefix: '/proxy',
|
||||
});
|
||||
expect(router).toBeDefined();
|
||||
});
|
||||
|
||||
@@ -17,21 +17,57 @@
|
||||
import { Config } from '@backstage/config';
|
||||
import express from 'express';
|
||||
import Router from 'express-promise-router';
|
||||
import createProxyMiddleware from 'http-proxy-middleware';
|
||||
import createProxyMiddleware, {
|
||||
Config as ProxyConfig,
|
||||
Proxy,
|
||||
} from 'http-proxy-middleware';
|
||||
import { Logger } from 'winston';
|
||||
|
||||
export interface RouterOptions {
|
||||
logger: Logger;
|
||||
config: Config;
|
||||
// The URL path prefix that the router itself is mounted as, commonly "/proxy"
|
||||
pathPrefix: string;
|
||||
}
|
||||
|
||||
// Creates a proxy middleware, possibly with defaults added on top of the
|
||||
// given config.
|
||||
function buildMiddleware(
|
||||
pathPrefix: string,
|
||||
route: string,
|
||||
config: string | ProxyConfig,
|
||||
): Proxy {
|
||||
const fullConfig =
|
||||
typeof config === 'string' ? { target: config } : { ...config };
|
||||
|
||||
// Default is to do a path rewrite that strips out the proxy's path prefix
|
||||
// and the rest of the route.
|
||||
if (fullConfig.pathRewrite === undefined) {
|
||||
const routeWithSlash = route.endsWith('/') ? route : `${route}/`;
|
||||
fullConfig.pathRewrite = {
|
||||
[`^${pathPrefix}${routeWithSlash}`]: '/',
|
||||
};
|
||||
}
|
||||
|
||||
// Default is to update the Host header to the target
|
||||
if (fullConfig.changeOrigin === undefined) {
|
||||
fullConfig.changeOrigin = true;
|
||||
}
|
||||
|
||||
return createProxyMiddleware(fullConfig);
|
||||
}
|
||||
|
||||
export async function createRouter(
|
||||
options: RouterOptions,
|
||||
): Promise<express.Router> {
|
||||
const router = Router();
|
||||
const proxyConfig = options.config.get('proxy') ?? {};
|
||||
|
||||
const proxyConfig = options.config.getOptional('proxy') ?? {};
|
||||
Object.entries(proxyConfig).forEach(([route, proxyRouteConfig]) => {
|
||||
router.use(route, createProxyMiddleware(proxyRouteConfig));
|
||||
router.use(
|
||||
route,
|
||||
buildMiddleware(options.pathPrefix, route, proxyRouteConfig),
|
||||
);
|
||||
});
|
||||
|
||||
return router;
|
||||
|
||||
@@ -40,6 +40,7 @@ export async function startStandaloneServer(
|
||||
const router = await createRouter({
|
||||
config,
|
||||
logger,
|
||||
pathPrefix: '/proxy',
|
||||
});
|
||||
const service = createServiceBuilder(module)
|
||||
.enableCors({ origin: 'http://localhost:3000' })
|
||||
|
||||
Reference in New Issue
Block a user