Class wwJsonServiceClient

This class makes it easy to call JSON REST services with Visual FoxPro. The class manages JSON serialization and HTTP calls in a simple single method interface.

You can use the class directly using CallMethod() method to call a service directly, or - better - create a subclass and build a dedicated service class for multiple calls.

For a more detailed look please check out the following blog post:

You can use this class to:

  • Directly call JSON REST services
  • Subclass it and implement service methods that map a service

Directly call a JSON REST Service

The direct approach just uses the CallService() method directly.

A simple HTTP GET data retrieval could look like this:

loProxy = CREATEOBJECT("wwJsonServiceClient")

lcUrl = ""
loArtists = loProxy.CallService(lcUrl)

IF (loProxy.lError OR ISNULL(loArtists))
   ? loProxy.cErrorMsg

*** Service returns an array which is turned into a FoxPro collection
? loArtists.Count  && Collection 
FOREACH(loArtist in loArtists)
   ? loArtist.ArtistName
   ? loArtist.Description
   ? loArtist.ImageUrl
   ? "---"

Sending Data to the Server

You can also pass data to the service. JSON REST endpoints that expect data typically expect a single JSON parameter - which can be an object with many sub properties - to represent input values. To call the service with an object parameter for example, simply provide a FoxPro object that maps the structure of the JSON expected by the service. wwJsonServiceClient automatically serializes the FoxPro object/value into JSON for you.

To send data to the server, simply pass the lvData parameter in CallService() with a FoxPro value or object and specify the HTTP verb to be used (typically POST or PUT):

loProxy = CREATEOBJECT("wwJsonServiceClient")

lcUrl = ""
lvData = loAlbum && FoxPro object with Album Data
lcVerb = "PUT"   && HTTP Verb

*** Update the Album with the loAlbum data we're sending
loAlbum = loProxy.CallService(lcUrl,lvData,lcVerb)

IF (loProxy.lError)
   ? loProxy.cErrorMsg

*** Use the updated result album
? loAlbum.Title
? loAlbum.Description

Customizing the HTTP Request

The Service client class has an .oHttp property that handles the HTTP request and is loaded on initialization. You can access this existing instance, or create a new one (using .CreatewwHttp(loNewHttp)) to customize the behavior of the HTTP request:

loProxy = CREATEOBJECT("wwJsonServiceClient")
loProxy.oHttp.AddHeader("x-custom","Custom Value")
loProxy.oHttp.nTimeout = 10

You can also override the CreatewwHttp() method in a subclass to provide re-usable common behavior for the oHttp instance.

Customizing the JSON Serializer

Likewise you can also use the .oSerializer property to customize serialization behavior.

loProxy = CREATEOBJECT("wwJsonServiceClient")
loProxy.oSerializer.PropertyNameOverrides = "lastName,firstName,lastAccess"

You can override the CreateSerializer() method in a subclass to provide re-usable common behavior for the oSerializer property.

Creating a Service Proxy Class

If you are calling a service that has many methods it's recommended that you create a separate class for all the service calls, similar to a service 'business object' that isolates all logic related to the service in a class. This does several things:

  • Single logical location for all Service related code
  • Consistent interface for calling service methods
  • Easy reuse for service calls throughout application

To use, subclass wwJsonServiceClient and implement your service methods that then using CallService() to call JSON service endpoints. The idea is that each service method you implement completely abstracts the service logic so the calling code simply calls a method with a parameter and a result value - all the service logic is handled internally to the service wrapper class.

Here's what a class looks like calling a couple of service methods:

DEFINE CLASS CustomerServiceClient as wwJsonServiceClient

cServiceBaseUrl = "http://localhost:23332/localizationService.ashx?method="

FUNCTION GetResourceSets()
    LOCAL loResult
    loResult = this.CallService(this.cServiceBaseUrl + "GetResourceSets")

    IF (this.lError)
       RETURN .NULL.
    RETURN loResult

FUNCTION UpdateResource(loResource)
    LOCAL loResult
    *** Service returns update resource
    loResult = this.CallService(this.cServiceBaseUrl + "UpdateResource",loResource,"PUT")
    IF (this.lError)
    RETURN loResult


To use this you would then just use:

loProxy = CREATEOBJECT("CustomerServiceClient")

loResources = loProxy.GetResources()
if ISNULL(loResources)
   ? loProxy.cErrorMsg

? loResources.Count
? loResources.Item(0).Locale
? loResources.Item(0).Text

loResource = GetMyResourceToUpdateFromSomewhere()
loResource = loProxy.UpdateResource(loResource)

if !llResult
   ? loProxy.cErrorMsg

? loResource.ResourceId
? loResource.Locale
? loResource.Text

This latter approach is preferrable as it treats service access like a business object where all logic created around the service is created in one place. It allows you to reuse the service calls and isolate your error handling and future maintenance all in one place.


Class Members



Adds an HTTP header to the current .oHttp instance.

This method is a shortcut for .oHttp.AddHeader() to make the functionality easier to discover.

o.AddHeader(lcHeader, lcValue)




Allows for overriding of the wwJsonSerializer instance that is loaded on Init() by this class in subclasses to provide custom serializer functionality. .oSerializer is always available, but you can customize this method to specify the create a customized instance of a serializer that can be used instead.





An error message if an error occurs and .lError is .T.



Flag that is set if either the HTTP request or JSON Serialization failed. If .T. the .cErrorMsg is also set.


By default all JSON responses are decoded from UTF-8. If the response content is not UTF-8 encoded set this value to .T.

JSON output is almost always returned in UTF-8 format, so you should never have to set this flag. It's here for those rare exceptions.




DEFINE CLASS CustomerServiceClient as wwJsonServiceClient

*  GetCustomers
FUNCTION Customers(loParms)
LOCAL loCustomers

loCustomers = THIS.CallService(this.cServiceBaseUrl + "customers.csvc", loParms)

IF THIS.lError
   RETURN null

RETURN loCustomers
*   GetCustomers

*  UpdateCustomer
FUNCTION UpdateCustomer(loCustomer)

loCustomer = THIS.CallService(this.cServiceBaseUrl + "customer.csvc",loCustomer,"PUT")

IF THIS.lError
   RETURN null

RETURN loCustomer
*   UpdateCustomer



Assembly: wwJsonSerializer.prg • wwHttp.prg (dependency)

See also:

Class wwJsonServiceClient

© West Wind Technologies, 1996-2021 • Updated: 09/26/21
Comment or report problem with topic