Calling REST API from Progress Client

Posted by anandknr on 03-Sep-2019 11:44

I am exploring the possible options of accesssing a REST API via OpenEdge ChUI client. My progress version is 11.7.4 and after going through progress tutorials I opted to use OpenEdge Http client (OpenEdge.Net.pl). 

 

USING OpenEdge.Net.HTTP.IHttpRequest.
USING OpenEdge.Net.HTTP.IHttpResponse.
USING OpenEdge.Net.HTTP.ClientBuilder.
USING OpenEdge.Net.HTTP.RequestBuilder. 

DEFINE VARIABLE oRequest  AS IHttpRequest NO-UNDO.
DEFINE VARIABLE oResponse AS IHttpResponse NO-UNDO.

oRequest = RequestBuilder:Get('www.progress.com/'):Request. 

oResponse = ClientBuilder:Build():Client:Execute(oRequest).

MESSAGE
    oResponse:StatusCode SKIP   
    oResponse:StatusReason SKIP
    VIEW-AS ALERT-BOX.

But I am getting below error if I execute from Procedure Editor.  

Secure Socket Layer (SSL) failure. error code -3829:  SSL routines (9318)
Connection failure for host www.progress.com port 443 transport TCP. (9407)

response-data-received.txt created was blank.

Then  instead (of https://www.progress.com/) I used another API (http://api.worldbank.org/countries?format=json) which will return a json data. (Through broswer I have confirmed it.) But through OE Client it gave oResponse:StatusCode as 403 and oResponse:StatusMessage as "Forbidden".

This time response-data-received.txt was created with below content.

HTTP/1.1 403 Forbidden
Server: squid/3.5.20
Mime-Version: 1.0
Date: Tue, 03 Sep 2019 11:38:22 GMT
Content-Type: text/html;charset=utf-8
Content-Length: 3655
X-Squid-Error: ERR_ACCESS_DENIED 0
Vary: Accept-Language
Content-Language: en
X-Cache: MISS from cppra00a0288.erferf.com
X-Cache-Lookup: NONE from cppra00a0288.erferf.com:0
Via: 1.1 cppra00a0288.erferf.com (squid/3.5.20)
Connection: keep-alive

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "www.w3.org/.../strict.dtd">
<html><head>
<meta type="copyright" content="Copyright (C) 1996-2016 The Squid Software Foundation and contributors">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>ERROR: The requested URL could not be retrieved</title>
<style type="text/css"><!--
 /*
 * Copyright (C) 1996-2016 The Squid Software Foundation and contributors
 *
 * Squid software is distributed under GPLv2+ license and includes
 * contributions from numerous individuals and organizations.
 * Please see the COPYING and CONTRIBUTORS files for details.
 */

/*
 Stylesheet for Squid Error pages
 Adapted from design by Free CSS Templates
 www.freecsstemplates.org
 Released for free under a Creative Commons Attribution 2.5 License
*/

/* Page basics */
* {
	font-family: verdana, sans-serif;
}

html body {
	margin: 0;
	padding: 0;
	background: #efefef;
	font-size: 12px;
	color: #1e1e1e;
}

/* Page displayed title area */
#titles {
	margin-left: 15px;
	padding: 10px;
	padding-left: 100px;
	background: url('/squid-internal-static/icons/SN.png') no-repeat left;
}

/* initial title */
#titles h1 {
	color: #000000;
}
#titles h2 {
	color: #000000;
}

/* special event: FTP success page titles */
#titles ftpsuccess {
	background-color:#00ff00;
	width:100%;
}

/* Page displayed body content area */
#content {
	padding: 10px;
	background: #ffffff;
}

/* General text */
p {
}

/* error brief description */
#error p {
}

/* some data which may have caused the problem */
#data {
}

/* the error message received from the system or other software */
#sysmsg {
}

pre {
    font-family:sans-serif;
}

/* special event: FTP / Gopher directory listing */
#dirmsg {
    font-family: courier;
    color: black;
    font-size: 10pt;
}
#dirlisting {
    margin-left: 2%;
    margin-right: 2%;
}
#dirlisting tr.entry td.icon,td.filename,td.size,td.date {
    border-bottom: groove;
}
#dirlisting td.size {
    width: 50px;
    text-align: right;
    padding-right: 5px;
}

/* horizontal lines */
hr {
	margin: 0;
}

/* page displayed footer area */
#footer {
	font-size: 9px;
	padding-left: 10px;
}


body
:lang(fa) { direction: rtl; font-size: 100%; font-family: Tahoma, Roya, sans-serif; float: right; }
:lang(he) { direction: rtl; }
 --></style>
</head><body id=ERR_ACCESS_DENIED>
<div id="titles">
<h1>ERROR</h1>
<h2>The requested URL could not be retrieved</h2>
</div>
<hr>

<div id="content">
<p>The following error was encountered while trying to retrieve the URL: <a href="api.worldbank.org/countries

