To publish web services for consumption by remote applications, you create the web service using ColdFusion components. For more information on components, see Chapter 11, "Building and Using ColdFusion Components".
ColdFusion components 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:
<cfcomponent>
<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, you must modify the function definition to add the access
attribute, 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:
access
attribute of the cffunction
tag must be remote
.
cffunction
tag must include the returnType
attribute to specify a return type.If the function does not return anything, set its returnType
attribute to void
.
output
attribute of the cffunction
tag must be set to No
because ColdFusion converts all output to XML to return it to the consumer.
required="false"
for the cfargument
tag is ignored. ColdFusion considers all parameters as required.
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:
<cfcomponent>
<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:
In most cases, consumers of ColdFusion web services will be able to easily pass data to and return results from component functions by mapping their data types to the WSDL data types shown above.
For ColdFusion structures and queries, clients might have to perform some processing to map their data 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".
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
For example, you define a ColdFusion component as follows:
<cfcomponent>
<cffunction name = "echoString" returnType = "string" output = "no" access = "remote"> <cfargument name = "input" type = "string"> <cfreturn #arguments.input#> </cffunction> </cfcomponent>
If you register the component in Dreamweaver MX, it appears in the Application panel as the following figure shows:
Requesting the WSDL file returns the following:
<?xml version="1.0" encoding="UTF-8" ?>
<wsdl:definitions targetNamespace="http://webservices" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:intf="http://webservices" xmlns:impl="http://webservices-impl" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns="http://schemas.xmlsoap.org/wsdl/"> <wsdl:message name="echoStringResponse"> <wsdl:part name="return" type="SOAP-ENC:string" /> </wsdl:message> <wsdl:message name="echoStringRequest"> <wsdl:part name="input" type="SOAP-ENC:string" /> </wsdl:message> <wsdl:portType name="echo"> <wsdl:operation name="echoString" parameterOrder="in0"> <wsdl:input message="intf:echoStringRequest" /> <wsdl:output message="intf:echoStringResponse" /> </wsdl:operation> </wsdl:portType> <wsdl:binding name="echo.cfcSoapBinding" type="intf:echo"> <wsdlsoap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http" /> <wsdl:operation name="echoString"> <wsdlsoap:operation soapAction="" style="rpc" /> <wsdl:input> <wsdlsoap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://webservices" /> </wsdl:input> <wsdl:output> <wsdlsoap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://webservices" /> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="echo.cfcService"> <wsdl:port name="echo.cfc" binding="intf:echo.cfcSoapBinding"> <wsdlsoap:address location="http://SMGILSON02/webservices/echo.cfc" /> </wsdl:port> </wsdl:service> </wsdl:definitions>
<cfcomponent output="false"> <cffunction name = "echoString" returnType = "string" output = "no" access = "remote"> <cfargument name = "input" type = "string"> <cfreturn #arguments.input#> </cffunction> </cfcomponent>
<cfinvoke webservice ="http://localhost/echo.cfc?wsdl" method ="echoString" input = "hello" returnVariable="foo"> <cfoutput>#foo#</cfoutput>
The following string appears in your browser:
hello
You can also invoke the web service using the following code:
<cfscript>
ws = CreateObject("webservice", "http://localhost/echo.cfc?wsdl"); wsresults = ws.echoString("hello"); writeoutput(wsresults); </cfscript>
ColdFusion components let you define both methods and properties of the component. Once defined, you can use components to define data types for web services. The following code defines a component in the file address.cfc:
<cfcomponent>
<cfproperty name="Number" type="numeric"> <cfproperty name="Street" type="string"> <cfproperty name="City" type="string"> <cfproperty name="State" type="string"> <cfproperty name="Country" type="string"> </cfcomponent>
This component contains properties that represent a street address. The following code defines a component in the file name.cfc that defines first and last name properties:
<cfcomponent>
<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:
<cfcomponent>
<cffunction name="echoName" returnType="name" access="remote"> <cfargument name="input" type="name"> <cfreturn #arguments.input#> </cffunction> <cffunction name="echoAddress" returnType="address" access="remote"> <cfargument name="input" type="address"> <cfreturn #arguments.input#> </cffunction> </cfcomponent>
Note: If the component files are not in a directory under your web root, you must create a ColdFusion mapping to the directory containing them.
If you register the component in Dreamweaver MX, it appears in the Application panel as the following figure shows:
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, shown below is the definition for name:
<complexType name="name">
<all> <element name="Firstname" nillable="true" type="xsd:string" /> <element name="Lastname" nillable="true" type="xsd:string" /> </all> </complexType>
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 Chapter 11, "Building and Using ColdFusion Components".
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's browser opens a login prompt containing a username 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 username and password information as part of the request. The cfinvoke
tag includes the username
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:
<cfinvoke webservice = "http://some.wsdl" returnVariable = "foo" ... username="aName" password="aPassword"> <cfoutput>#foo#</cfoutput>
ColdFusion inserts the username/password string in the authorization
request header as a base64 binary encoded string, with a colon separating the username and password. This method of passing the username/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 username 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".
Instead of letting the web server control access to your web services, you can handle the username/password string in your Application.cfm file as part of your own security mechanism. In this case, you use the cflogin
tag to retrieve the username/password information from the authorization
header, decode the binary string, and extract the username and password, as the following example Application.cfm file shows:
<cfsilent>
<cflogin> <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 username/password, return a 401 error. The browser then prompts the user for a username/password. ---> <cfheader statuscode="401"> <cfheader name="WWW-Authenticate" value="Basic realm=""Test"""> <cfabort> </cfif> </cfsilent>
This example does not show how to perform user verification. For more information on verification, see Chapter 16, "Securing Applications".
ColdFusion components offer role-based security. The following example creates a component method that deletes files:
<cfcomponent>
<cffunction name="deleteFile" access="remote" roles="admin,manager"> <cfargument name="filepath" required="yes"> <cffile action="DELETE" file=#arguments.filepath#> </cffunction> </cfcomponent>
In the example, the cffunction
tag includes the roles
attribute to specify the user roles allowed to access it. In this example, only users in the role admin
and manager
can access the function. Notice that multiple roles are delimited by a comma.
Role based security can be used with any ColdFusion component, not just for web services. For more information on roles, see Chapter 16, "Securing Applications".
You can implement your own security within the a function to protect resources. For example you can use the ColdFusion function IsUserInRole()
to determine if a user is in particular role, as the following example shows:
<cffunction name="foo">
<cfif IsUserInRole("admin")> ... do stuff allowed for admin <cfelseif IsUserInRole("user")> ... do stuff allowed for user <cfelse> <cfoutput>unauthorized access</cfoutput> <cfabort> </cfif> </cffunction>
ColdFusion web services provide a powerful mechanism for publishing and consuming application functionality. However, before you produce web services for publication, you might want to consider the following best practices: