3
votes

When I use the following code:

<cftry>
    <cfif CompareNoCase(request.engine,"Railo") EQ 0>
        <cfset RestInitApplication(request.filepath & "\com\api",local.serviceMapping,false,request.webAdminPassword) />
    <cfelse>
        <cfset RestInitApplication(request.filepath & "\com\api",local.serviceMapping) />
    </cfif>
    <cfcatch>
     </cfcatch>
</cftry>

Adobe Coldfusion throws the following compilation error:

Parameter validation error for the RESTINITAPPLICATION function.
The function accepts 1 to 3 parameters. 

Can anyone suggest a way, I can stop Coldfusion from throwing an error?

If I try and do the following:

<cfif CompareNoCase(request.engine,"Railo") EQ 0>
    <cfset RestInitApplication(dirPath=request.filepath & "\com\api",serviceMapping=local.serviceMapping,password=request.webAdminPassword) />
<cfelse>
    <cfset RestInitApplication( dirPath=request.filepath & "\com\api", serviceMapping=local.serviceMapping) />
</cfif>

ACF throws a different kind of compilation error:

Parameter validation error for the RESTINITAPPLICATION function.
A built-in ColdFusion function cannot accept an assignment statement as a parameter, although it can accept expressions. For example, RESTINITAPPLICATION(d=a*b) is not acceptable. 

And if I try:

<cfif CompareNoCase(request.engine,"Railo") EQ 0>
  <cfset this.webAdminPassword = request.webAdminPassword />
  <cfset RestInitApplication(request.filepath & "\com\api",local.serviceMapping) />
<cfelse>
  <cfset RestInitApplication(request.filepath & "\com\api",local.serviceMapping) />
</cfif>

Lucee throws an error telling me that the password is not defined.

Environment:

ACF11 on Windows 10

Lucee 4.5 on Windows 2008R2 Server

1
Any change if you specify the parameter names? ie restInitApplication( dirPath=request.filepath & "\com\api"), serviceMapping=local.serviceMapping) - SOS
This is a good idea, but ACF throws a different kind of compilation error. Parameter validation error for the RESTINITAPPLICATION function. A built-in ColdFusion function cannot accept an assignment statement as a parameter, although it can accept expressions. For example, RESTINITAPPLICATION(d=a*b) is not acceptable. - Charles Robertson
Sounds similar to what's mentioned in this entry. The function is messed up, because what you tried should work as the last 2 parameters are optional. Anyway, supplying the "optional" 3rd parameter (structure) seems to make it work: <cfset restInitApplication( request.filepath & "\com\api", local.serviceMapping, {})> - SOS
3 parameters are fine, but 4 is not, in ACF. And I need to provide Lucee with 4, because Password, is the 4th, unfortunately... - Charles Robertson
Yeah, that's irritating... In some cases I can see why they'd want to deviate, but not this one. Though Adobe definitely messed up the implementation too, just in a different way :-/ - SOS

1 Answers

5
votes

OK. I found a solution which is officially supported. If you look at the Adobe Coldfusion Official Documentation, paragraph entitled "Site-level REST application support", towards the bottom of the page:

https://helpx.adobe.com/coldfusion/developing-applications/changes-in-coldfusion/restful-web-services-in-coldfusion.html

It states that you can use the:

this.restsettings

For nearly all of the:

RestInitApplication()

Parameters.

I tried the ones it doesn't mention, like:

dirPath
password

And it works.

So here is the solution:

<cfif CompareNoCase(request.engine,"Railo") EQ 0>
  <cfset this.restsettings.dirPath = request.filepath & "\com\api" />
  <cfset this.restsettings.serviceMapping = local.serviceMapping />
  <cfset this.restsettings.password = request.webAdminPassword />
<cfelse>
  <cfset this.restsettings.dirPath = request.filepath & "\com\api" />
  <cfset this.restsettings.serviceMapping = local.serviceMapping />
</cfif>

UPDATE 1

I have sinced found out that when changes are made to the REST API CFCs, the rest application needs to be refreshed.

This is the purpose of:

RestInitApplication()

So, I have devised a solution to deal with this issue, that actually simplifies the routine. It seems like the only parameter that RestInitApplication() requires is:

dirPath

Based on this new information, here is the ammendment to my original answer:

<cftry>
  <cfif CompareNoCase(request.engine,"Railo") EQ 0>
    <cfset this.restsettings.password = request.webAdminPassword />
  </cfif>
  <cfset restInitApplication(local.dirPath,local.serviceMapping)>
  <cfcatch>
  </cfcatch>
</cftry>

You could actually remove the second parameter, and replace it with:

<cfset this.restsettings.serviceMapping = local.serviceMapping />

But, I will leave this decision up to you!

UPDATE 2:

After haveing spoken to Sean Corfield, he also suggested another approach, which is really clever.

Using:

<cfinclude>

As a container for each version of restInitApplication()

The code will not throw an error at compile time, even though the parameter count violation still exists. The cfinclude acts as a buffer, when placed inside a conditional clause.

So here is a second solution, and, in my opinion, the cleanest one, because, it intialises the REST API, the way it is meant to be done:

<cfif CompareNoCase(request.engine,"Railo") EQ 0>
  <cfset restinitdirpath = local.dirPath>
  <cfset restinitservicemapping = local.serviceMapping>
  <cfset restinitdefault = false>
  <cfset restinitpassword = request.webAdminPassword>
  <cfinclude template="includes/structures/rest/railo-rest-init-structure.cfm">
<cfelse>
  <cfset restinitdirpath = local.dirPath>
  <cfset restinitservicemapping = local.serviceMapping>
  <cfinclude template="includes/structures/rest/coldfusion-rest-init-structure.cfm">
</cfif>

railo-rest-init-structure.cfm

<cfoutput>

  <cfparam name="restinitdirpath" default="">
  <cfparam name="restinitservicemapping" default="">
  <cfparam name="restinitdefault" default="false">
  <cfparam name="restinitpassword" default="">

  <cfset restInitApplication(restinitdirpath,restinitservicemapping,restinitdefault,restinitpassword)>

</cfoutput>

coldfusion-rest-init-structure.cfm

<cfoutput>

  <cfparam name="restinitdirpath" default="">
  <cfparam name="restinitservicemapping" default="">

  <cfset restInitApplication(restinitdirpath,restinitservicemapping)>

</cfoutput>

Now, I have tested this and it works, and any changes made to your REST API CFCs, subsequently, will get detected each time restInitApplication() is hit.