Access HTTP content over the Web
The Client Tools have broad support for accessing HTTP content using the wwHTTP class. Downloading content off the Web and posting data to a Web site is quite easy and flexible with this class and only takes a few lines of code usually.
Web content includes anything that is accessible over the Web via the HTTP protocol. Content can be HTML text, plain text, JSON or XML data, binary conent like Zip files, images or PDFs. You can easily use any HTTP Verb like GET, POST, PUT, DELETE etc., access secure content and automatically handle authentication, redirect and GZip compression/decompression.
The simplest requests are GET operations to retrieve content only. The following example captures some HTML text from a Web Server URL:
oHTTP=CREATEOBJECT("wwHTTP") lcHTML = oHTTP.Get("https://west-wind.com") *** Show HTML generated in Browser ShowHTML( lcHTML ) && in wwUtils.prg
The raw result from the request is returned via the return value (or a result file via the
llDownloadFile parameter ), but you can also retrieve the HTTP Response Header or HTTP Result Status Code:
lcHTML = oHTTP.Get("https://markdownmonser.west-wind.com") *** Get HTTP Response Code ? oHttp.cResultCode && 200, 500, 401, 404, 401.1 etc. *** Get full Http Response Header (multiple lines) ? oHttp.cHttpHeaders
To post data to a server you generally use either
.Put(). Semantically POST is used for adding, PUT for updating, but for most Web backends this distinction is not significant and you can use the two interchangeably. POST tends to be more common.
To post data to a server using HTML Form style form submissions with urlencoded Key/Value pairs (
application/x-www-form-urlencoded content), you can use the
.AddPostKey() method. Use that method to add key and value pairs to POST to the server. You can also add HttpHeaders by using
.AppendHeader() to add any standard or custom HTTP headers to your request.
.Put()) to make the request:
oHTTP=CREATEOBJECT("wwHTTP") *** Add POST form variables (url encoded by default) oHTTP.AddPostKey("FirstName","Rick") oHTTP.AddPostKey("LastName","Strahl") oHTTP.AddPostKey("Company","West Wind Technologies") *** Optionally add custom headers oHTTP.AppendHeader("cache-control","private") oHttp.AppendHeader("Custom-Header","Custom value") lcHTML = oHTTP.Post("https://west-wind.com/wconnect/TestPage.wwd") ShowHTML( lcHTML )
This formats the HTTP POST buffer for sending the variables to the Web server which simulates an HTML Web form submission which is quite common.
The above example posts using Html Form type POST data that is provided in key value pairs. wwHttp supports 2 form data post modes via the
- 1 -
application/x-www-form-urlencoded- html form based encoding
- 2 -
multi-part/form-data- used for file uploads and forms with binary data
For raw data posts that provide a full buffer of data as-is rather than the key/value pairs shown above, you can can use the
cContentType property to specify the content type, then POST the raw data as a single string.
The following is sufficient for sending JSON content to the server:
loHttp.cContentType = "application/json" loHttp.Post(lcUrl, lcJson)
cContentType- but don't use both! Use
nHttpPostModefor form submissions with
cContentTypeto send raw buffers with
AddPostKey(lcData)or directly in
A common scenario is to post JSON or XML to a server for some sort of Service access. In this case you'll need to use the
PUT HTTP operation and set the
cContentType to the appropriate content type like
text/xml for example.
To send XML data to a server you can use the following code:
loHttp = CREATEOBJECT("wwHttp") *** Specify that we want to post raw data and a custom content type loHttp.cContentType = "text/xml" && Content type of the data posted *** Explicitly specify HTTP verb optionall * loHttp.cHttpVerb = "POST" && (PUT/DELETE/HEAD/OPTIONS) *** Load up the XML data any way you need lcXML = FILETOSTR("XmlData.xml") lcXmlResult = loHttp.Post("http://www.west-wind.com/SomeXmlService.xsvc", lcXml) IF (loHttp.nError # 0) RETURN ENDIF ShowXml(lcXmlResult)
If you've been using
wwHttp for a while you might note that this syntax of using
.Post() is new as is the
lcData parameter. The old syntax that uses
.AddPostKey(lcData) also still works:
with the same behavior as the example above. The new
.Post() syntax is just simpler and more common for HTTP requests.
REST services are the latest rage, and when using REST you typically deal with JSON data instead of XML. The client tools include a wwJsonSerializer class that can handle serialization and deserialization for you.
DO wwHttp DO wwJsonSerializer loHttp = CREATEOBJECT("wwHttp") loHttp.cContentType = "application/json; charset=utf-8" lcJsonResult = loHttp.Post(lcUrl, STRCONV(lcJsonIn,9)) loResultObject = loSer.DeserializeJson(lcJsonResult) *** Do something with the result object ? loResultObject.status ? loResultObject.Data.SummaryValue
To make things even easier with JSON REST Services take a look at the JsonServiceClient class which handles all the HTTP calls and serialization and error handling all via single
The following sends JSON data to a service and receives a JSON result back as a FoxPro object:
loProxy = CREATEOBJECT("wwJsonServiceClient") lcUrl = "http://albumviewer.west-wind.com/api/album" lvData = loAlbum && FoxPro object lcVerb = "PUT" && HTTP Verb *** Make the service call and returns an Album object loAlbum2 = loProxy.CallService(lcUrl, lvData, lcVerb) IF (loProxy.lError) ? loProxy.cErrorMsg RETURN ENDIF ? loAlbum2.Title ? loAlbum2.Artist.ArtistName
You can also send binary data, which in FoxPro is just represented as a string. Make sure you set the
.cContentType property to specify what you are sending to the server:
loHttp = CREATEOBJECT("wwHttp") *** Specify that we want to post raw data with a custom content type loHttp.cContentType = "application/pdf" lcPdf = FILETOSTR("Invoice.pdf") loHttp.AddPostKey(lcPdf) && Add as raw string *** Send to server and retrieve result lcHtml = loHttp.Post("http://www.west-wind.com/SomeUril.xsvc")
Note that you can use the cContentType property to specify the content type of the data POSTed to the server.
You can also stream the content of a URL directly to a file. To do this you can use additional parameters on the
.Delete() methods which take an
lcOutputFilename parameter to allow streaming the HTTP data into. This allows for large files to be downloaded without tying up memory as they normally would.
loHttp = CREATEOBJECT('wwhttp') loHttp.Get("http://www.west-wind.com/","c:\test.htm") IF loHttp.nError # 0 wait window loHttp.cErrorMsg return ENDIF *** Browse the file from local disk GoUrl("c:\test.htm")
Streaming to file allows you to bypass large memory usage as
wwHTTP directly streams into the file with small chunks read from the server. This allows files much larger than 16mb to be downloaded.
wwHttp also includes an OnHttpBufferUpdate event wich provides you download progress information via an event handler on the wwHttp class. You can find out more on how this works and an example here:
Comment or report problem with topic