<blockquote id="error">
<p><b>Access Denied.</b></p>
</blockquote>

<p>Access control configuration prevents your request from being allowed at this time. Please contact your service provider if you feel this is incorrect.</p>

<p>Your cache administrator is <a href="mailto:root?subject=CacheErrorInfo%20-%20ERR_ACCESS_DENIED&amp;body=CacheHost%3A%20cppra00a0288.erferf.com%0D%0AErrPage%3A%20ERR_ACCESS_DENIED%0D%0AErr%3A%20%5Bnone%5D%0D%0ATimeStamp%3A%20Tue,%2003%20Sep%202019%2011%3A38%3A22%20GMT%0D%0A%0D%0AClientIP%3A%2010.86.128.240%0D%0A%0D%0AHTTP%20Request%3A%0D%0AGET%20%2Fcountries%3Fformat%3Djson%20HTTP%2F1.1%0AUser-Agent%3A%20OpenEdge-HttpClient%2F0.4.0%20(WIN32%2F64)%20OpenEdge%2F11.7.0.0.1388%20Lib-ABLSockets%2F0.4.0%0D%0AAccept%3A%20*%2F*%0D%0AHost%3A%20api.worldbank.org%0D%0A%0D%0A%0D%0A">root</a>.</p>
<br>
</div>

<hr>
<div id="footer">
<p>Generated Tue, 03 Sep 2019 11:38:22 GMT by cppra00a0288.erferf.com (squid/3.5.20)</p>
<!-- ERR_ACCESS_DENIED -->
</div>
</body></html>


Can someone help me to identify the issue here? Is it because calling a http data from SSL client?

All Replies

Posted by Torben on 03-Sep-2019 12:12

Running on OE 12.0 I get:

Error(s):

Lead attributes in a chained-attribute expression (a:b:c) must be type HANDLE or a user-defined type and valid (not UNKNOWN). (10068)

Unable to parse malformed URI: www.progress.com/

Changing line to:

oRequest = RequestBuilder:Get('https://www.progress.com/'):Request.


Gives: 200 OK

Posted by pwokke on 03-Sep-2019 12:32

When you start with SSL you need to exchange and load the proper certificates in the client environment.

Other question: on the server are you using an PASOE instance or a Classic AppServer?

Posted by Peter Judge on 03-Sep-2019 13:24

As Peter notes, you have to load all of the TLS/SSL certificates into the OE cert store, using the certutil command.  Make sure that you have all of them (the whole chain) , including the root CA. It's not enough to have them on the OS - they must be in the OE-version-specific certstore.

I use my browser to get the certs (most browsers have the ability to download/export them).

Posted by Peter Judge on 03-Sep-2019 13:29

The "unable to parse malformed URI" error is because there's no schema on the URI (ie no 'http' or 'https').

Posted by anandknr on 03-Sep-2019 14:14

Thanks Torben. This seems a formatting issue in site. When I copied it was just like what you mentionied here. Mostly the formatting stepped over this. My program looks exactly like your quoted piece of code.

Posted by Torben on 03-Sep-2019 14:54

After importing certificates I get the following code to give desired result.

Think they are behind load balancer, so you need the ServerNameIndicator

BLOCK-LEVEL ON ERROR UNDO, THROW.
USING OpenEdge.Core.*.
USING OpenEdge.Net.HTTP.ClientBuilder.
USING OpenEdge.Net.HTTP.IHttpRequest.
USING OpenEdge.Net.HTTP.IHttpResponse.
USING OpenEdge.Net.HTTP.RequestBuilder.
USING OpenEdge.Net.HTTP.Lib.ClientLibraryBuilder.

DEFINE VARIABLE jOut AS Progress.Json.ObjectModel.JsonArray NO-UNDO.

FUNCTION InvokeworldBank RETURNS Progress.Json.ObjectModel.JsonArray ():
   DEFINE VARIABLE oHttpRequest   AS IHttpRequest  NO-UNDO.
   DEFINE VARIABLE oHttpResponse  AS IHttpResponse NO-UNDO.
   DEFINE VARIABLE oUri    AS OpenEdge.Net.URI           NO-UNDO.
   DEFINE VARIABLE oLib AS OpenEdge.Net.HTTP.IHttpClientLibrary NO-UNDO.
   // Set server to call
   oUri = (NEW OpenEdge.Net.URI('https', 'api.worldbank.org')).
   oUri:Path = '/countries'.
   oUri:addQuery("format", "json":U).
   // Set ssl properties
   oLib = OpenEdge.Net.HTTP.Lib.ClientLibraryBuilder:Build()
