|
Building a Basic Web Service With ColdFusion MX
by Peter deHaan
PRINT THIS TUTORIAL
In the Beginning...
Before you get into the "meat and potatoes" of building a Web Service, the most important thing to find out is that you have ColdFusion installed. If you haven't downloaded it already, head over to the official Macromedia ColdFusion page at www.macromedia.com/software/coldfusion. Macromedia has a nice setup, where they let you try the software free of charge (naturally) for 30 days, at which point the software reverts to a "single-ip developer edition". Translation: you can use the software as long as you want, but you will only be able to use it from a single IP address and won't be able to host public sites or anything. A fair deal if you ask me!
After you install ColdFusion MX and you've verified it is working correctly, you're ready to begin. If you don't have a web server installed, fret not! Macromedia even includes a basic Web Server which works for development purposes. This is a lot easier than having to set up Apache or IIS just to evaluate ColdFusion. For our purposes here, we're assuming that you've installed the latest version of ColdFusion (at the time of writing, that happens to be CFMX 6.1) and are using the included development Web Server running on port 8500 (the default). If you're using IIS or Apache, or managed to change the port of the Web Server, you will need to modify any addresses accordingly so they connect to either port 80 (default for WWW -- so feel free to omit the port altogether) or use whatever available port you happen to be using.
Onward and forward!
Create a new file in your Web Root (the default location for the included Web Server is C:\CFusionMX\wwwroot\ -- if you're using IIS, it may be at C:\Inetpub\wwwroot\) and name it "helloworld.cfc". We'll start with the obligatory, and completely irrelevant, "Hello World" example. If this is the first time you've ever worked with ColdFusion, I'll give you a very (VERY) quick overview. ColdFusion templates typically end with the extension CFM or even CFML. Writing Web Services is a new addition to ColdFusion MX, and these Web Services have the extension CFC, short for "ColdFusion Component". There, now you're up to speed!
Open the file in your HTML editor of choice (such as HomeSite+, Dreamweaver, Notepad, etc.) and type in the following:
<cfcomponent>
<cffunction name="HelloWorld" access="remote" returntype="string">
<cfreturn "Hello World">
</cffunction>
</cfcomponent>
Save the file and open your Web browser of choice. Enter the address of the CFC into the address bar.
Note: If you're using the included Web Server, it would likely be at http://localhost:8500/helloworld.cfc).
Click the Enter key. If all goes well, you should be taken to a login screen prompting you for your "RDS or Admin password".
Now that you're thoroughly confused, allow me to explain. Viewing your CFC file directly takes you to a handy little "component inspector" which shows you a nice list of methods and properties in your Web Service. The most important piece of code in the above snippet is the "access" parameter. That parameter needs to be set to "remote" for the Web Service to work. If that parameter was set to "Public" or "Private" or omitted altogether, you would be unable to have remote users consume that particular method. While it doesn't necessarily prevent you from consuming the Web Service yourself on the same site, it can make it impossible if you are connecting using Flash or consuming the Web Service from a different site/server.
If we had bothered to write some special documentation in our CFC, we'd also be able to view the special comments on this page (which you'll see in a minute). Open another Web browser and again enter the address to helloworld.cfc - but this time add ?wsdl to the end of the CFC in the address bar. Your URL should now look similar to http://localhost:8500/helloworld.cfc?wsdl, or, if your Web Server is configured on port 80 it would simply be http://localhost/helloworld.cfc?wsdl. Your browser should now be displaying a whole bunch of cryptic looking XML syntax which makes no sense whatsoever. If you're able to view the XML, then everything has probably worked perfectly and your Web Service was a success, but more on that in a second.
Back in your HTML editor of choice, create a new file in the same folder as helloworld.cfc, name the new file helloworld_test.cfm and enter the following code:
<cfinvoke webservice="http://localhost/helloworld.cfc?wsdl"
method="HelloWorld" returnvariable="result">
</cfinvoke>
<cfoutput>#result#</cfoutput>
Save the new file and open it in your Web browser (the URL should be similar to http://localhost:8500/helloworld_test.cfm). With a bit of luck, the browser should now greet you with a pleasant "Hello World". While you're busy reeling from the impressive powerhouse that is ColdFusion and Web Services, lets look at what the code is doing here. The <cfinvoke> tag invokes the specified Web Service (note that the URL needs to have the ?wsdl appended or it won't work) and calls our HelloWorld method. We also specified a "returnvariable" (in this example named 'result') which will hold the result sent from the Web Service, or in this case, the string "Hello World". The remainder of the code closes the cfinvoke tag and outputs the #result# variable to the user's browser using ColdFusion's cfoutput tag. But wait, it gets better.
Return to your HTML editor for a second, and you'll look at how to properly document your Web Service CFC file so that it gives additional output in that component inspector screen.
<cfcomponent displayname="My First Web Service -- Hello World"
hint="This Web Service serves no practical purpose at all.">
<cffunction name="HelloWorld" access="remote" returntype="string"
displayname="My Hello World method"
hint="Returns the string 'Hello World'. Useful? Hardly.">
<cfreturn "Hello World">
</cffunction>
</cfcomponent>
Modify the existing code in the CFC and replace it with the code above. If you don't want to lose all that precious code you've already entered, you can simply comment it out using the ColdFusion comment tags of <!--- and --->. Note that they are exactly the same as HTML comments, except have one extra "-". After you paste the above code into the CFC and save the freshly modified file, view the file CFC file (without the ?wsdl in the address) to view the changes in the component inspector. You should now see some additional information on the screen that explains what the component itself does, and what each method (or the one method at least) does. It is worth mentioning that adding the "displayname" and "hint" parameters to the cfcomponent and cffunction tags don't affect the XML generated by ColdFusion when you append ?wsdl to the address. Perfect! Now, let's add another method to this less than exciting example.
Create another method in the Hello World component named "HelloName". This method accepts a single parameter and returns a personalized greeting. Far from interesting, I know, but baby steps.
Add the following code after the first method, but before the closing </cfcomponent> tag:
<cffunction name="HelloName" access="remote" returntype="string"
displayname="My Hello Name method"
hint="Accepts a single parameter and returns a greeting.">
<cfargument name="Name" type="string" required="Yes">
<cfreturn "Hello, #Arguments.Name#.">
</cffunction>
Ah, now you're getting somewhere. This time the Web Service accepts a single parameter Name and returns a personalized greeting. Still not overly useful, but getting there! In order to accept arguments to the method, you used the cfargument tag. If you haven't noticed already, all ColdFusion tags are prefixed by the letters "CF", which makes them a bit easier to distinguish from HTML tags. The cfargument tag specifies that a single parameter can be supplied, named "Name", and must be a string data type. The last parameter in the cfargument tag, "required", means that the Name MUST be supplied to the Web Service otherwise you'll get an error. Finally you return a string which is your personalized greeting of "Hello, ____." The name passed in as an argument is basically just echoed back to the user. You also need to mention that ColdFusion variables are often (except for some circumstances) enclosed in pound, or hash, signs (#). When you return a string, ColdFusion replaces the value of #Arguments.Name# with the actual value supplied to the Web Service. Enough talk, let’s see this in action.
In your HTML editor, open up the helloworld_test.cfm file you created earlier and modify the existing code to the code in the following example:
<cfinvoke webservice="http://localhost/helloworld.cfc?wsdl"
method="HelloName" returnvariable="result">
<cfinvokeargument name="Name" value="Gus">
</cfinvoke>
<cfoutput>#result#</cfoutput>
Save and rerun the code in your Web browser and this time it should say "Hello, Gus." Fascinating, no?
Naturally, this is just scratching the surface of what you can do with Web Services and ColdFusion. The previous two examples have no practical usage in the "real world", but it does introduce you to a few key concepts. Also remember that a Web Service can only return a single value. In the previous two examples, you returned strings - but you can also return arrays, numbers, objects, queries (if your site happens to use a database), Boolean (true/false) values, or dates.
Calling 3rd Party Web Services Using ColdFusion
Let's look at a useful example that uses a third party Web Service off of www.xmethods.net. For this example, you will do a WhoIs lookup on an IP address. Create a new ColdFusion document named "whoislookup.cfm" and type the following code into your document:
<cfinvoke webservice="http://ws.cdyne.com/whoisquery/whois.asmx?WSDL"
method="QueryIP" returnvariable="ip_info">
<cfinvokeargument name="IPaddress" value="216.239.37.99">
<cfinvokeargument name="LicenseKey" value="0">
</cfinvoke>
<cfoutput>#ip_info#</cfoutput>
The code is fairly similar to the previous example, except this time the Web Service and method properties are different, as well as a different set of arguments to the Web Service. You could also somewhat shorten the above code by passing the arguments in the cfinvoke tag instead of having to use the cfinvokeargument tag. It is easier to show you the code;
<cfinvoke webservice="http://ws.cdyne.com/whoisquery/whois.asmx?WSDL"
method="QueryIP" returnvariable="ip_info"
IPaddress="216.239.37.99" LicenseKey="0">
</cfinvoke>
<cfoutput>#ip_info#</cfoutput>
Save the new file and test it in a Web browser. You should see a poorly formatted bunch of nonsense with the word "google" sprinkled throughout. You've just managed to syndicate an existing Web Service and find out that google owns a particular IP address. Again, not hugely useful, but not bad! Lets first work on cleaning out the formatting of the results. There are two ways you can easily format the result from the Web Service; using the pre tag, or the textarea tag. Let's use the textarea approach, because it will look a bit cleaner.
In the above code, replace the last line with the following code:
<cfoutput>
<textarea cols="80" rows="25" wrap="soft" name="result">#ip_info#</textarea>
</cfoutput>
Save the file and refresh your browser. Now the result should display all nice and tidy. You can replace the IP address in the script with anything you want. Sometimes the IP address can show very useful information. For example, if you happen to receive a piece of spam in your inbox from the IP address "66.26.166.255", you can see that some filthy monkey using the Road Runner service is sending you junk and wasting your bandwidth. Or, what's even more useful is if you modify the script above to use the IP address of the user viewing the page.
ColdFusion lets you grab the current user's IP address by using the following variable, #CGI.REMOTE_ADDR#. Now, before you think this is the next best thing since buttered bread, it will only display that user's information on their own display. You can't use this to really watch the IP owner information on your monitor in real time (although with a bit of coding you could). So, again, change the IP address in the code above to #CGI.REMOTE_ADDR# in the appropriate cfinvokeargument tag and resave you work. Then refresh your browser.
If you installed ColdFusion on your local desktop, the value of #CGI.REMOTE_ADDR# is probably "127.0.0.1" which is the same as your local machine. So essentially, it tells you nothing useful. Likewise, if you're behind a firewall you'll probably see an IP address of "192.168.0.100" or "10.0.0.1" or something like that. Each of those IP addresses and addresses similar to those are special and are mainly used for internal networks. So, you're out of luck if you're trying to test your own service. But, the good news is that we can easily make a form where you can enter an IP address and run a whois search on it. Let’s go back and modify our example once again.
Modify the existing code in whoislookup.cfm so it looks like the following example:
<cfform action="whoislookup.cfm" method="post">
IP Address: <cfinput type="text" name="IPaddress"
value="#CGI.REMOTE_ADDR#" required="yes"
message="Please enter an IP address.">
<input type="Submit" value="Search">
</cfform>
<cfif IsDefined("Form.IPaddress")>
<cfinvoke
webservice="http://ws.cdyne.com/whoisquery/whois.asmx?WSDL"
method="QueryIP" returnvariable="ip_info"
IPaddress="216.239.37.99" LicenseKey="0">
</cfinvoke>
<cfoutput>
<textarea cols="80" rows="25" wrap="soft"
name="result">#ip_info#</textarea>
</cfoutput>
</cfif>
After you save and reload athe whoislookup.cfm template in your Web browser, you should be able to enter an IP address and do as many searches as you want. The nice part is that the IP address always defaults to the IP address of the current user. You can also see a couple new tags and functions in the above code. The first new bit of code is the cfform tag, which lets you easily build HTML forms and add JavaScript validation. You could have also used the regular old HTML form tags, and done your own JavaScript validation, or had no validation at all. The next new tag is the cfinput tag which displays an input field on the page where users can enter any IP address they want to check out.
The next bit of code checks to see if a variable exists. The IsDefined function is a little tricky in ColdFusion: it is one of the few places where you can't really put a # sign around the variable, but instead have to use a pair of quotes. The code says "if the Form variable "IPaddress" is defined, then execute the following code". If the variable wasn’t defined (such as, it's the user's first visit to the page) the block of code between the opening and closing cfif tag would be skipped. That is, unless there was a cfelse tag. A user can now use your page to look up as many IP addresses and find the IP address owner's address. That doesn't necessarily mean you'll know the name and address of the person sitting on the other end of the keyboard though. Earlier, you looked at that IP address of a random person who sent me spam. Doing a IP lookup of that delinquent revealed only that the Road Runner ISP owned that particular range of IP addresses, so there would be no use going to the returned street address to look for the spammer in person.
This also brings up a few other points worth mentioning. The whois Web Service (above) that you found listed deep in the xmethods.net Web site requires both an IP address and License Key for it to work. For evaluation purposes, you can use a license key value of 0 (zero) as you can find in the usage information on xmethods. If you want to use the service on your Web site, sign up and pay a monthly fee. This seems to be a growing trend on xmethods where some services require you to either sign up for free, or pay a monthly/yearly price in order to use the Web Service.
The other nice thing about using Web Services is that you can consume a Web Service written in an entirely different language above. The above URL for the whois Web Service points to an ASMX file, which is an ASP.NET Web Service. It doesn't really matter in this case if you connect to a ColdFusion, PHP, ASP or Java Web Service. ColdFusion can connect and pass the appropriate data back and forth without having to worry about what language the Web Service was written in.
Connecting to a remote service
Let's extend the above example a bit more and create a Web Service that connects to the remote whois Web Service. This allows us to build a whois client that uses Flash as a front-end instead of an HTML form. It is sometimes necessary to write your own Web Service that talks to other services so you can avoid certain Flash Player security limitations. Flash is much easier to work with if you're connecting to a Web Service located at the same domain as your Flash movie. Other times you may want to write your own Web Service in order to hide some of the programming complexity of the other service.
This time we'll create a service that inspects a remote Web site and returns the Web server that the site uses (ie: Apache, IIS, etc). This simple Web Service connects to the remote server and returns a series of values in an Object/structure. First let's look at the Web Service code. Place the following snippet in a new ColdFusion file named serverinfo_test.cfm:
<cfhttp url="http://www.google.com" method="GET"></cfhttp>
<cfdump var="#CFHTTP#">
The cfdump tag displays a variable, whether it is an array, object/structure, number, query/recordset, etc. If you save and run the previous snippet you'll see a big list of variables and corresponding values. The only value in the structure that you're interested in at this point is ResponseHeader, which happens to be an object itself.
Change the above code to only display the value of the Responseheader variable by changing the last line of the code to:
<cfdump var="#CFHTTP.ResponseHeader#">
Next you'll convert the sample code above to a basic Web Service. The service takes a single parameter, a URL, and returns the ResponseHeader structure. The code itself is only a few short lines of code, and not really any more complex than the HelloWorld example you looked at earlier. Create a new file named siteinfo.cfc and add the following code:
<cfcomponent>
<cffunction name="getSiteInfo" access="remote" returntype="struct">
<cfargument name="siteURL" type="string" required="yes">
<cfhttp url="#Arguments.siteURL#" method="GET"></cfhttp>
<cfreturn CFHTTP.ResponseHeader />
</cffunction>
</cfcomponent>
The Web Service only returns a single part of the response from the CFHTTP call.
First lets look at what the cfhttp tag is doing. The cfhttp tag is capable of many great things, one of which is retrieving a remote Web page (or XML file, or ...). In this example, you're simply grabbing the home page of a particular domain. With that out of the way, lets create a quick ColdFusion template to test the Web Service.
In your HTML editor, create a new document and enter the following code:
<cfinvoke webservice="http://localhost/siteinfo.cfc?wsdl"
method="getSiteInfo" returnvariable="siteinfo">
<cfinvokeargument name="siteURL" value="http://www.flash-mx.com">
</cfinvoke>
<cfdump var="#siteinfo#">
The code is fairly straight forward. Again, it just calls a CFC on the local server and passes a single parameter to the Web Service. The ColdFusion script dumps the results of the Web Service to the browser. You could easily display each item in a nicely formatted table using the following code:
<cfinvoke webservice="http://localhost/siteinfo.cfc?wsdl"
method="getSiteInfo" returnvariable="siteinfo">
<cfinvokeargument name="siteURL" value="http://www.flash-mx.com">
</cfinvoke>
<cfoutput>
<strong>Content-Type:</strong> #siteinfo["Content-Type"]#<br />
<strong>Date:</strong> #siteinfo["Date"]#<br />
<strong>Http_Version:</strong> #siteinfo["Http_Version"]#<br />
<strong>Server:</strong> #siteinfo["Server"]#<br />
<strong>Status_Code:</strong> #siteinfo["Status_Code"]#<br />
</cfoutput>
Calling a component locally
Before wrapping up, there is one last thing you should look at. Sometimes it is easier to call a component locally, instead of providing a full Web Service URL. The following snippet shows you an example of how to call the CFC as a component, instead of a Web Service. You just use the component name without the full URL or even the file extension (.cfc) or ?wsdl. This is shown in the following code:
<cfinvoke component="siteinfo" method="getSiteInfo"
returnvariable="siteinfo">
<cfinvokeargument name="siteURL" value="http://www.flash-mx.com">
</cfinvoke>
<cfdump var="#siteinfo#">
If the component was in a subfolder of the root folder, you need to prefix the component name with the folder name. For example, if the siteinfo.cfc component was in a folder named "mywebservices" in the root folder, you need to set the cfinvoke tag's component parameter to "mywebservices.siteinfo". The other trick is to separate folder's with a period (.) instead of a slash.
Conclusion
I hope you enjoyed this brief glimpse at building basic Web Services/components in ColdFusion. Look for future tutorials which will show you how to do some useful things with ColdFusion which you can integrate into your Web Services.
|