Creating web services

Introduction

Creating a web service using a translator script in the From HTTPS component is very easy. You can import web service calls from the logs to use as test data, and edit the code on the fly to get the behaviour right.

This article presents some examples, with code for you to try out:

Web service link Description
Hello World Probably the simplest web service in the world! No authentication.
Get the current date and time This simple web service uses basic authentication and returns an XML response with the time.username = admin and password = password.
Patient demographics A more complex example that uses JSON and services multiple requests. username = admin and password = password.

Without authentication [top]

In general a web service takes in an HTTP request, processes it and sends a response.

Steps

  1. Take in an HTTP request using a From HTTPS channel component.
  2. Parse the request into a Lua table using net.http.parseRequest{}
  3. Process the parsed request.
  4. Optional: Take some action based on the processing.
  5. Send a response using net.http.respond{}.

Example

Try it now: Hello World, no authorization.

This web service is very simple! We just respond to an HTTP request by returning “Hello World” as XML. It’s implemented using a single channel set up with From HTTPS –> To Channel. We just take in an HTTP request, push the message to the queue, and return “Hello World” as XML.

To run the example

  1. Create a From HTTPS –> To Channel channel.
  2. Set the Source > Use Translator to “Translator”.
  3. Then set the “Source>URL path” to “hello”, and note the web link that is created:

    Note: The port number will be different from that used for Iguana.
  4. Copy the code snippet into the From HTTPS script.
  5. Use the URL from step 3 to access the web service.

Note: The key value entity_type=’text/xml’ tells the receiver that the response is XML, rather than the default HTML (to prevent browsers from showing a blank screen).

function main(Data)

  -- parse the request data
  local R = net.http.parseRequest{data=Data}

   -- add data processing here

   -- push the result to the queue
   queue.push{data=Data}

   -- vary response based on processing
   net.http.respond{
      entity_type='text/xml',
      body="<text>Hello World</text>", debug_result=true}
end

Using basic authentication [top]

In general a web service takes in an HTTP request, processes it and sends a response.

Steps

  1. Take in an HTTP request using a From HTTPS channel component.
  2. Parse the request into a Lua table using net.http.parseRequest{}.
  3. Authenticate the user and password:
    • If authentication fails use net.http.respond{} to send a 401 (or other error) and then return (taking no further action).
    • If authentication is successful continue to the next step.
  4. Process the parsed request.
  5. Optional: Take some action based on the processing.
  6. Send a response using net.http.respond{}.

Example

Try it now: Get the current date and time, username = admin and password = password.

This example of an authorized web service is as simple as we could make it! We just take in a request, using HTTP basic authentication, and then we return the current date and time. It’s implemented using a single channel set up with From HTTPS –> To Channel.

To run the example

  1. Create a From HTTPS –> To Channel channel.
  2. Set the Source > Use Translator to “Translator”.
  3. Then set the “Source>URL path” to “current_time”, and note the web link that is created.
    Note: The port number will be different from that used for Iguana.
  4. Load the project from this zip file Current_Date_and_Time_From_HTTPS.zip into the From HTTPS script.
  5. Use the URL from step 3 to access the web service.

How the example works

The raw HTTP request data comes into the main() function and we do the following:

  1. Use queue.push{data=Data} to log the incoming data.
    Note: This gives us a record of all requests. Also we can import test data from the logs into the Translator, so we can develop and test using real requests.
  2. Use net.http.parseRequest{data=Data} to parse the incoming HTTP request into a table object which gives us easy access to all the headers, cookies, post and get variables.
  3. We authenticate the user and password using the auth.BasicAuthentication() function.

Tip: If authentication fails the auth.BasicAuthentication() function sends an HTTP 401 error, and returns false (inspect the “auth” module code for details).

You can also find this module in our code repository.

Patient Demographics [top]

Patient Demographics is a more realistic example of building a web service with Iguana. Just load up the code and inspect it see how it works.

It uses these techniques:

  • Using error handling with pcall()
  • Maintaining a table of available calls
  • Returning JSON from the result set
  • It also serves up some simple documentation for the interface

Try it now: Patient demographics, username = admin and password = password.

To run the example

  1. Set up a channel with From HTTPS –> To Channel.
  2. Set the Source > Use Translator to “Translator”.
  3. Then set the “Source>URL path” to “demographic”, and note the web link that is created.
    Note: The port number will be different from that used for Iguana.
  4. Import this project file Patient_demographics_From_HTTPS.zip into the From HTTPS script.
  5. Create the tables using table.vmd that is included in the project.
  6. Use the URL from step 3 to access the web service.

Using Patient Demographics [top]

PersonAdd

This adds a new empty person record. It returns a GUID as an Id for the new record. After adding the record you must use PersonUpdate to set the demographic fields. http://example.interfaceware.com:6544/demographics?Method=PersonAdd username = admin and password = password

Note: This implementation has the potential to create many blank person records, if you run PersonAdd and forget to run PersonUpdate. You could modify PersonAdd to include demographic data, you could implement this by calling PersonUpdate from within PersonAdd.

PersonUpdate

This call requires an Id in the form of a GUID and allows one to set the data for an existing person record. To create a new person first get a new GUID using PersonAdd. Every parameter needs to present in the HTTP request, although they can be blank. Sex needs to use one of the following codes:

  • M = Male
  • F = Female
  • U = Unknown
  • O = Other

Here are some example calls: http://example.interfaceware.com:6544/demographics?Method=PersonUpdate&Id=7AA1FA52A9029411DD08DB9DFAFAFCF3&LastName=Smith&GivenName=Fred&Dob=19841112&Sex=M&MiddleInitial=T&Suffix=e&Prefix= http://example.interfaceware.com:6544/demographics?Method=PersonUpdate&Id=A3AAFA528E03EA6224B38196DC510879&LastName=Eliot&GivenName=Tim&Dob=19641112&Sex=M&MiddleInitial=S&Suffix=Mr&Prefix= The return from a successful call looks like this: { “Description”: “Person updated”, “Id”: “A3AAFA528E03EA6224B38196DC510879” }

PersonQuery

This method provides two mechanisms to search for a person record. We can search by Keyword: http://example.interfaceware.com:6544/demographics?Method=PersonQuery&Keyword=Eliot username = admin and password = password Or by Id: http://example.interfaceware.com:6544/demographics?Method=PersonQuery&Id=A3AAFA528E03EA6224B38196DC510879 username = admin and password = password

The Keyword may have spaces, if so we break it up and search for multiple words. The API does not provide the means to search for other fields like date of birth. The assumption is that since this is an interoperability API that the software using the API can search on those parameters. Good enough?

Tip: We did include a function FetchPersonByGivenName() in the demographics module, which you could use to add a search on the GivenName field.

List

The List call simply returns a JSON formatted list of the supported methods.

http://example.interfaceware.com:6544/demographics?Method=List

username = admin and password = password