//       :SslVerifyHost(FALSE)
       :ServerNameIndicator('api.worldbank.org')
       :library.
   oHttpRequest = OpenEdge.Net.HTTP.RequestBuilder:Get(oUri):Request.
   // Call and get response
   oHttpResponse = ClientBuilder:Build()
      :UsingLibrary(oLib)
      :Client:Execute(oHttpRequest).
   MESSAGE
      oHttpResponse:StatusCode SKIP
      oHttpResponse:StatusReason
      VIEW-AS ALERT-BOX INFORMATION.
   IF TYPE-OF(oHttpResponse:Entity, Progress.Json.ObjectModel.JsonArray) THEN RETURN CAST(oHttpResponse:Entity, Progress.Json.ObjectModel.JsonArray).
   UNDO, THROW NEW Progress.Lang.AppError("Wrong response type", 0).
END FUNCTION.

// Call worldBank with input parameters
jOut = InvokeworldBank().
// Message 200 first chars of result
MESSAGE STRING(SUBSTRING(jOut:GetJsonText(), 1, 200)) VIEW-AS ALERT-BOX INFORMATION.

[{"page":1,"pages":7,"per_page":"50","total":304},[{"id":"ABW","iso2Code":"AW","name":"Aruba","region":{"id":"LCN","value":"Latin America & Caribbean "},"adminregion":{"id":"","value":""},"incomeLevel

Posted by anandknr on 03-Sep-2019 15:07

Hi Peter,

Is this certificate specific to a particular API url? I am confused beacuse in my browser(chrome) I can see only one entry under certificates. When I try to export that one, the options "Export with Private Key" & "Include all certificates in certification path" are disabled and unselected. So I am not sure if this is a show-stopper for me !!. Still I was able to export certificate file.

I tried to add the above certificate into my OE developer studio but client still gave the same "Forbidden" error.

Ideally when we consume a REST API, should we need to request & get for a certificate from them?

Posted by anandknr on 03-Sep-2019 15:10

I am currently executing it from developer studio and also tried it with PASOE instance. I don't have AppServer in my application.  

Posted by anandknr on 03-Sep-2019 15:38

Hi Torben,

Could you help me to understand the steps to import those licences? <sorry if that was a very basic queston>

Also, when I used your code block in my OE studio it is not able to find "ServerNameIndicator" and causing syntax error. Probably that would be a newly introduced method in 12.0. (Mine is 11.7)

Posted by Anil Kumar on 03-Sep-2019 17:38

Hi Anandknr,
 
>> Could you help me to understand the steps to import those licences?
I guess you were referring to importing certificates. Following are steps to import the cert file into OpenEdge environment. We import these certificates using certutil utility
 
For any OpenEdge client (ABL) to talk to any of the external domains which is configured with SSL (HTTPS), then we need to load those certificates into OpenEdge via certutl -import. This operation needs to be performed via proenv. Once we import those certificates into OpenEdge, then OpenEdge creates an alias name for specific certificate and is kept inside $DLC/certs directory. Whenever an ABL client tries to interact with specific domain then ABL client will look for the availability of specific certificate in the $DLC/certs directory.
 
proenv>certutil -import <path_to_certification_followed_by_cert_name.crt>
 
In your example, we need to import complete certificate chain of ‘api.worldbank.org’
Once you have the .crt file downloaded from ‘api.worldbank.org’ then load those certs using proenv as below:
 
 
This would then generate a new .crt file in your OpenEdge installation directory ($DLC/cert) with name ‘d6325660.0’
 
At this point, we have successfully imported respective certificates into OpenEdge environment. Now, try running the ABL program from PDS OE and it should result in following output.
 
---------------------------
Information (Press HELP to view stack trace)
---------------------------
200
OK
---------------------------
OK   Help  
---------------------------
 
---------------------------
Information (Press HELP to view stack trace)
---------------------------
[{"page":1,"pages":7,"per_page":"50","total":304},[{"id":"ABW","iso2Code":"AW","name":"Aruba","region":{"id":"LCN","value":"Latin America & Caribbean "},"adminregion":{"id":"","value":""},"incomeLevel
---------------------------
OK   Help  
---------------------------
 
Regarding your issue with the ServerNameIndicator attribute, can you check if you can see that in the Class Browser? In Developer Studio click on ‘Ctrl+F12’ and it should open Class Browser which will list all classes and its attributes as below:
 
Thanks and Regards,
Anil Kumar
 

Posted by anandknr on 03-Sep-2019 19:00

Hi Anil Kumar,

Thanks for the step by step detailed explanation. I tried to create an .crt file from chrome but strangely it had an extension of .cer instead. When I tried to install that file using proenv, it gave an error that "The file C:\xx\xx\\worldBank.cer does not contain a Digital Certificate". I guess, I need to retry it in Mozilla. I will update you soon how it goes.

Posted by pwokke on 04-Sep-2019 06:27

On certutil you can add the -format DER to import binary formatted certificates.

Posted by Torben on 04-Sep-2019 08:08

You need 11.7.3 or later for SNI support.

knowledgebase.progress.com/.../

This thread is closed