REST Service not Working in ColdFusion 2018 running on Microsoft IIS 10.0
1) I installed IIS with ALL features and subfeatures;
2) I created a host "api.generic.lab" using hosts file located in C:\Windows\System32\drivers\etc then a website "api.generic.lab" in IIS using DefultAppPool;
3) I installed the ColdFusion 2018 developer mode with all features in "C:\ColdFusion" and at port 8594, then I ran the IIS_connector.bat located in "C:\ColdFusion\cfusion\bin\connetors";
4) I installed ALL ColdFusion updates (from 1 through 10);
5) In ColdFusion Administrator > Server Settings > Settings > API Manager Section I've checked "Allow REST Discovery" option;
6) I configuerd the web.config this way:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<httpProtocol>
<customHeaders>
<remove name="X-Powered-By" />
<add name="Access-Control-Allow-Credentials" value="true" />
<add name="Access-Control-Allow-Methods" value="GET, POST, PUT, HEAD, OPTIONS, DELETE" />
<add name="Access-Control-Max-Age" value="600" />
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="x-requested-with, Content-Type, origin, authorization, accept, client-security-token" />
<add name="Api-Version" value="2" />
</customHeaders>
</httpProtocol>
<security>
<requestFiltering>
<verbs>
<add verb="PUT" allowed="true" />
<add verb="DELETE" allowed="true" />
<add verb="PATCH" allowed="true" />
</verbs>
<fileExtensions>
<add fileExtension=".cfm" allowed="true" />
<remove fileExtension=".cfm" />
<add fileExtension=".cfc" allowed="true" />
<remove fileExtension=".cfc" />
</fileExtensions>
</requestFiltering>
</security>
<defaultDocument>
<files>
<clear />
<add value="index.cfm" />
</files>
</defaultDocument>
<directoryBrowse enabled="true" />
<urlCompression doStaticCompression="true" doDynamicCompression="true" />
<handlers>
<add name="asp_as_html" path="*.html" verb="*" modules="IsapiModule" scriptProcessor="%windir%\system32\inetsrv\asp.dll" />
<add name="asp_as_htm" path="*.htm" verb="*" modules="IsapiModule" scriptProcessor="%windir%\system32\inetsrv\asp.dll" />
</handlers>
<httpErrors existingResponse="PassThrough" errorMode="Custom" />
</system.webServer>
</configuration>
7) I created a simple application.cfc using cfscript:
component output=true displayName='Application' hint='Application that uses global variables and manages accesses.'{
this['name']='generic_api';
this['applicationTimeout']=createTimeSpan(0,0,2,30);
this['appBasePath']=expandPath('/');
this['timeout']=900;
this['enableRobustException']=true; // alterar para false no ambiente de Produção
this['sessionManagement']=false;
// this['sessionTimeout']=createTimeSpan(0,0,2,30);
// this['loginStorage']='session';
this['passArrayByReference']=true;
this['searchImplicitScopes']=false;
this['enableNULLSupport']=true;
this['sameFormFieldsAsArray']=true;
this['scriptProtect']='all';
this['secureJSON']=false;
this['wsChannels']=[{'name'='w_generic'}];
// this['wsChannels']=[{'name'='w_generic','cfcListener'='_src._pgs._str._webSocket'}];
/* this['sessionCookie']={
'domain'='generic.lab'
, 'sameSite'='Lax'
, 'secure'=true
, 'httpOnly'=true
, 'disableUpdate'=true
};
*/
this['serialization']={
'preserveCaseForStructKey'=true
, 'serializeQueryAs'='struct'
, 'preserveCaseForQueryColumn'=true
};
/* this['SMTPserverSettings']={
'server'='smtp.sceiffer.com'
, 'username'='sceiffer@sceiffer.com'
, 'password'='Ah-Ah-Ah-you-didnt-say-the-magic-word'
, 'port'=465
};
*/
setting enableCFoutputOnly=false showDebugOutput=false;
public boolean function onApplicationStart(){
application['s_dataSources']={
's_dsn'={
's_mssql'={
'dataSource'='generic_mssql'
}
, 's_mysql'={
'dataSource'='generic_mysql'
}
}
, 's_qoq'={
'DBType'='query'
}
};
application['s_timeZone']={
'v_UTC'=duplicate(getTimeZoneInfo()['utcTotalOffset'])
, 'v_local'=duplicate(getTimeZoneInfo()['utcTotalOffset'])*(-1)
};
application['s_smtp']=duplicate(this['SMTPserverSettings']);
application['s_block']={
'v_authentication'=3
};
local['a_restDirectories']=directoryList(path=expandPath('/rest/'),recurse=false,listInfo='path');
if(yesNoFormat(arrayLen(local['a_restDirectories']))){
local['i_directory']=0;
for(local.i_directory in local.a_restDirectories){
restInitApplication(local['i_directory'],listLast(local['i_directory'],'\'));
}
}
return true;
}
public void function onSessionStart(){
return;
}
public boolean function onMissingTemplate(required string targetPage){
return true;
}
public boolean function onRequestStart(required string targetPage){
return true;
}
public void function onRequest(required string targetPage){
setLocale('Portuguese (Brazilian)');
include arguments['targetPage'];
return;
}
public void function onCFCRequest(string cfcname,string method,struct args){
return;
}
public void function onAbort(required string targetPage){
return;
}
public void function onRequestEnd(){
return;
}
public void function onSessionEnd(required struct sessionScope,struct applicationScope={}){
return;
}
public void function onApplicationEnd(struct applicationScope={}){
local['a_restDirectories']=directoryList(path=expandPath('/rest/'),recurse=false,listInfo='path');
if(yesNoFormat(arrayLen(local['a_restDirectories']))){
local['i_directory']=0;
for(local.i_directory in local.a_restDirectories){
restDeleteApplication(local['i_directory']);
}
}
return;
}
public void function onError(required any exception,required string eventName){
local['v_newFolder']=expandPath('/_src/_dbg/')&'_'&dateFormat(dateAdd('s',application['s_timeZone']['v_UTC'],now()),'yyyy-mm-dd');
if(not(directoryExists(local['v_newFolder']))){
directoryCreate(local['v_newFolder']);
}
local['q_listErrorFiles']=directoryList(path=local['v_newFolder'],listInfo='query');
local['v_newFile']=timeFormat(dateAdd('s',application['s_timeZone']['v_UTC'],now()),'HH-mm-ss-lll');
local['v_simultaneous']=0;
local['s_query']={
'v_sql'="
select
1
from [local].[q_listErrorFiles]
where name=:v_errorFileName
;"
, 's_params'={
'v_errorFileName'={
'cfsqltype'='cf_sql_varchar'
, 'value'='_'&local['v_newFile']&'_'&toString(numberFormat(local['v_simultaneous'],'000'))&'.html'
}
}
};
local['q_getErrorFile']=queryExecute(sql=local['s_query']['v_sql'],params=local['s_query']['s_params'],options=application['s_dataSources']['s_qoq']);
while(local['q_getErrorFile'].recordCount>0){
local['v_simultaneous']=local['v_simultaneous']+1;
local['s_query']={
'v_sql'="
select
1
from [local].[q_listErrorFiles]
where name=:v_errorFileName
;"
, 's_params'={
'v_errorFileName'={
'cfsqltype'='cf_sql_varchar'
, 'value'='_'&local['v_newFile']&'_'&toString(numberFormat(local['v_simultaneous'],'000'))&'.html'
}
}
};
local['q_getErrorFile']=queryExecute(sql=local['s_query']['v_sql'],params=local['s_query']['s_params'],options=application['s_dataSources']['s_qoq']);
}
local['v_newFile']=local['v_newFolder']&'\'&'_'&local['v_newFile']&'_'&toString(numberFormat(local['v_simultaneous'],'000'))&'.html';
fileWrite(local['v_newFile'],'','utf-8');
writeDump(var=arguments,label='arguments',format='html',output=local['v_newFile']);
if(isDefined('variables')){
writeDump(var=variables,label='variables',format='html',output=local['v_newFile']);
}
writeDump(var=cgi,label='cgi',format='html',output=local['v_newFile']);
writeDump(var=server,label='server',format='html',output=local['v_newFile']);
if(isDefined('application')){
writeDump(var=application,label='application',format='html',output=local['v_newFile']);
}
writeDump(var=cookie,label='cookie',format='html',output=local['v_newFile']);
writeDump(var=url,label='url',format='html',output=local['v_newFile']);
if(isDefined('form')){
writeDump(var=form,label='form',format='html',output=local['v_newFile']);
}
return;
}
}
😎 I created a simple component named firstObj.cfc in D:\websites\generic.lab\SubDomains\api\rest\firstAPI:
component output=true rest=true restPath='firstObj'{
remote void function firstGET() httpMethod='GET' restPath='firstGET' produces='application/json'{
local['s_return']={
'status'=200
, 'content'=serializeJSON(data={'response'='Oi!'},useSecureJSONPrefix=false,useCustomSerializer=false)
};
restSetResponse(local['s_return']);
}
}
9) I created a simple index.cfm just to register the REST Service.
10) With REST Service registered, I tried to run the firstGET method including cfhttp tag at index.cfm
cfhttp(method='GET',url='http://api.generic.lab/rest/firstAPI/firstObj/firstGET',port=80,charset='utf-8',result='variables.s_result');
writeDump(var=variables.s_result);
11) Receiving the result "404 NOT FOUND", I lauched the REST Playground in ColdFusion Administrator > Data & Services > REST Services that comprehended the REST Service for host http://127.0.0.1:8594/rest/firstAPI/firstObj/firstGET. The result changed to "204 NO RESPONSE". When I change the host in REST Playground to http://api.generic.lab/rest/firstAPI/firstObj/firstGET the result came back to "404 NOT FOUND";
12) I've included some settings in restInitApplication function after REST mapping parameter:
restInitApplication(local['i_directory'],listLast(local['i_directory']),{
'skipCFCWithError'=false
, 'autoRegister'=true
, 'isDefault'=false
, 'useHost'=true
, 'host'='api.generic.lab'
});
13) The result was 404 NOT FOUND for both domains 127.0.0.1:8594 and api.generic.lab. I tried to change the isDefault to true then changed the address to http://api.generic.lab/rest/firstObj/firstGET but the result still was 404 NOT FOUND, I removed the host parameter then the REST Service was registered to api.generic.lab... Honestly, I don't know what to do just to see a SIMPLE REST function working.
