Created
March 25, 2014 10:30
-
-
Save bennadel/9758853 to your computer and use it in GitHub Desktop.
Using OnMissingMethod() With Remote Access ColdFusion Components
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<cfcomponent | |
output="false" | |
hint="I provide the core remote proxy API functionality."> | |
<cffunction | |
name="NewAPIResponse" | |
access="public" | |
returntype="struct" | |
output="false" | |
hint="I provide a new default API response object."> | |
<!--- Define the local scope. ---> | |
<cfset var LOCAL = {} /> | |
<!--- Create a new API response object. ---> | |
<cfset LOCAL.Response = { | |
Success = true, | |
Errors = [], | |
Data = "" | |
} /> | |
<!--- Return new response object. ---> | |
<cfreturn LOCAL.Response /> | |
</cffunction> | |
<cffunction | |
name="ManuallyReturnReponse" | |
access="public" | |
returntype="void" | |
output="false" | |
hint="I stream the given response to the client manually using CFHeader and CFContent."> | |
<!--- Define arguments. ---> | |
<cfargument | |
name="Response" | |
type="struct" | |
required="true" | |
hint="I am the API response being returned." | |
/> | |
<cfargument | |
name="ReturnFormat" | |
type="string" | |
required="false" | |
default="JSON" | |
hint="I am the format required for the API response." | |
/> | |
<!--- Define the local scope. ---> | |
<cfset var LOCAL = {} /> | |
<!--- | |
Create the response string. Check to see if we want | |
this as WDDX or JSON. | |
---> | |
<cfswitch expression="#ARGUMENTS.ReturnFormat#"> | |
<cfcase value="wddx"> | |
<!--- Convert to WDDX. ---> | |
<cfwddx | |
action="cfml2wddx" | |
input="#ARGUMENTS.Response#" | |
output="LOCAL.ResponseString" | |
/> | |
</cfcase> | |
<cfdefaultcase> | |
<!--- | |
By default, we are going to return the API | |
response in JSON string (since that is what | |
our appliation does by default). | |
---> | |
<cfset LOCAL.ResponseString = SerializeJSON( | |
ARGUMENTS.Response | |
) /> | |
</cfdefaultcase> | |
</cfswitch> | |
<!--- | |
Now that we have our API response string, we need | |
to update the headers and return the response. | |
---> | |
<!--- | |
Set header response code to be 200 - remember, the | |
whole point of the unified API response is that it | |
never "fails" unless there is truly a request | |
exception. | |
---> | |
<cfheader | |
statuscode="200" | |
statustext="OK" | |
/> | |
<!--- Steam binary contact back. ---> | |
<cfcontent | |
type="text/plain" | |
variable="#ToBinary( ToBase64( LOCAL.ResponseString ) )#" | |
/> | |
<!--- | |
At this point, the request has been completely | |
committed and cannot be altered. | |
---> | |
<!--- Return out. ---> | |
<cfreturn /> | |
</cffunction> | |
<cffunction | |
name="OnMissingMethod" | |
access="public" | |
returntype="struct" | |
output="false" | |
hint="I handle non-explicit API messaging."> | |
<!--- Define arguments. ---> | |
<cfargument | |
name="MethodName" | |
type="string" | |
required="true" | |
hint="I am the name of the method." | |
/> | |
<cfargument | |
name="MethodArguments" | |
type="struct" | |
required="true" | |
hint="I am the collection of arguments." | |
/> | |
<!--- | |
Use the error response to create and return an API | |
response with the given API error. | |
---> | |
<cfreturn THIS.NewErrorResponse( "The method that you requested, #ARGUMENTS.MethodName#, is not supported in the current version of this API." ) /> | |
</cffunction> | |
<cffunction | |
name="NewErrorResponse" | |
access="public" | |
returntype="struct" | |
output="false" | |
hint="I create an return a new error response with the given error."> | |
<!--- Define arguments. ---> | |
<cfargument | |
name="Error" | |
type="string" | |
required="true" | |
hint="I am the error message." | |
/> | |
<!--- Define the local scope. ---> | |
<cfset var LOCAL = {} /> | |
<!--- Create a new API response object. ---> | |
<cfset LOCAL.Response = THIS.NewAPIResponse() /> | |
<!--- Flag it as not successful. ---> | |
<cfset LOCAL.Response.Success = false /> | |
<!--- Set the error message. ---> | |
<cfset LOCAL.Response.Errors[ 1 ] = { | |
Property = "", | |
Error = ARGUMENTS.Error | |
} /> | |
<!--- Return new response. ---> | |
<cfreturn LOCAL.Response /> | |
</cffunction> | |
</cfcomponent> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<cfcomponent | |
output="false" | |
hint="I provide application settings and event handlers."> | |
<cffunction | |
name="OnError" | |
access="public" | |
returntype="void" | |
output="true" | |
hint="I handle uncaught application errors."> | |
<!--- Define the arguments. ---> | |
<cfargument | |
name="Exception" | |
type="any" | |
required="true" | |
hint="I am the uncaught exception." | |
/> | |
<!--- Define the local scope. ---> | |
<cfset var LOCAL = {} /> | |
<!--- | |
Normally, we would want to return a error header, but | |
if the request was an API call (remote call), we never | |
want to return an error. Rather, we want to return an | |
"unsuccessful" API request. | |
---> | |
<cfif REFindNoCase( "\.cfc$", CGI.script_name )> | |
<!--- | |
Create an instance of the CFC in question. | |
NOTE: This line of code leverages the undocumented | |
ability for ColdFusion components to be created | |
both dot-delimited AND slash-delimited file paths. | |
---> | |
<cfset LOCAL.API = CreateObject( | |
"component", | |
REReplaceNoCase( | |
CGI.script_name, | |
"\.cfc$", | |
"", | |
"one" | |
) | |
) /> | |
<!--- Set default return format. ---> | |
<cfset LOCAL.ReturnFormat = "JSON" /> | |
<!--- Check to see if return format was overriden. ---> | |
<cfif StructKeyExists( URL, "ReturnFormat" )> | |
<!--- Overriding default format. ---> | |
<cfset LOCAL.ReturnFormat = URL.ReturnFormat /> | |
</cfif> | |
<!--- | |
Check to see what kind of error we had. If the | |
"func" key exists, then it was a missing method | |
error. If not, then it was simply an unhandled | |
error. | |
---> | |
<cfif StructKeyExists( ARGUMENTS.Exception, "Func" )> | |
<!--- Missing method error. ---> | |
<!--- Build up arguments. ---> | |
<cfset LOCAL.Arguments = Duplicate( URL ) /> | |
<cfset StructAppend( LOCAL.Arguments, FORM ) /> | |
<!--- | |
Call onMissingMethod and stream back response | |
to client manually. | |
---> | |
<cfset LOCAL.API.ManuallyReturnReponse( | |
LOCAL.API.OnMissingMethod( | |
LOCAL.Arguments.Method, | |
LOCAL.Arguments | |
), | |
LOCAL.ReturnFormat | |
) /> | |
<cfelse> | |
<!--- Uncaught exception. ---> | |
<!--- | |
Create a new error and return it to the client | |
using explicit stream. | |
---> | |
<cfset LOCAL.API.ManuallyReturnReponse( | |
LOCAL.API.NewErrorResponse( | |
ARGUMENTS.Exception.Message | |
), | |
LOCAL.ReturnFormat | |
) /> | |
</cfif> | |
</cfif> | |
<!--- Return out. ---> | |
<cfreturn /> | |
</cffunction> | |
</cfcomponent> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment