Publishing web services

To publish web services for consumption by remote applications, you create the web service using ColdFusion components. For more information on components, see Building and Using ColdFusion Components.

Creating components for web services

ColdFusion components (CFCs) encapsulate application functionality and provide a standard interface for client access to that functionality. A component typically contains one or more functions defined by the cffunction tag. 
For example, the following component contains a single function:

<cffunction name="echoString" returnType="string" output="no">
<cfargument name="input" type="string">
<cfreturn #arguments.input#>
</cffunction>
</cfcomponent>

The function, named echoString, echoes back any string passed to it. To publish the function as a web service, modify the function definition to add the access attribute and specify remote, as the following example shows:

<cffunction name="echoString" returnType="string" output="no" access="remote">

By defining the function as remote, ColdFusion includes the function in the WSDL file. Only those functions marked as remote are accessible as a web service.
The following list defines the requirements for how to create web services for publication:

  1. The value of the access attribute of the cffunction tag must be remote.
  2. The cffunction tag must include the returnType attribute to specify a return type.
  3. The output attribute of the cffunction tag must be set to No because ColdFusion converts all output to XML to return it to the consumer.
  4. The attribute setting required="false" for the cfargument tag is ignored. ColdFusion considers all parameters as required.

Specifying data types of function arguments and return values

The cffunction tag lets you define a single return value and one or more input parameters passed to a function. As part of the function definition, you include the data type of the return value and input parameters. 
The following example shows a component that defines a function with a return value of type string, one input parameter of type string, and one input parameter of type numeric:

<cffunction name="trimString" returnType="string" output="no">
<cfargument name="inString" type="string">
<cfargument name="trimLength" type="numeric">
</cffunction>
</cfcomponent>

As part of publishing the component for access as a web service, ColdFusion generates the WSDL file that defines the component where the WSDL file includes definitions for how ColdFusion data types map to WSDL data types. The following table shows this mapping:

ColdFusion data type

WSDL data type published

numeric

SOAP-ENC:double

Boolean

SOAP-ENC:boolean

string

SOAP-ENC:string

array

SOAP-ENC:Array

binary

xsd:base64Binary

date

xsd:dateTime

guid

SOAP-ENC:string

uuid

SOAP-ENC:string

void (operation returns nothing)

 

struct

Map

query

QueryBean

any

complex type

component definition

complex type

In most cases, consumers of ColdFusion web services can easily pass data to and return results from component functions by mapping their data types to the WSDL data types shown in the preceding table.

Note: Document-literal web services use XML schema data types, not SOAP-ENC data types. For more information, see Publishing document-literal style web services.

For ColdFusion structures and queries, Some clients must process their data to map it to the correct type. For more information, see Publishing web services that use complex data types.
You can also define a data type in one ColdFusion component based on another component definition. For more information on using components to specify a data type, see Using ColdFusion components to define data types for web services.

Producing WSDL files

ColdFusion automatically creates a WSDL file for any component referenced as a web service. For example, if you have a component named echo.cfc in your web root directory, you can view its corresponding WSDL file by requesting the component as follows:

http://localhost/echo.cfc?wsdl

The cfcomponent tag includes optional attributes that you can use to control the WSDL that ColdFusion generates. You can use these attributes to create meaningful WSDL attribute names, as the following example shows:

namespace = "http://www.mycompany.com/"
serviceportname = "RestrictedEmpInfo"
porttypename = "RestrictedEmpInfo"
bindingname = "myns:RestrictedEmpInfo"
displayname = "RestrictedEmpInfo"
hint = "RestrictedEmpInfo">

 

Note: For complete control of the WSDL, advanced users can specify the cfcomponent wsdlFile_ attribute to use a predefined WSDL file._

The following example defines a ColdFusion component that can be invoked as a web service:

<cffunction
name = "echoString"
returnType = "string"
output = "no"
access = "remote">
<cfargument name = "input" type = "string">
<cfreturn #arguments.input#>
</cffunction>
</cfcomponent>

 

Note: If you register the component in Dreamweaver, it appears in the Components tab of the Application panel.

Requesting the WSDL file in a browser returns the following:

<wsdl:definitions targetNamespace="http://ws"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:apachesoap="http://xml.apache.org/xml-soap"
xmlns:impl="http://ws"
xmlns:intf="http://ws"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:tns1="http://rpc.xml.coldfusion"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<!--WSDL created by ColdFusion -->
<wsdl:types>
<schema targetNamespace="http://rpc.xml.coldfusion"
xmlns="http://www.w3.org/2001/XMLSchema">
<import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>
<complexType name="CFCInvocationException">
<sequence/>
</complexType>
</schema>
</wsdl:types>
<wsdl:message name="CFCInvocationException">
<wsdl:part name="fault" type="tns1:CFCInvocationException"/>
</wsdl:message>
<wsdl:message name="echoStringResponse">
<wsdl:part name="echoStringReturn" type="xsd:string"/>
</wsdl:message>
<wsdl:message name="echoStringRequest">
<wsdl:part name="input" type="xsd:string"/>
</wsdl:message>
<wsdl:portType name="echo">
<wsdl:operation name="echoString" parameterOrder="input">
<wsdl:input message="impl:echoStringRequest" name="echoStringRequest"/>
<wsdl:output message="impl:echoStringResponse"
name="echoStringResponse"/>
<wsdl:fault message="impl:CFCInvocationException" name="CFCInvocationException"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="echo.cfcSoapBinding" type="impl:echo">
<wsdlsoap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/
http"/>
<wsdl:operation name="echoString">
<wsdlsoap:operation soapAction=""/>
<wsdl:input name="echoStringRequest">
<wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/
encoding/" namespace="http://ws" use="encoded"/>
</wsdl:input>
<wsdl:output name="echoStringResponse">
<wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/
encoding/" namespace="http://ws" use="encoded"/>
</wsdl:output>
<wsdl:fault name="CFCInvocationException">
<wsdlsoap:fault encodingStyle="http://schemas.xmlsoap.org/soap/
encoding/" name="CFCInvocationException" namespace=
"http://ws" use="encoded"/>
</wsdl:fault>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="echoService">
<wsdl:port binding="impl:echo.cfcSoapBinding" name="echo.cfc">
<wsdlsoap:address location="http://localhost:8500/ws/echo.cfc"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>

Publish a web service
  1. Create a ColdFusion page with the following content:

    <cffunction
    name = "echoString"
    returnType = "string"
    output = "no"
    access = "remote">
    <cfargument name = "input" type = "string">
    <cfreturn #arguments.input#>
    </cffunction>
    </cfcomponent>

  2. Save this file as echo.cfc in your web root directory.
  3. Create a ColdFusion page with the following content:

    <cfinvoke webservice ="http://localhost/echo.cfc?wsdl"
    method ="echoString"
    input = "hello"
    returnVariable="foo">

    <cfoutput>#foo#</cfoutput>

  4. Save this file as echoclient.cfm in your web root directory.
  5. Request echoclient.cfm in your browser. The following string appears in your browser:

    hello

You can also invoke the web service using the following code:

ws = CreateObject("webservice", "http://localhost/echo.cfc?wsdl");
wsresults = ws.echoString("hello");
writeoutput(wsresults);
</cfscript>

Using ColdFusion components to define data types for web services

ColdFusion lets you define components that contain only properties. Once defined, you can use components to define data types for web services. The following code defines a component in the file address.cfc that contains properties that represent a street address:

<cfproperty name="AddrNumber" type="numeric">
<cfproperty name="Street" type="string">
<cfproperty name="City" type="string">
<cfproperty name="State" type="string">
<cfproperty name="Country" type="string">
</cfcomponent>

The following code defines a component in the filename.cfc that defines first and last name properties:

<cfproperty name="Firstname" type="string">
<cfproperty name="Lastname" type="string">
</cfcomponent>

You can then use address and name to define data types in a ColdFusion component created to publish a web service, as the following example shows:

<cffunction
name="echoName" returnType="name" access="remote" output="false">
<cfargument name="input" type="name">
<cfreturn #arguments.input#>
</cffunction>

<cffunction
name="echoAddress" returnType="address" access="remote" output="false">
<cfargument name="input" type="address">
<cfreturn #arguments.input#>
</cffunction>
</cfcomponent>

 

Note: If the component files are not in a directory under your web root, create a web server mapping to the directory that contains them. You cannot use ColdFusion mappings to access web services.

The WSDL file for the web service contains data definitions for the complex types name and address. Each definition consists of the elements that define the type as specified in the ColdFusion component file for that type. For example, the following example shows the definition for name:

<sequence>
<element name="firstname" nillable="true" type="soapenc:string"/>
<element name="lastname" nillable="true" type="soapenc:string"/>
</sequence>
</complexType>

You can also specify an array of CFCs in the returnType attribute, as the following example shows:

<cffunction
name="allNames" returnType="name[]" access="remote" output="false">
<cfset var returnarray = ArrayNew(1)>
<cfset var temp = "">
<cfquery name="empinfo" datasource="cfdocexamples">
SELECT firstname, lastname
FROM employee
</cfquery>
<cfloop query="empinfo" >
<cfobject component="name" name="tempname">
<cfset tempname.Firstname = #empinfo.firstname#>
<cfset tempname.Lastname = #empinfo.lastname#>
<cfset temp = ArrayAppend(returnarray, tempname)>
</cfloop>
<cfreturn returnarray>
</cffunction>
</cfcomponent>

When you invoke the web service, it returns an array of CFCs. Access the properties in the CFC by using dot notation, as the following example shows:

<cfinvoke webservice ="http://localhost:8500/ws/cfcarray.cfc?wsdl"
method ="allNames"
returnVariable="thearray">

<cfif IsArray(thearray)>
<h1>loop through the employees</h1>
<p>thearray has <cfoutput>#ArrayLen(thearray)#</cfoutput> elements.</p>
<cfloop index="i" from="1" to="#ArrayLen(thearray)#">
<cfoutput>#thearray[i].firstname#, #thearray[i].lastname# </cfoutput><br>
</cfloop>
<cfelse>
<h1>Error: thearray is not an array</h1>
</cfif>

