Spreading Http And HttpParam Tags Across Multiple Function Calls In Lucee CFML 5.3.8.201
Back when InVision was running on Adobe ColdFusion 10, I leaned heavily on the native Http.cfc
component when making network requests. However, once we switched over to Lucee CFML 5.3, where tag support in CFScript is much more robust, I found myself reverting back to the http
and httpParam
tags for network requests. There's something I find so elegant about the syntax of tags and their builder-like pattern of construction. One nice about using the Http.cfc
ColdFusion component, however, is that it can be passed around and augmented such as with the injection of tracing headers. This got me thinking about augmenting http
tags with httpParam
tags; and, whether such an augmentation could be spread across function calls in Lucee CFML 5.3.8.201.
This isn't the first time that I've considered such a pattern. Last year, I demonstrated that you could compose a SQL statement along with its cfqueryparam
tags across multiple function calls. At the time, I didn't know if that was something specific to the cfquery
tags; or, if that was a technique that would generally work with all tags in Lucee CFML.
To explore this concept, I'm going to create a page that composes httpParam
tags inside Function calls. Then, I'm going to make an HTTP request to an end-point that echoes the incoming HTTP headers in its response. First, let's just take a look at the target.cfm
template - our HTTP end-point:
<cfscript>
// Extract inbound HTTP headers.
incomingHeaders = getHttpRequestData( false ).headers;
// Prepare HTTP headers to be echoed in BODY of response.
serializedHeaders = serializeJson( incomingHeaders );
responsePayload = charsetDecode( serializedHeaders, "utf8" );
content
type = "application/json; charset=utf8"
variable = responsePayload
;
</cfscript>
As you can see, this simply grabs the .headers
property out of the request context, serializes it as JSON (JavaScript Object Notation), and dumps it in to the response body.
Now, we can go about generating that request using the http
tag and several httpParam
tags. Note that two of the httpParam
tags are defined in UDFs (User Defined Functions):
<cfscript>
// Construct the root URL that we are going to hit (sibling to this template).
host = "http://#cgi.server_name#:#cgi.server_port#";
wwwRoot = getDirectoryFromPath( cgi.script_name );
targetUrl = ( host & wwwRoot & "target.cfm" );
// The "target.cfm" end-point does nothing but serialize and return the incoming HTTP
// HEADERS as a JSON (JavaScript Object Notation) payload. Our goal here is to see if
// we can compose that set of HTTP headers across a series of Function calls.
http
result = "targetResponse"
method = "get"
url = targetUrl
{
// Gather "httpParam" TAGS across external function calls.
injectAuthorizationHeaders();
injectTracingHeaders();
// Mix-in our own "local" header.
httpParam
type = "header"
name = "X-Meep"
value = "moop"
;
}
// Output the HTTP HEADERS that the target end-point found and returned.
dump( deserializeJson( targetResponse.fileContent ) );
// ------------------------------------------------------------------------------- //
// ------------------------------------------------------------------------------- //
/**
* I apply the Authorization HTTP header to the current HTTP context.
*/
public void function injectAuthorizationHeaders() {
httpParam
type = "header"
name = "Authorization"
value = "Bearer: ICANHASCHEEZEBURGER"
;
}
/**
* I apply the tracing HTTP headers to the current HTTP context.
*/
public void function injectTracingHeaders() {
param
name = "request.requestID"
type = "string"
default = "request-#createUuid()#"
;
httpParam
type = "header"
name = "X-Request-ID"
value = request.requestID
;
}
</cfscript>
As you can see, inside our http
tag context, we're calling two methods:
injectAuthorizationHeaders()
injectTracingHeaders()
Each of these methods contains an httpParam
tag that magically attaches to and augments the http
context in current the call-stack. And, when we run this ColdFusion template, we get the following output:
As you can see, all three httpParam
header values were attached to the outgoing HTTP request. This demonstrates that http
and httpParam
tags can be aggregated across several method calls. This means that we can easily create functions that apply "behaviors" (such as Authorization and Tracing) to any contextual http
tag in our application.
Freaking Lucee CFML - it's just awesome!
Want to use code from this post? Check out the license.
Reader Comments
You should check out HYPER - http calls with a real chainable builder setup, its so cool in CFML.
https://www.forgebox.io/view/hyper
@Gavin,
That looks pretty cool. I feel like I've heard you all talk about that on the Modernize or Die show. Looks like it has a lot of flexibility. And, the ability to set defaults across the board is very nice. 💪
Ugggg, so, I was just trying this technique in Adobe ColdFusion and it throws the error:
Super lame! This is true in both ACF 2021 and 2023. It doesn't make sense - the whole base-tag context mechanisms are (almost) the same in the two runtimes. I'm not sure why Adobe ColdFusion is struggling with this.