Tuesday, 18 May 2010

Writing Web Services for widgets

In a previous post I outlined the importance of web services to widget development, and pointed to two kinds of web service - proprietary ones which you can't alter, and locally written ones which you can. Today, I'm going to concentrate on locally written web services, and talk about some of the issues involved in writing your own web services. We're going to be making our code available towards the end of the project, so you should be able to pick up some complete examples soon. In the meantime, here are some of the basic ingredients of a home-baked web service.

1. Getting started
  • Programming language: we use Perl (and occasionally PHP).
  • Data source: the database or dataset you want to interact with (i.e. Library Management System).
  • Query language: the language you will use to retrieve or alter the data in this system. Usually SQL.
2. Finding a home
  • Your web services will need to live somewhere on your web server. In theory they can go anywhere, but it's best to have a separate directory for web services in general, and then distinct sub-directories for each system or dataset you want to interact with.
  • Putting all your web services into one overall directory has the added benefit of making it easier for your system administrator (or you) to keep on top of the permissions and settings needed for web service files. Basically, if you're writing web services in Perl, the directory needs to be CGI enabled, and the files need to be readable and executable by anybody (usual octal permissions 755).
3. Do a bit of thinking
  • If you're doing a lot of interaction with a dataset you'll probably have a range of questions/alterations you want to throw at it. Most "complete" transactions with datasets are made up of multiple smaller transactions (i.e. to book a train ticket, you might need to find the current time, find the next train, and book the ticket.)
  • Instead of trying to write one huge web service to do everything, break each activity into its smallest distinct parts. This will leave you with lots of small, simple web services, each of which does only one thing.
  • Now you can chain these simple services together into more complex transactions - but you can also reuse them in other transactions. This saves you asking the same question (i.e. "what's the time?") again and again in multiple web services.
4. What input do you need?
  • Web services are triggered by requests. These requests (like web services themselves) can be of two types - questions for services that retrieve data or instructions for services that alter data.
  • Requests are made up of the location of the web service, plus as many parameters as are necessary to either frame the question or perform the instruction. These parameters make up the input for the web service.
  • The smallest amount of parameters needed is none. Think about a question like "what's the time?". If you had a web service which just gave back the current time when triggered, no further parameters would be needed.
  • Most web services take at least one parameter. Taking the "what's the time?" service, if you introduced a parameter of "city" the web service could alter the query depending on the value of the parameter. So the service could ask "what's the time - in London?", "what's the time - in New York?", depending on the value of the parameter.
  • The rule of thumb with parameters is that you should use as few of them as possible in order to ask the question/perform the alteration. You can always add more if required. Again, you should be thinking of small, simple services, each related to a specific task.
5. Checking input
  • There are two things you need to check your parameters for - existence and content.
  • For each parameter, you need to decide if it is compulsory or optional. Compulsory parameters are necessary for the web service to perform its function. For example, a service to book a train will need the train time in order to make the booking.
  • But you might make the "city" parameter of "what's the time?" optional - if it exists, return the time in that city - if not, just return the current time in the UK.
  • All parameters, compulsory or optional, need to be checked for content. Either the value will have to be in a limited range (i.e. if the parameter value isn't "Y" or "N" then it is an invalid value). Or it might need to be a type of value (i.e. a number, or a string). Even in the case of parameters which allow "free text" values, you will still have to check for "dangerous" characters. Web services (and all programs executable by the web server) are vulnerable to security attacks, and you will need to make sure that incoming parameters don't contain anything dodgy.
  • A good rule is to decide what values or kind of values you will allow in parameter values and build from there, rather than trying to disallow all the possibly dangerous characters (you may miss one). So a rule like "the value must be a mixture of letters, numbers, commas and whitespace" is better (or more secure) than "the value must not contain semicolons).
6. Building the query
  • Having gathered and checked parameters (if any) the web service now has to perform its function. To do this, it needs to talk to the dataset - and the usual language for doing this is SQL.
  • Web services which retrieve data will use SQL to ask the dataset a question - such as "What's the time in New York?"
  • Web services which alter data will use SQL to form an instruction. For instance "Book a seat on the 9.15 from Cambridge to London"
  • If your web services use parameters for input, these will (usually) be interpolated into the SQL. So, for the train booking example above, "9.15" would have been the value of the parameter "time", "Cambridge" the value of the parameter "from" and "London" the value of the parameter "to". Parameters are a means of altering the question or instruction which gets sent to the dataset
7. Returning the response
  • All web services should send a response back to whoever made the request.
  • For web services which retrieve data, this will be the answer to the question - i.e. for question "What is the time in New York" the response might be "The time in New York is 10.30".
  • For web services which alter data, the response will tell you what the web service has done. So for the instruction "Book me a seat on the 9.15 from Cambridge to London" the response might be "Seat booked" or even the more verbose "Seat no. XX booked on the 9.15 from Cambridge to London".
  • The response should be tailored to how it's going to be used. Sometimes, you'll just want to know if the request was processed ok, sometimes you'll need much more detailed information.
  • Your web services should always send a response, even if the request fails. A response of "your request has failed" is far more useful than nothing at all!
8. Chaining web services together
  • A common way of using web services is to chain them together - which means using the response from one web service as part of the input for the next.
  • Taking the (very simplified) example of booking a seat on the next train, the chain might go something like this:
  • Request to "what's the time?" returns value TIME
  • Request to "what's the next train?" with parameter TIME returns next train after time as value TRAIN
  • Request to "book seat" with parameter TRAIN returns value SEAT BOOKED

No comments:

Post a Comment