Publishing document-literal style web services

In addition to RPC-oriented operations, for which consumers specify a method and arguments, ColdFusion also lets you publish web services using the document-literal style. When you use document-literal style, the WSDL for the web service tells the client to use XML schemas rather than RPC calling conventions.
In most cases, the publisher of a web services identifies it as document-literal or RPC style. To identify the type, open the WSDL document and find the soap:binding element and examine its style attribute, as the following example shows:

<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document" />

In this example, the style is document-literal. Examine the WSDL to determine the methods you can call and the parameters for each method.
On the client side, the cfinvoke tag and other ColdFusion methods for calling web services handle the style automatically. In most cases, no modifications are necessary. Similarly, when publishing CFCs as document-literal style web services, ColdFusion automatically creates and manages the appropriate WSDL.
To publish CFCs as document-literal style web services, specify cfcomponent style="document", along with the other attributes required for document-literal style web services. For example, ColdFusion publishes the following CFC using document-literal style:

<cffunction
name = "getEmp"
returntype="string"
output = "no"
access = "remote">
<cfargument name="empid" required="yes" type="numeric">
<cfset var fullname = "">
<cfquery name="empinfo" datasource="cfdocexamples">
SELECT emp_id, firstname, lastname
FROM employee
WHERE emp_id = <cfqueryparam cfsqltype="cf_sql_integer"
value="#arguments.empid#">
</cfquery>
<cfif empinfo.recordcount gt 0>
<cfset fullname = empinfo.lastname & ", " & empinfo.firstname>
<cfelse>
<cfset fullname = "not found">
</cfif>
<cfreturn #fullname#>
</cffunction>
</cfcomponent>

Securing your web services

You can restrict access to your published web services to control the users allowed to invoke them. You can use your web server to control access to the directories containing your web services, or you can use ColdFusion security in the same way that you would to control access to any ColdFusion page.

To browse the HTML description of a CFC file, you request the file by specifying a URL to the file in your browser. By default, ColdFusion secures access to all URLs that directly reference a CFC file, and prompts you to enter a password upon the request. Use the ColdFusion RDS password to view the file.
To disable security on CFC file browsing, use the ColdFusion Administrator to disable the RDS password. 
For more information, see Building and Using ColdFusion Components.

Using your web server to control access

Most web servers, including IIS and Apache, implement directory access protection using the basic HTTP authentication mechanism. When a client attempts to access one of the resources under a protected directory, and has not properly authenticated, the web server automatically sends back an authentication challenge, typically an HTTP Error 401 Access Denied error. 
In response, the client browser opens a login prompt containing a user name and password field. When the user submits this information, the browser sends it back to the web server. If authentication passes, the web server allows access to the directory. The browser also caches the authentication data as long as it is open, so subsequent requests automatically include the authentication data. 
Web service clients can also pass the user name and password information as part of the request. The cfinvoke tag includes the user name and password attributes that let you pass login information to a web server using HTTP basic authentication. You can include these attributes when invoking a web service, as the following example shows:

webservice = "http://some.cfc?wsdl"
returnVariable = "foo"
...
username="aName"
password="aPassword">
<cfoutput>#foo#</cfoutput>

ColdFusion inserts the user name/password string in the authorization request header as a base64 binary encoded string, with a colon separating the user name and password. This method of passing the user name/password is compatible with the HTTP basic authentication mechanism used by web servers. 
The ColdFusion Administrator lets you predefine web services. As part of defining the web service, you can specify the user name and password that ColdFusion includes as part of the request to the web service. Therefore, you do not have to encode this information using the cfinvoke tag. For information on defining a web service in the ColdFusion Administrator, see Configuring web services in the ColdFusion Administrator in Consuming web services.

Using ColdFusion to control access

Instead of letting the web server control access to your web services, you can handle the user name/password string in your Application.cfc or Application.cfm file as part of your own security mechanism. In this case, you use the cflogin tag to retrieve the user name/password information from the authorization header, decode the binary string, and extract the user name and password, as the following excerpt from an Application.cfc onRequestStart method shows:

<cfset isAuthorized = false>

<cfif isDefined("cflogin")
<!--- Verify user name from cflogin.name and password from
cflogin.password using your authentication mechanism. --->
>
<cfset isAuthorized = true>
</cfif>
</cflogin>

<cfif not isAuthorized>
<!--- If the user does not pass a user name/password, return a 401 error.
The browser then prompts the user for a user name/password. --->
<cfheader statuscode="401">
<cfheader name="WWW-Authenticate" value="Basic realm=""Test""">
<cfabort>
</cfif>

This example does not show how to perform user verification. For more information on verification, see Securing Applications.

Best practices for publishing web services

ColdFusion web services provide a powerful mechanism for publishing and consuming application functionality. However, before you produce web services for publication, consider the following best practices:

  1. Minimize the use of ColdFusion complex types, such as query and struct, in the web services you create for publication. These types require consumers, especially ones that consume the web service using a technology other than ColdFusion, to create special data structures to handle complex types.
  2. Locally test the ColdFusion components implemented for web services before publishing them over the Internet.

 Adobe

Get help faster and easier

New user?