-
Notifications
You must be signed in to change notification settings - Fork 6
Extensions
Graphman Client provides an extensibility mechanism that allows you to customize and enhance the behavior of various operations through extension points. Extensions are JavaScript modules that implement specific interfaces to intercept and modify data at key points in the Graphman workflow.
Extensions are pluggable JavaScript modules that allow you to:
- Modify HTTP request options before sending to the Gateway
- Process input/output bundles
- Process input/output details by loading third-party modules if required
-
Registration: Extensions are registered in the
graphman.configurationfile - Loading: Graphman loads extension modules at runtime
- Invocation: Extensions are invoked at specific points during operation execution
- Processing: Each extension receives input data and context, processes it, and returns modified data
┌─────────────────┐
│ Graphman CLI │
└────────┬────────┘
│
├──> pre-request ──────> HTTP Request ──────> Gateway
│ │
│ ▼
│ Query/Mutation
│ │
│ ▼
├──> post-export <────── Export Response <──────┘
│
├──> pre-import ───────> Import Request ──────> Gateway
│
├──> multiline-text-diff ──> Diff Operation
│
└──> policy-code-validator ──> Validate Operation
Note
Extensions can only be activated/processed from the configured home directory. Please consider configuring your workspace (home) directory for hosting the extensions. Ref: https://github.com/Layer7-Community/graphman-client/wiki/Getting-Started#configure-home-directory
Note
Extension argument (context) is revised since 2.0.9 release.
Purpose: Modify HTTP request options before sending to the Gateway
When Invoked: Before every GraphQL query or mutation request
Use Cases:
- Add custom HTTP headers
- Modify authentication credentials
- Configure proxy settings
- Add request interceptors
- Implement custom retry logic
Purpose: Process and transform bundles after exporting from the Gateway
When Invoked: After receiving export response from the Gateway, before writing to output
Use Cases:
- Remove sensitive data from exported bundles
- Transform entity properties
- Add metadata or annotations
- Filter out specific entities
- Normalize data formats
Purpose: Process and transform bundles before importing to the Gateway
When Invoked: Before sending import mutation to the Gateway
Use Cases:
- Sanitize bundle data
- Replace environment-specific values
- Validate bundle structure
- Transform entity properties
- Add or remove entities based on rules
Purpose: Compute detailed differences for multiline text fields (especially policy code)
When Invoked: During diff operation when comparing entities with multiline text fields
Use Cases:
- Generate unified diff format for policy XML
- Customize diff output format
- Ignore whitespace differences
- Highlight specific changes
- Generate HTML diff reports
Pre-requisites:
- default implementation uses the diff third-party module. By default, it is not enabled for use.
- once enabled, make sure this package is installed, available for use
npm install diff@5.2.0 --global
Purpose: Create custom JSON schema validators for policy code validation
When Invoked: During validate operation when validating policy code
Use Cases:
- Use different JSON schema validator libraries
- Configure validator options
- Add custom validation formats
- Implement custom validation logic
Pre-requisites:
- default implementation uses the ajv third-party module. By default, it is not enabled for use.
- once enabled, make sure this package is installed, available for use
npm install ajv --global
Note
Not all the extensions are enabled by default for use. Needed extensions can be enabled either by configuration file or using --options.extensions CLI argument.
When the extensions are customized and configured to load from the home directory, their third-party packages might not get loaded. Because of which, the below warning can be observed.
[warn] failed to load the multiline-text-diff extension, cause=MODULE_NOT_FOUND, falling back to the default
This can be resolved by linking the required third-party packages to the home directory using the below npm-link command.
;change the current directory to GRAPHMAN_HOME
npm link <third-party-library-name>
Assuming that the graphman is configured with home directory so that extensions are pulled into it with the default code. FYI, refer to https://github.com/Layer7-Community/graphman-client/wiki/Getting-Started#configure-home-directory
Edit the $GRAPHMAN_HOME/modules/graphman-extension-post-export.js file and replace the existing code with the below one.
/*
* Copyright (c) 2025. Broadcom Inc. and/or its subsidiaries. All Rights Reserved.
*/
module.exports = {
/**
* Extension to process gateway exported configuration.
* @param input exported bundle
* @param context CLI operation execution context
* @param context.operation operation
* @param context.gateway gateway object
* @param context.options CLI options
*/
apply: function (input, context) {
if (context.options.excludeOTK) {
if (input.policies) input.policies = input.policies.filter(item => !item.folderPath || !item.folderPath.startsWith("/OTK"));
if (input.encassConfigs) input.encassConfigs = input.encassConfigs.filter(item => !item.name.startsWith("OTK "));
if (input.serverModuleFiles) input.serverModuleFiles = input.serverModuleFiles.filter(item => !item.name.startsWith("OTK "));
if (input.clusterProperties) input.clusterProperties = input.clusterProperties.filter(item => !item.name.startsWith("otk."));
}
return input;
}
}
Now, run the export command with --options.excludeOTK option
graphman export --service:full --variables.resolutionPath /some-service --options.excludeOTK
Assuming that the graphman is configured with home directory so that extensions are pulled into it with the default code. FYI, refer to https://github.com/Layer7-Community/graphman-client/wiki/Getting-Started#configure-home-directory
Edit the $GRAPHMAN_HOME/modules/graphman-extension-pre-request.js file and replace the existing code with the below one.
/*
* Copyright (c) 2025. Broadcom Inc. and/or its subsidiaries. All Rights Reserved.
*/
module.exports = {
/**
* Extension to enhance http request options
* @param input http request options
* @param context CLI operation execution context
* @param context.operation operation
* @param context.gateway gateway object
* @param context.options CLI options
*/
apply: function (input, context) {
// Add your custom header to the HTTP request
input.headers["x-hello"] = "Hello, World!";
// Assuming that --options.customGreetings CLI argument is specified.
input.headers["y-hello"] = context.options.customGreetings;
return input;
}
}
Now, run the export command with --options.customGreetings option
graphman export --service:full --variables.resolutionPath /some-service --options.customGreetings "Hello, Graphman!"
Extensions should focus on a single responsibility:
- ✅ Transform specific fields
- ✅ Add metadata
- ✅ Validate structure
- ❌ Complex business logic
- ❌ External API calls (unless necessary)
module.exports = {
apply: function (input, context) {
try {
// Your logic here
return processInput(input, context);
} catch (error) {
console.error('Extension error:', error.message);
// Return original input on error
return input;
}
}
}module.exports = {
apply: function (input, context) {
console.log(`[${context.operation}] Processing with custom extension`);
// Your logic
console.log(`[${context.operation}] Extension complete`);
return input;
}
}module.exports = {
apply: function (input, context) {
const config = context.options.extensionConfig || {};
if (config.enableFeatureX) {
// Feature X logic
}
return input;
}
}Pass configuration via command line:
graphman export --using all --extensionConfig.enableFeatureX true