Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / PowerBuilder

RESTful Web Services: A Quick-Start How-to Guide - Part 1

4.43/5 (11 votes)
14 Oct 2011CPOL12 min read 39.4K  
Coding a client to retrieve data from a response-oriented RESTful service

Among PowerBuilder 12.5 .NET's new features comes the ability to use WCF to call RESTful web services. This article, the first in a two-part series, provides a PowerBuilder 12.5 .NET developer with the foundational knowledge and skills to rapidly get up and running building PowerBuilder RESTful Web Service clients. Along the way I'll share with you a few tips and workarounds.

Introduction

PowerBuilder 12.0 .NET provided the ability to call SOAP-based web services using Microsoft's .NET 3.5 WCF API. I encourage those of you not familiar with WCF and SOAP to view my PowerBuilder WCF primer and StockTrader reference application overview hosted on Sybase.com. You can get to all my free tutorials from http://yakovwerde.ulitzer.com/node/1551687. New with version 12.5, along with an upgrade to WCF 4.0, is the ability to call RESTful web services, an increasingly popular mechanism for accessing remote resources in SOA applications. In this article I'll help you gain some foundational understanding and definitions, then familiarize you with the mechanics of coding a client to retrieve data from a response-oriented RESTful service. In Part 2, I'll explore the three types of request-oriented operations.

What Are RESTful Web Services?

In a nutshell, RESTful services are "web natural" and lightweight. They leverage HTPP's native GET, PUT, POST & DELETE methods to invoke service methods at well-known URIs. Much has already been written and is freely available on the Internet about the nature and implementation of RESTful web services and how they compare to SOAP/WSDL services. Instead of rehashing what has already been thoroughly described, Listing 1 provides a couple of web references from which you can glean an understanding of the technology. If you need more information, a quick search on your favorite search engine will turn up more references. If you're really serious and would like a full-sized book, you can purchase Jon Flanders' RESTful .NET published by O'Reilly.

  1. A Guide to Designing and Building RESTful Web Services with WCF 3.5
  2. Learn REST: A Tutorial
Listing 1: Useful Web References

One pragmatic difference between WSDL / SOAP services and RESTful services from the client viewpoint is the amount of onus placed on the client developer. SOAP services are fully described in a WSDL document, including their service methods, input parameters and return types. A PowerBuilder developer has no responsibility other than to input the WSDL location into the wizard or project painter and click the generate proxy button. The project painter does the rest. SOAP calls are also method based. At runtime the developer instantiates a single proxy and invokes specific methods as necessary. With RESTful services, however, the developer has more responsibility in defining the interface. He has to get hold of either a schema (XSD) document or .NET assembly that fully describes the types in the returned XML or JSON, OR a sample result set with sufficiently varied data to help the proxy generator decipher the return structure. He also has to know enough about the structure of the return type so as to be able to review the wizard's work and make corrections as necessary (more about this later). Calls to a RESTful service are not method based - simply navigating to the service URI with correct parameters appended gets you a response. This means there is one proxy per service (method), hence more code objects to maintain.

What Is JSON?

Depending on how they are implemented, RESTful web services can return data in one of several standard formats. Among the possible formats are XML, CSV, RSS, ATOM and JSON. PowerBuilder 12.5 allows you to choose either XML or JSON for your transfer format. What is JSON? The upshot is that JSON is a JavaScript / AJAX browser friendly data transfer format. Because AJAX is a pervasive web technology, many services are only available in JSON flavor. Listing 2 provides some useful references from which you can get more background on JSON.

JSON presents no problem for PowerBuilder! At design time you can provide a sample data set in JSON or XML format to the project painter. The project painter will parse the sample data, JSON data and generate the .NET reference objects you'll need to work with your data. At runtime JSON-based data transfer is parsed and converted to .NET value objects. The good news is that as a PB programmer you will not have to write JSON; however, you will have to read it to understand how a result set is constructed.

  1. Quick overview of this JSON
  2. JSON, a formal definition
