How to parse JSON from https website using Ada - rest

I am trying to make a simple parser for an https website push, so trying to follow from the example from http://rosettacode.org/wiki/HTTP#Ada, just changing the address from a website.
So I tried
with Ada.Text_IO; use Ada.Text_IO;
with AWS.Client;
with AWS.Response;
procedure Main_Other is
begin
Put_Line (AWS.Response.Message_Body
(AWS.Client.Get
(URL => "https://google.com")));
end Main_Other;
But I got an exception
raised PROGRAM_ERROR : aws-client.adb:398 finalize/adjust raised exception
[2020-04-02 10:41:20] process exited with status 1, elapsed time: 00.80s
So, any thoughts on how to fix that?
I'd like to parse the current status of some tables in a website, similar of making something like that in Python
import pandas as pd
def retrieve_json(json_url):
return pd.read_json(json_url)
I'd like to code this solution the simplest way possible, even better not relying on AWS.
Please, and thanks.

It seems that you're using a build of AWS with SSL support disabled (SSL support is optional). Replacing https with http should do the trick. If an unsecured connection is not an option, either recompile AWS with SSL support enabled (see here and here) or, if you're in a hurry and happen to develop on Linux, fall back on GNAT.Expect and wget (tested with GNAT CE 2019):
main.adb
with Ada.Text_IO; use Ada.Text_IO;
with GNAT.Expect; use GNAT.Expect;
with GNATCOLL.JSON; use GNATCOLL.JSON;
procedure Main is
-------------------
-- Download_JSON --
-------------------
function Download_JSON (URL : String) return JSON_Value is
Cmd : constant String := "wget";
Arg_1 : aliased String := "-q"; -- Turn off Wget's own messages.
Arg_2 : aliased String := "-O"; -- Output response to ...
Arg_3 : aliased String := "-"; -- ... standard output.
Arg_4 : aliased String := URL;
Status : aliased Integer;
Response : String :=
Get_Command_Output
(Command => Cmd,
Arguments => (1 => Arg_1'Unchecked_Access,
2 => Arg_2'Unchecked_Access,
3 => Arg_3'Unchecked_Access,
4 => Arg_4'Unchecked_Access),
Input => "",
Status => Status'Unchecked_Access);
begin
-- Omitting check of 'Status' for brevity.
return Read (Response);
end;
Root : JSON_Value;
begin
Root := Download_JSON
("https://raw.githubusercontent.com/AdaCore/gnatcoll-core/" &
"master/testsuite/tests/json/validation/basic_object.json");
Put_Line (Write (Root));
end Main;
default.gpr
with "gnatcoll.gpr";
project Default is
for Source_Dirs use ("src");
for Object_Dir use "obj";
for Main use ("main.adb");
end Default;
output
$ ./main
{"a":1,"b":"a tringg","c":[1,2,3],"d":{"a":"a"},"e":null}

Related

Consuming rest API using PL/SQL - Body not recognized

I am new to this forum and consuming Rest API's using PL/SQL. I am trying to consume a rest service from pl/sql, but the server is not able to identify the request. The same request works from postman.. so no problem in the service, something with my pl/sql code i think..
I am trying the free api provided by rapidapi.
https://rapidapi.com/weatherapi/api/weatherapi-com
My Stored Procedure
Create Or Replace Procedure TEST_REST_API
(
PURL IN VARCHAR2
)
is
req utl_http.req;
res utl_http.resp;
url varchar2(4000) := PURL;
buffer varchar2(32767);
content varchar2(8000);
begin
dbms_output.put_line('START');
UTL_TCP.close_all_connections;
DBMS_OUTPUT.put_line('2');
UTL_HTTP.set_wallet('file:/u01/app/oracle/product/11.2.0/db_1/wallet/rapidapi','wallet123');
DBMS_OUTPUT.put_line('3');
UTL_HTTP.CLEAR_COOKIES();
content := '{"q":"autp:ip"}';
--content := '';
dbms_output.put_line('content '||content);
req := utl_http.begin_request(url, 'GET',' HTTP/1.1');
utl_http.set_header(req, 'X-RapidAPI-Key', 'af1e7931bamsh3ac102afa8fef68p100423jsn8d4d3cc1325b');
utl_http.set_header(req, 'X-RapidAPI-Host', 'weatherapi-com.p.rapidapi.com');
utl_http.set_header(req, 'Content-Length', length(content));
utl_http.set_header(req, 'User-Agent', 'mozilla/4.0');
--utl_http.set_header(req, 'user-agent', 'PostmanRuntime/7.29.2');
utl_http.set_header(req, 'Content-Type', 'application/json');
utl_http.set_header(req, 'Connection','keep-alive');
--utl_http.set_header(req, 'Accept','*/*');
--utl_http.write_text(req, content);
utl_http.write_text(req, content);
--utl_http.write_text(req,'');
--insert into wstemp values (req);
res := utl_http.get_response(req);
-- process the response from the HTTP call
begin
loop
utl_http.read_line(res, buffer,TRUE);
dbms_output.put_line(buffer);
end loop;
dbms_output.put_line('Response XML:'|| cast(x_clob as varchar2));
utl_http.end_response(res);
exception
when utl_http.end_of_body
then
utl_http.end_response(res);
end;
end;
The execution script
BEGIN
TEST_REST_API
(
'https://weatherapi-com.p.rapidapi.com/ip.json'
);
END;
/
The response from server
{"error":{"code":1003,"message":"Parameter q is missing."}}
Any help would be highly appreciated.
If you're posting data then you need to use POST not GET:
req := utl_http.begin_request(url, 'POST', 'HTTP/1.1');
You also seem to have a typo in your content, with autp instead of auto:
content := '{"q":"auto:ip"}';
However, the API you're using only seems to support GET, so you can't send body content - that only applies when posting data. You will need to revert the method to GET, remove content from your test procedure, and either append the request parameter in the procedure:
req := utl_http.begin_request(url || '?q=auto:ip', 'GET',' HTTP/1.1');
or modify the URL being passed in, or add another parameter with the query parameter to append. You may need to add quotes, and might also need to escape some entities.

SSL3_GET_RECORD Error Using Delphi XE5 RestClient

First time trying to connect to a server's HTTP API Interface using RESTClient/1.0 library installed with Delphi XE5. RestRequest.Execute raises an EIdOSSLUnderlyingCryptoError Exception:
error:1408F10B:SSL routines: SSL3_GET_RECORD:wrong version number.
Only components used are RestClient, RestRequest, and RestResponse.
from the .dfm file:
object RESTClient1: TRESTClient
Accept = 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'
BaseURL = 'https://intakeq.com/api/v1'
ContentType = 'ctAPPLICATION_JSON'
Params = <>
HandleRedirects = True
Left = 117
Top = 256
end
object RESTRequest: TRESTRequest
Client = RESTClient1
Params = <>
Response = RESTResponse1
Left = 185
Top = 258
end
from the .pas file
RestRequest.Params.Clear;
RestClient1.BaseURL := sBaseUrl + 'practitioners';
RestRequest.Method := TRESTRequestMethod.rmGET;
RestRequest.Params.AddItem;
RestRequest.Params[0].Kind := TRESTRequestParameterKind.pkHTTPHEADER;
RestRequest.Params[0].name := 'X-Auth-Key';
RestRequest.Params[0].Value := 'xxxxxyyyyyzzzzz';
When I put the same information into the Embarcadero REST Debugger it connected without an error.
Is there an updated REST Client Library that would work with XE5, and if so, where would I find it?
I don't see anything in the TRestClient or TRestResponse components that indicates what the SSL or TLS version is. Is that something that I need to install separately?

Within a gimp python-fu plug-in can one create/invoke a modal dialog (and/or register a procedure that is ONLY to be added as a temp procedure?)

I am trying to add a procedure to pop-up a modal dialog inside a plug-in.
Its purpose is to query a response at designated steps within the control-flow of the plug-in (not just acquire parameters at its start).
I have tried using gtk - I get a dialog but it is asynchronous - the plugin continues execution. It needs to operate as a synchronous function.
I have tried registering a plugin in order to take advantage of the gimpfu start-up dialogue for same. By itself, it works; it shows up in the procedural db when queried. But I never seem to be able to actually invoke it from within another plug-in - its either an execution error or wrong number of arguments no matter how many permutations I try.
[Reason behind all of this nonsense: I have written a lot of extension Python scripts for PaintShopPro. I have written a App package (with App.Do, App.Constants, Environment and the like that lets me begin to port those scripts to GIMP -- yes it is perverse, and yes sometimes the code just has to be rewritten, but for a lot of what I actual use in the PSP.API it is sufficient.
However, debugging and writing the module rhymes with witch. So. I am trying to add emulation of psp's "SetExecutionMode" (ie interactive). If
set, the intended behavior is that the App.Do() method will "pause" after/before it runs the applicable psp emulation code by popping up a simple message dialog.]
A simple modal dialogue within a gimp python-fu plug-in can be implemented via gtk's Dialog interface, specifically gtk.MessageDialog.
A generic dialog can be created via
queryDialogue = gtk.MessageDialog(None, gtk.DIALOG_DESTROY_WITH_PARENT \
gtk.MESSAGE_QUESTION, \
gtk.BUTTONS_OK_CANCEL, "")
Once the dialog has been shown,
a synchronous response may be obtained from it
queryDialogue.show()
response = queryDialogue.run()
queryDialogue.hide()
The above assumes that the dialog is not created and thence destroyed after each use.
In the use case (mentioned in the question) of a modal dialog to manage single stepping through a pspScript in gimp via an App emulator package, the dialogue message contents need to be customized for each use. [Hence, the "" for the message argument in the Constructor. [more below]]
In addition, the emulator must be able to accept a [cancel] response to 'get out of Dodge' - ie quit the entire plug-in (gracefully). I could not find a gimpfu interface for the latter, (and do not want to kill the app entirely via gimp.exit()). Hence, this is accomplished by raising a custom Exception class [appTerminate] within the App pkg and catching the exception in the outer-most scope of the plugin. When caught, then, the plug-in returns (exits).[App.Do() can not return a value to indicate continue/exit/etc, because the pspScripts are to be included verbatim.]
The following is an abbreviated skeleton of the solution -
a plug-in incorporating (in part) a pspScript
the App.py pkg supplying the environment and App.Do() to support the pspScript
a Map.py pkg supporting how pspScripts use dot-notation for parameters
App.py demonstrates creation, customization and use of a modal dialog - App.doContinue() displays the dialogue illustrating how it can be customized on each use.
App._parse() parses the pspScript (excerpt showing how it determines to start/stop single-step via the dialogue)
App._exec() implements the pspScript commands (excerpt showing how it creates the dialogue, identifies the message widget for later customization, and starts/stops its use)
# App.py (abbreviated)
#
import gimp
import gtk
import Map # see https://stackoverflow.com/questions/2352181/how-to- use-a-dot-to-access-members-of-dictionary
from Map import *
pdb = gimp.pdb
isDialogueAvailable = False
queryDialogue = None
queryMessage = None
Environment = Map({'executionMode' : 1 })
_AutoActionMode = Map({'Match' : 0})
_ExecutionMode = Map({'Default' : 0}, Silent=1, Interactive=2)
Constants = Map({'AutoActionMode' : _AutoActionMode}, ExecutionMode=_ExecutionMode ) # etc...
class appTerminate(Exception): pass
def Do(eNvironment, procedureName, options = {}):
global appTerminate
img = gimp.image_list()[0]
lyr = pdb.gimp_image_get_active_layer(img)
parsed = _parse(img, lyr, procedureName, options)
if eNvironment.executionMode == Constants.ExecutionMode.Interactive:
resp = doContinue(procedureName, parsed.detail)
if resp == -5: # OK
print procedureName # log to stdout
if parsed.valid:
if parsed.isvalid:
_exec(img, lyr, procedureName, options, parsed, eNvironment)
else:
print "invalid args"
else:
print "invalid procedure"
elif resp == -6: # CANCEL
raise appTerminate, "script cancelled"
pass # terminate plugin
else:
print procedureName + " skipped"
pass # skip execution, continue
else:
_exec(img, lyr, procedureName, options, parsed, eNvironment)
return
def doContinue(procedureName, details):
global queryMessage, querySkip, queryDialogue
# - customize the dialog -
if details == "":
msg = "About to execute procedure \n "+procedureName+ "\n\nContinue?"
else:
msg = "About to execute procedure \n "+procedureName+ "\n\nDetails - \n" + details +"\n\nContinue?"
queryMessage.set_text(msg)
queryDialogue.show()
resp = queryDialogue.run() # get modal response
queryDialogue.hide()
return resp
def _parse(img, lyr, procedureName, options):
# validate and interpret App.Do options' semantics vz gimp
if procedureName == "Selection":
isValid=True
# ...
# parsed = Map({'valid' : True}, isvalid=True, start=Start, width=Width, height=Height, channelOP=ChannelOP ...
# /Selection
# ...
elif procedureName == "SetExecutionMode":
generalOptions = options['GeneralSettings']
newMode = generalOptions['ExecutionMode']
if newMode == Constants.ExecutionMode.Interactive:
msg = "set mode interactive/single-step"
else:
msg = "set mode silent/run"
parsed = Map({'valid' : True}, isvalid=True, detail=msg, mode=newMode)
# /SetExecutionMode
else:
parsed = Map({'valid' : False})
return parsed
def _exec(img, lyr, procedureName, options, o, eNvironment):
global isDialogueAvailable, queryMessage, queryDialogue
#
try:
# -------------------------------------------------------------------------------------------------------------------
if procedureName == "Selection":
# pdb.gimp_rect_select(img, o.start[0], o.start[1], o.width, o.height, o.channelOP, ...
# /Selection
# ...
elif procedureName == "SetExecutionMode":
generalOptions = options['GeneralSettings']
eNvironment.executionMode = generalOptions['ExecutionMode']
if eNvironment.executionMode == Constants.ExecutionMode.Interactive:
if isDialogueAvailable:
queryDialogue.destroy() # then clean-up and refresh
isDialogueAvailable = True
queryDialogue = gtk.MessageDialog(None, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_QUESTION, gtk.BUTTONS_OK_CANCEL, "")
queryDialogue.set_title("psp/APP.Do Emulator")
queryDialogue.set_size_request(450, 180)
aqdContent = queryDialogue.children()[0]
aqdHeader = aqdContent.children()[0]
aqdMsgBox = aqdHeader.children()[1]
aqdMessage = aqdMsgBox.children()[0]
queryMessage = aqdMessage
else:
if isDialogueAvailable:
queryDialogue.destroy()
isDialogueAvailable = False
# /SetExecutionMode
else: # should not get here (should have been screened by parse)
raise AssertionError, "unimplemented PSP procedure: " + procedureName
except:
raise AssertionError, "App.Do("+procedureName+") generated an exception:\n" + sys.exc_info()
return
A skeleton of the plug-in itself. This illustrates incorporating a pspScript which includes a request for single-step/interactive execution mode, and thus the dialogues. It catches the terminate exception raised via the dialogue, and then terminates.
def generateWebImageSet(dasImage, dasLayer, title, mode):
try:
img = dasImage.duplicate()
# ...
bkg = img.layers[-1]
frameWidth = 52
start = bkg.offsets
end = (start[0]+bkg.width, start[1]+frameWidth)
# pspScript: (snippet included verbatim)
# SetExecutionMode / begin interactive single-step through pspScript
App.Do( Environment, 'SetExecutionMode', {
'GeneralSettings': {
'ExecutionMode': App.Constants.ExecutionMode.Interactive
}
})
# Selection
App.Do( Environment, 'Selection', {
'General' : {
'Mode' : 'Replace',
'Antialias' : False,
'Feather' : 0
},
'Start': start,
'End': end
})
# Promote
App.Do( Environment, 'SelectPromote' )
# und_so_weiter ...
except App.appTerminate:
raise AssertionError, "script cancelled"
# /generateWebImageSet
# _generateFloatingCanvasSetWeb.register -----------------------------------------
#
def generateFloatingCanvasSetWeb(dasImage, dasLayer, title):
mode="FCSW"
generateWebImageSet(dasImage, dasLayer, title, mode)
register(
"generateFloatingCanvasSetWeb",
"Generate Floating- Frame GW Canvas Image Set for Web Page",
"Generate Floating- Frame GW Canvas Image Set for Web Page",
"C G",
"C G",
"2019",
"<Image>/Image/Generate Web Imagesets/Floating-Frame Gallery-Wrapped Canvas Imageset...",
"*",
[
( PF_STRING, "title", "title", "")
],
[],
generateFloatingCanvasSetWeb)
main()
I realize that this may seem like a lot of work just to be able to include some pspScripts in a gimp plug-in, and to be able to single-step through the emulation. But we are talking about maybe 10K lines of scripts (and multiple scripts).
However, if any of this helps anyone else with dialogues inside plug-ins, etc., so much the better.

Invoke a REST service from PL/SQL

I am trying to make a HTTP Request from PL/Sql. I need to use access token for authentication rather than username and password. Please suggest the standard API or code to use to pass the access token.
Code:
DECLARE
obj json;
val_ json_value;
el_val BOOLEAN;
req utl_http.req;
res utl_http.resp;
url VARCHAR2(4000) := 'http://acdl-act-
dev.azurewebsites.net/apiconn/push';
name VARCHAR2(4000);
buffer CLOB;
l_chunk VARCHAR2(32000);
content CLOB := '{ "User_Name":"John","City":"Delhi", "Operation":"I"';
BEGIN
req := utl_http.begin_request( url, 'POST', ' HTTP/1.1');
utl_http.set_header( req, 'user-agent', 'mozilla/4.0');
utl_http.set_header( req,'content-type', 'application/x-www-form-urlencoded' );
utl_http.set_header( req,'Content-Length', length(content));
-- utl_http.set_authentication(r => req, username => p_user_name, password => p_pwd,scheme => 'Basic',for_proxy => false);
-- Need to use access token for authentication ex: 'adghjcjhdnmfbhjd367dsbasfkjhkdfsf38789734bcff'
utl_http.write_text(req, content);
res := utl_http.get_response(req);
-- process the response from the HTTPS call
BEGIN
LOOP
utl_http.read_line(res, buffer);
END LOOP;
utl_http.end_response(res);
EXCEPTION
WHEN utl_http.end_of_body THEN
utl_http.end_response(res);
END;
END ws_call_code;
/
I know this old, but incase someone is looking for the same information. I just needed to access a REST webservice using an OAuth token and I just needed to set a header with my token, utl_http.set_header(l_http_request, 'Authorization', l_token).
Reading Oracle documentation'
https://docs.oracle.com/database/121/ARPLS/u_http.htm#ARPLS71082
The procedure UTL_HTTP.SET_AUTHENTICATION has the following usage note
*
The supported authentication schemes are HTTP basic and Amazon S3
authentication.
*

Procedure PL/SQL to call a web service rest

I have to call in a PL/SQL procedure this web service rest.
I did this script to call this web service rest and download the table :
{
DECLARE
l_param_list VARCHAR2(512);
l_http_request UTL_HTTP.req;
l_http_response UTL_HTTP.resp;
l_response_text VARCHAR2(32767);
BEGIN
-- service's input parameters
l_param_list:=:xxx;
--l_param_list := FND_PROFILE.VALUE('XXCC_LINK_BANCA_ITALIA_CAMBIO');
DBMS_OUTPUT.put_line('link:'||l_param_list);
-- preparing Request...
l_http_request := UTL_HTTP.begin_request (l_param_list
, 'POST'
, 'HTTP/1.1');
-- ...set header's attributes
UTL_HTTP.set_header(l_http_request, 'Content-Type', 'application/x-www-form-urlencoded');
UTL_HTTP.set_header(l_http_request, 'Content-Length', LENGTH(l_param_list));
-- ...set input parameters
UTL_HTTP.write_text(l_http_request,l_param_list);
-- get Response and obtain received value
l_http_response := UTL_HTTP.get_response(l_http_request);
UTL_HTTP.read_text(l_http_response, l_response_text);
DBMS_OUTPUT.put_line(l_response_text);
-- finalizing
UTL_HTTP.end_response(l_http_response);
EXCEPTION
WHEN UTL_HTTP.end_of_body
THEN UTL_HTTP.end_response(l_http_response);
END;}
How can I declare the parameters of this service as initDay, initMonth or refCur?
POST parameters are passed in as part of the body (ie the write_text() call).. see How are parameters sent in an HTTP POST request? for the general procedure