Consuming rest API using PL/SQL - Body not recognized - rest

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.

Related

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?

How to parse JSON from https website using Ada

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}

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.
*

Delphi Seattle - Sending Post Request with custom body Responds bad Request 400

I would like to send a Post Request to a Rest Server of external Provider. I Have tried with Curl and everything works perfect. Here is the CURL Code:
curl -X POST -H 'PRODUCT-KEY: SUperL0ngAndSpecialSecretCode' -H 'Content-Type: application/json' -H 'Authorization: Basic CrytedWorksalsowellwithotherget' -i 'http://myserver:8080/rest.svc/v1.0/query' --data '{
"query":"SELECT Name from Address where name like '\''%me%'\''"
}'
In Curl Everything works fine.
I have tried for a bunch of hours to get this Code working in Delphi. At this time my code looks like this:
function GetSomeInformation: string;
var
lrestrequest: TRESTRequest;
lRestClient: TRESTClient;
lRestResponce: TRESTResponse;
begin
result := '';
lRestClient := TRESTClient.Create('http://myserver:8080/rest.svc/v1.0/query');
try
lrestrequest := TRESTRequest.Create(nil);
try
lRestResponce := TRESTResponse.Create(nil);
try
lrestrequest.Client := lRestClient;
lrestrequest.Response := lRestResponce;
lrestrequest.Method := rmPost;
lrestrequest.Params.AddItem('PRODUCT-KEY',
'SUperL0ngAndSpecialSecretCode',
TRESTRequestParameterKind.pkHTTPHEADER);
lrestrequest.Params.AddItem('Content-Type', 'application/json',
TRESTRequestParameterKind.pkHTTPHEADER);
lrestrequest.Params.AddItem('query',
ansitoutf8('SELECT Name from Address where Name like ' +
quotedstr('%me%')), TRESTRequestParameterKind.pkREQUESTBODY);
lrestrequest.Execute;
if not lRestResponce.Status.Success then
showmessage(lRestResponce.StatusText + ' ' +
inttostr(lRestResponce.StatusCode))
else
result := lRestResponce.Content;
finally
lRestResponce.Free;
end;
finally
lrestrequest.Free
end;
finally
lRestClient.Free;
end;
end;
I have no idea what to do next to get the Work done? Any ideas or ways I can Debug the problem better.
--Update
Okay I Used Wireshark to check if there are any differences between the Post commands, it look like Delphi ignores or broke my Header.
In the Wireshark snippet there is a Value Content-Type. It should be
Content-Type: application/json
But with Delphi I get
Content-Type: application%2Fjson, application/x-www-form-urlencoded
And I also miss the Procduct-Key Value.
Any Suggestions?
You have to specify the kind of request in Method property of TRESTRequest
lRESTRequest.Method := TRESTRequestMethod.rmPost
Delphi ships with code samples!
http://docwiki.embarcadero.com/CodeExamples/Tokyo/en/REST.RESTDemo_Sample
after some Research and some Wireshark I got my Work done at least here ist the way I throw the parameters into my Request.
function GetSomeInformation: string;
var
lrestrequest: TRESTRequest;
lRestClient: TRESTClient;
lRestResponce: TRESTResponse;
begin
result := '';
lRestClient := TRESTClient.Create('http://myserver:8080/rest.svc/v1.0/query');
try
lrestrequest := TRESTRequest.Create(nil);
try
lRestResponce := TRESTResponse.Create(nil);
try
lrestrequest.Client := lRestClient;
lrestrequest.Response := lRestResponce;
RESTRequest1.Params.Clear;
RESTRequest1.Method:=rmpost;
RESTResponse1.RootElement := '';
lparam := RESTRequest1.Params.AddItem;
lparam.name := 'PRODUCT-KEY';
lparam.Value := 'SpecialKeyButWithSomeTrickyCharsLike==';
lparam.ContentType := ctNone;
lparam.Kind := pkHTTPHEADER;
//This one is Important otherwise the '==' will get url encoded
lparam.Options := [poDoNotEncode];
lparam := RESTRequest1.Params.AddItem;
lparam.name := 'data';
lparam.Value := '{"query":"' + SelectString + '"}';
lparam.ContentType := ctAPPLICATION_JSON;
lparam.Kind := pkGETorPOST;
lrestrequest.Execute;
if not lRestResponce.Status.Success then
showmessage(lRestResponce.StatusText + ' ' +
inttostr(lRestResponce.StatusCode))
else
result := lRestResponce.Content;
finally
lRestResponce.Free;
end;
finally
lrestrequest.Free
end;
finally
lRestClient.Free;
end;
end;
Thanks for Supporting!
PJM

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