Listing 2: Useful JSON References

Viewing JSON

IE 9 does not have a native facility for viewing JSON data. You'll need to use a tool to view the output data. One such tool is http://www.jsonviewer.com/. Once on the page, input the full invocation URL and click the ‘Get JSON and Parse' button. Figure 1 shows what you might see.

Image 1

Figure 1: JSON Viewer

If you are using Fiddler to monitor HTTP traffic (http://www.fiddler2.com/fiddler2), install the JSON viewer.Figure 2 shows how you can view returned JSON objects in Fiddler.

Image 2

Figure 2: Fiddler with JSON Viewer

Getting Started with PowerBuilder RESTful clients

Sidebar Tip

PowerBuilder relies on tools from the .NET 4.0 SDK to generate many of the code artifacts your client application

will need. At the time of this writing 12.5 is in beta release version. The installer does not install the .NET 4.0 SDK. You will need to download and install the .NET 4.0 SDK from Microsoft. If the SDK is not installed on your system, you will get an error message when you attempt to generate a proxy.

For this tutorial I'm going to the use the free GeoNames service located at www.GeoNames.org. The GeoNames geographical database covers many countries and contains over eight million place names that are available for download free of charge. GeoNames provides a robust set of RESTful services via which you can access their database. Figure 3 shows a partial listing of available services. You can find the full list of available services at http://www.geonames.org/export/ws-overview.html. To explore GeoNames on your own, you'll want to create a free user account using the Login link on the upper right side of their home page. Having an account is important since you'll need to provide your username as a parameter to your service calls and access using the "demo" user name is extremely limited.

Image 3

Figure 3: Some GeoName Services

Getting Started

Here's a list of the information you'll need to have handy before entering inputs in the RESTful service project wizard:

  1. The name of PBL into which you want to save your project object (usually the same pbl containing the project object you use to generate you EXE).
  2. The name of PBL into which the project painter will generate the code for your proxy class (you may want a separate pbl just for proxies that you can batch refresh if need be).
  3. The web method type GET, POST, PUT or DELETE.
  4. A name for your proxy class. You will interact with this class in your code. I'd suggest using the P_ prefix as part of your name.
  5. A name for the NameSpace you want to put your proxy class in - you can leave it blank to use the default namespace.
  6. The URI for the service including any parameters needed for the call.
  7. The service's return data format: XML or JSON.
  8. A name for a generated assembly. This assembly will contain value objects used as parameters and/or return types. It will be added by the wizard to your target as a reference. This name will also become the namespace for the assembly.
  9. A source to help the painter determine the return data type. There are three options, choose one:
    • A schema document (XSD) that defines the structure of the returned dataset.
    • A preexisting assembly that formally defines the return type structure
    • A sample XML snippet or JSON object whose data is rich and robust enough that the tool can figure out the data types from its contents.

Sidebar Tip

As shown in Figure 4 you can cause the generator to include input parameters on the GetMessage( ) method by changing Service URL literal values to tokens. Identifiers inside {  } will become parameter names. If you leave the literal values in, the generator will emit a parameter-less method call.

Stepping though the Wizard

Creating a new proxy class is a two-step process. First, you run the wizard in order to generate the development time project object and reference assembly. Then you verify your inputs in the project painter and deploy the project object to generate your runtime code artifacts. Let me visually guide you through the process. For this example I'm going to do a GET on the GeoName findNearbyWikipedia service. Follow Figures 5 through 12 in sequence to overview the complete process.

Image 4

Figure 5: Wizard - Step 1

Image 5

Figure 6: Wizard - Step 2

Image 6

Figure 7: Wizard - Step 3

Image 7

Figure 8: Wizard - Step 4

Image 8

Figure 9: Wizard - Step 5

Image 9

Figure 10: Project Painter with generated project object

Image 10

Figure 11: Click the Generate Button on the Painter Toolbar

Image 11

Figure 12:  Generated Code objects

Sidebar Tip

The invocation method for a GET will always be named GetMessage( ). It is a good practice to include the service name as part of its corresponding proxy class name. This will make its intent clear.

Sidebar Tip

If you use a sample dataset (XML or JSON) to generate your reference assembly, it's important that you examine the emitted assembly to verify the data type of each property. Occasionally the Microsoft parser will misinterpret a property's type. You'll want to correct that before moving on. There is no intermediate source code for the reference assembly, so your only recourse is to supply values to the project object that will cause it to render the property correctly. For example, a supplied postalCode element with the value ‘07960' was generated as a UInt16 instead of the expected String type. Supplying the value ‘x7960' forced the type to be rendered as a String.

Generated Artifacts

Let's take a more in-depth look at the generated code artifacts. Figure 13 shows the three kinds of objects generated from a project object.

Image 12

Figure 13: Generated code artifacts

Project Object is a place to input your choices and a front end onto Microsoft and PowerBuilder code generation tools. You click the Generate Proxy button on the Project Object's PainterBar to kick off the code generation process

Proxy Class is the class you instantiate in your code and use to call the service. Don't modify the generated code. Any changes you make to this code object will be lost when you regenerate your proxy. To extend or modify this code, inherit from this class and write your changes in the descendant. You instantiate a proxy type object and call GetMessage( ) passing appropriate parameters to invoke the service. Figure 14, shows the contents of a typical Proxy class fronting a call to a GET method.

Image 13

Figure 14: Contents of a GET proxy object

Request and Response Assemblies contain value objects returned by a GET call or passed as parameters to DELETE, POST and PUT calls. The WCF infrastructure handles converting JSON & XML into value objects and vice versa. You are spared from dealing with low-level conversion issues. Usually there will be a wrapper object that may or may not have data properties. It's the equivalent of the root element in an XML document. The wrapper object will have an array of value objects. These are the repeating row-oriented XML structures. The value object will have some set of return specific data values. Figure 15 shows the contents of a typical Response Assembly.

Image 14

Figure 15: Contents of a typical Response Assembly

Scripting the Call

The runtime code algorithm follows these steps:

  1. Instantiate the proxy in the appropriate scope.
  2. Declare return value reference variables.
  3. Call the GetMessage( ) method passing applicable parameters and capture the return.
  4. Destroy the proxy or let it go out of scope.

Figure 16 shows the complete code for a GET service invocation. Of course in a "real-world" application you will do something more significant with the return values than display them in a messagebox.

Image 15

Figure 16: Complete code for a GET service invocation

Note that even in well-designed applications, things can go wrong that are outside the client developer's control. For example, at runtime a service can be down or totally unavailable at the known URI. Therefor even though exception handling is optional, it's a best practice to avoid runtime system errors by scripting service calls inside TRY CATCH blocks that include a robust handler for problematic conditions.

Sidebar Tip

Using a single line DataWindow expression to directly load a data buffer from a PowerScipt NVO array works great. However, directly assigning a .NET value object array to a DataWindow buffer using an expression throws a runtime error. As a result you have to take a more time and labor code intensive approach. You must either (a) iterate the .NET object array and call SetItem( ) for each value OR (b) assign the .NET value array to an equivalent intermediate PowerScript NVO type array and then assign it to a DataWindow.

Sidebar Tip

Unfortunately, Web Service DataWindow Objects are only SOAP compatible. They have not yet become RESTful aware. To use a DataWindow for data display, you'll need to declare an external data source DataWindow and manually populate its buffer from the RESTful WS call return.

Conclusion

RESTful services are becoming pervasive on the Web. The APIs of many popular services, such as Google are Yahoo, are available as RESTful services. PowerBuilder 12.5 .NET programmers now have the ability to integrate calls to RESTful services in their applications using standard tools and technologies.

Long Live PowerBuilder!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)