coldbox-proxy
Use this skill when building ColdBox Proxy objects to expose ColdBox event handlers to remote callers such as ColdFusion web services, Flex/AIR, event gateways, or CFC data binding -- enabling non-HTTP protocols to participate in the ColdBox event model.
ColdBox Proxy
When to Use This Skill
Use this skill when you need to expose your ColdBox application to non-HTTP callers: SOAP web services, Flex/AIR binary protocol, ColdFusion event gateways, or any remote CFC invocation that bypasses the normal HTTP request cycle.
Core Concepts
- Proxy โ A CFC that extends
coldbox.system.remote.ColdboxProxyand acts as an interface between external callers and the ColdBox event model process()โ Executes a ColdBox event from within the proxy; all extra arguments are merged into the request collectionloadColdBox()โ For loading an external ColdBox app whoseApplication.cfcis not in the webrootCOLDBOX_APP_MAPPINGโ Required inApplication.cfcwhen the ColdBox app lives in a sub-folder and uses non-HTTP protocols (Flex/AIR, gateways)preProxyResultsinterception point โ Fires right before proxy returns results; ideal for logging, transformation
File Organization
Create a remote/ folder in your application root and place one or more proxy CFCs there, organized by domain:
/Application
/remote
UserProxy.cfc
OrderProxy.cfc
Basic Proxy Structure
// remote/UserProxy.cfc
component extends="coldbox.system.remote.ColdboxProxy" {
/**
* Get a list of users
* @page Page number
* @limit Records per page
*/
array function getUsers( numeric page = 1, numeric limit = 25 ) {
arguments.event = "api.users.index";
var results = super.process( argumentCollection = arguments );
return results ?: [];
}
/**
* Get a single user by ID
*/
struct function getUser( required numeric id ) {
arguments.event = "api.users.show";
var results = super.process( argumentCollection = arguments );
return results ?: {};
}
/**
* Save a user record
*/
struct function saveUser( required struct userData ) {
arguments.event = "api.users.save";
structAppend( arguments, userData );
return super.process( argumentCollection = arguments ) ?: {};
}
}
Matching Event Handler
The event handler accessed via process() can return data just as it would in an HTTP call. Handlers can distinguish proxy calls from browser calls using event.isProxyRequest():
// handlers/api/Users.cfc
component extends="coldbox.system.EventHandler" {
property name="userService" inject="UserService";
function index( event, rc, prc ) {
var data = userService.list(
page = rc.page ?: 1,
limit = rc.limit ?: 25
);
// Return data directly when called via proxy
if ( event.isProxyRequest() ) {
return data.getRecords();
}
// Normal MVC view rendering
prc.users = data;
event.setView( "users/index" );
}
}
Proxy Methods Reference
| Method | Description |
|---|---|
process( event, [args...] ) | Execute a ColdBox event; extra args merged into request collection |
announce( state, data ) | Fire a ColdBox interception announcement |
getInstance( name, dsl, initArguments ) | Get a WireBox model object |
getController() | Return the ColdBox controller instance |
getCache( cacheName ) | Return a named CacheBox cache provider |
getCacheBox() | Return the CacheBox instance |
getLogBox() | Return the LogBox instance |
getWireBox() | Return the WireBox instance |
getInterceptor( name ) | Get a named interceptor |
getRemotingUtil() | Utility to manipulate output / buffer |
loadColdBox( appMapping ) | Load an external ColdBox application into scope |
AppMapping for Non-HTTP Protocols
When using Flex/AIR or event gateways (no HTTP), ColdBox cannot auto-detect your app location. Set COLDBOX_APP_MAPPING in Application.cfc:
// Application.cfc
component {
// Empty string means app is at webroot (default)
COLDBOX_APP_MAPPING = "";
// Sub-folder: app lives at /apps/myApp
// COLDBOX_APP_MAPPING = "apps.myApp";
}
COLDBOX_APP_MAPPINGis an instantiation path, not a file system path.
Interception: preProxyResults
Use the preProxyResults interception point to transform, log, or audit results before they are returned to the caller:
// interceptors/ProxyLogger.cfc
component extends="coldbox.system.Interceptor" {
property name="log" inject="logbox:logger:{this}";
function preProxyResults( event, interceptData ) {
log.debug( "Proxy call completed", {
event : event.getCurrentEvent(),
results : interceptData.proxyResults
} );
}
}
ProxyReturnCollection Setting
By default, process() returns whatever the event handler returns. To always return the full request collection instead, set:
// config/ColdBox.cfc
coldbox = {
proxyReturnCollection : true
};
SOAP Web Service Example
// remote/ProductService.cfc
component
extends = "coldbox.system.remote.ColdboxProxy"
output = "false"
hint = "Product remote service"
{
/**
* @webservice true
*/
remote array function getProducts( string category = "" ) {
arguments.event = "api.products.index";
return super.process( argumentCollection = arguments ) ?: [];
}
remote struct function getProduct( required string id ) {
arguments.event = "api.products.show";
return super.process( argumentCollection = arguments ) ?: {};
}
}
Key Rules
- Never place business logic inside proxy CFCs โ delegate everything to handlers via
process(). - Keep proxy CFCs organized by domain (e.g.,
UserProxy,OrderProxy) rather than one giant proxy. - Always provide a safe default return value (
?: [],?: {}) in case the event returns nothing. - Use
event.isProxyRequest()in handlers to differentiate proxy vs. HTTP responses. - Set
COLDBOX_APP_MAPPINGonly when using non-HTTP protocols and the app is NOT at the webroot.