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?
Related
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.
I try to deploy the Azure function by using Rest API and zip-archive of solution.
It works properly in Postman.
I've found advice on how to upload mp3 files and develop a solution for my task.
But when I try to create a payload for request by AL-code for Business Central (file have been uploaded to instr):
CR := 13;
LF := 10;
NewLine += '' + CR + LF;
httpHeader.Clear();
TempBlob.CreateOutStream(PayloadOutStream);
PayloadOutStream.WriteText('--boundary' + NewLine);
PayloadOutStream.WriteText(StrSubstNo('Content-Disposition: form-data; name="file"; filename="%1"', filename) + NewLine);
PayloadOutStream.WriteText('Content-Type: application/zip' + NewLine);
PayloadOutStream.WriteText(NewLine);
CopyStream(PayloadOutStream, InStr);
PayloadOutStream.WriteText(NewLine);
PayloadOutStream.WriteText('--boundary');
PayloadOutStream.WriteText(NewLine);
TempBlob.CreateInStream(PayloadInStream);
Content.WriteFrom(PayloadInStream);
Content.GetHeaders(httpHeader);
if httpHeader.Contains('Content-Type') then httpHeader.Remove('Content-Type');
httpHeader.Add('Content-Type', 'multipart/form-data;boundary=boundary');
httpRequest := CreateHttpRequestMessage(Content, 'Post', RequestURI);
Client.Clear();
Client.DefaultRequestHeaders.Add('Authorization', StrSubstNo('Bearer %1', token));
if Client.Send(httpRequest, httpResponse) then begin
httpResponse.Content().ReadAs(responseText);
Message(responseText);
end
else
Error(RequestErrorMsg);
I received an error in the response message from the deployment process like this:
{"Message":"An error has occurred.","ExceptionMessage":"Number of entries expected in End Of Central Directory does not correspond to number of entries in Central Directory.","ExceptionType":"System.IO.InvalidDataException","StackTrace":" at System.IO.Compression.ZipArchive.ReadCentralDirectory()\r\n at System.IO.Compression.ZipArchive.get_Entries()\r\n at Kudu.Core.Infrastructure.ZipArchiveExtensions.Extract(ZipArchive archive, String directoryName, ITracer tracer, Boolean doNotPreserveFileTime) in C:\\Kudu Files\\Private\\src\\master\\Kudu.Core\\Infrastructure\\ZipArchiveExtensions.cs:line 114\r\n at Kudu.Services.Deployment.PushDeploymentController.<>c__DisplayClass21_0.<LocalZipFetch>b__1() in C:\\Kudu Files\\Private\\src\\master\\Kudu.Services\\Deployment\\PushDeploymentController.cs:line 746\r\n at System.Threading.Tasks.Task.InnerInvoke()\r\n at System.Threading.Tasks.Task.Execute()......
I believe, something is wrong when I build the payload. Could you give me advice on how I have to build the body of request for my case?
So I tried sending an email using the luasocket smtp function with ssl but for some reason I get this error /usr/local/share/lua/5.1/socket/smtp.lua:80: attempt to call field 'b64' (a nil value) I have all the libraries downloaded and I don't know why it doesn't work.
This is my code
local smtp = require("socket.smtp")
local ssl = require('ssl')
local https = require 'ssl.https'
local mime = require("mime")
function sslCreate()
local sock = socket.tcp()
return setmetatable({
connect = function(_, host, port)
local r, e = sock:connect(host, port)
if not r then return r, e end
sock = ssl.wrap(sock, {mode='client', protocol='tlsv1'})
return sock:dohandshake()
end
}, {
__index = function(t,n)
return function(_, ...)
return sock[n](sock, ...)
end
end
})
end
local k, e = smtp.send{
from = "[REDACTED]",
rcpt = self.params.email,
user = "[REDACTED]",
password = "[REDACTED]",
port = 465,
server = "smtp.gmail.com",
source = smtp.message(message),
create = sslCreate
}
if not k then
print(e)
end
The code on line 80 calls mime.b64() function, with mime being the result of require "mime" call (where mime module comes from the luasocket library). Unless there is something wrong with the mime module itself (and if it came from the correct source and was properly installed, there shouldn't be), it's most likely caused by mime.lua file available somewhere in package.path, so it gets loaded instead of the actual module.
If you want to troubleshoot it further, just review the result of require "mime" in the debugger or use package.searchpath("mime", package.path) to see what is being picked up (searchpath); you may also need to try it with package.cpath.
I have used Network.Wai.Middleware.Cors's simpleCors, it worked properly for GET requests, but when I try to make a POST request I get the following problem
OPTIONS /users
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Status: 400 Bad Request 0.032443s
The only way I was able to make it work was by removing the simpleCors from the following part in Application.hs
-- | Convert our foundation to a WAI Application by calling #toWaiAppPlain# and
-- applying some additional middlewares.
makeApplication :: App -> IO Application
makeApplication foundation = do
logWare <- makeLogWare foundation
-- Create the WAI application and apply middlewares
appPlain <- toWaiAppPlain foundation
return $ logWare $ defaultMiddlewaresNoLogging $ simpleCors $ appPlain
and adding a OPTIONS method response
optionsNewUserR :: Handler RepPlain
optionsNewUserR = do
return $ RepPlain $ toContent ("" :: Text)
and adding CORS headers... But it is a dirty solution, because I would need to change ALL my API handlers! Any help is highly appreciated!
I believe the issue is that simpleCors is built off simpleCorsResourcePolicy, which only covers simpleMethods, which doesn't cover OPTIONS.
You can fix this issue by using the same methods to roll whatever middleware you need.
Here's the one I use for the OPTIONS problem you've described:
{-# LANGUAGE OverloadedStrings #-}
module Middlewares where
import Network.Wai (Middleware)
import Network.Wai.Middleware.AddHeaders (addHeaders)
import Network.Wai.Middleware.Cors (CorsResourcePolicy(..), cors)
-- | #x-csrf-token# allowance.
-- The following header will be set: #Access-Control-Allow-Headers: x-csrf-token#.
allowCsrf :: Middleware
allowCsrf = addHeaders [("Access-Control-Allow-Headers", "x-csrf-token,authorization")]
-- | CORS middleware configured with 'appCorsResourcePolicy'.
corsified :: Middleware
corsified = cors (const $ Just appCorsResourcePolicy)
-- | Cors resource policy to be used with 'corsified' middleware.
--
-- This policy will set the following:
--
-- * RequestHeaders: #Content-Type#
-- * MethodsAllowed: #OPTIONS, GET, PUT, POST#
appCorsResourcePolicy :: CorsResourcePolicy
appCorsResourcePolicy = CorsResourcePolicy {
corsOrigins = Nothing
, corsMethods = ["OPTIONS", "GET", "PUT", "POST"]
, corsRequestHeaders = ["Authorization", "Content-Type"]
, corsExposedHeaders = Nothing
, corsMaxAge = Nothing
, corsVaryOrigin = False
, corsRequireOrigin = False
, corsIgnoreFailures = False
}
And then just compose the middlewares you need like you're already doing:
run port $ logger . allowCsrf . corsified $ app cfg
Simplifying the answer of Mario we can use simplePolicy
import Network.Wai.Middleware.Cors
allowCors :: Middleware
allowCors = cors (const $ Just appCorsResourcePolicy)
appCorsResourcePolicy :: CorsResourcePolicy
appCorsResourcePolicy =
simpleCorsResourcePolicy
{ corsMethods = ["OPTIONS", "GET", "PUT", "POST"]
, corsRequestHeaders = ["Authorization", "Content-Type"]
}
And to use it:
main = scotty 8080 $ do
middleware allowCors
matchAny "/" $ text "Success"
I am attempting to access the betfair API using Matlab and the urlread2 function available here.
EDIT: I have posted this problem on Freelancer if anyone can help with it: tinyurl.../pa7sblb
The documentation for the betfair API I am following is this getting started guide. I have successfully logged in and kept the session open using these codes: (I am getting a success response)
%% Login and get Token
url = 'https://identitysso.betfair.com/api/login';
params = {'username' '******' 'password' '******'};
header1 = http_createHeader('X-Application','*****');
header2 = http_createHeader('Accept','application/json');
header = [header1, header2];
[paramString] = http_paramsToString(params)
[login,extras] = urlread2(url,'POST',paramString,header)
login = loadjson(login)
token = login.token
%% Keep Alive
disp('Keep Session Alive')
url_alive = 'https://identitysso.betfair.com/api/keepAlive';
header1 = http_createHeader('X-Application','******');
header2 = http_createHeader('Accept','application/json');
header3 = http_createHeader('X-Authentication',token');
header_alive = [header1, header2, header3];
[keep_alive,extras] = urlread2(url_alive,'POST',[],header_alive);
keep_alive = loadjson(keep_alive);
keep_alive_status = keep_alive.status
My trouble starts when I am attempting to do the next step and load all available markets. I am trying to replicate this example code which is designed for Python
import requests
import json
endpoint = "https://api.betfair.com/exchange/betting/rest/v1.0/"
header = { 'X-Application' : 'APP_KEY_HERE', 'X-Authentication' : 'SESSION_TOKEN_HERE' ,'content-type' : 'application/json' }
json_req='{"filter":{ }}'
url = endpoint + "listEventTypes/"
response = requests.post(url, data=json_req, headers=header)
The code I am using for Matlab is below.
%% Get Markets
url = 'https://api.betfair.com/exchange/betting/rest/v1.0/listEventTypes/';
header_application = http_createHeader('X-Application','******');
header_authentication = http_createHeader('X-Authentication',token');
header_content = http_createHeader('content_type','application/json');
header_list = [header_application, header_authentication, header_content];
json_body = savejson('','filter: {}');
[list,extras] = urlread2(url_list,'POST',json_body,header_list)
I am having trouble with a http response code 415. I believe that the server cannot understand my parameter since the headings I have used with success previously.
Any help or advice would be greatly appreciated!
This is the error:
Response stream is undefined
below is a Java Error dump (truncated):
Error using urlread2 (line 217)
Java exception occurred:
java.io.IOException: Server returned HTTP response code: 415 for URL....
I looked at your problem and it seems to be caused by two things:
1) The content type should be expressed as 'content-type' and not 'content_type'
2) The savejson-function doesn't create an adequate json-string. If you use the json-request from the Python-script it works.
This code work for me:
%% Get Markets
url = 'https://api.betfair.com/exchange/betting/rest/v1.0/listEventTypes/';
header_application = http_createHeader('X-Application','*********');
header_authentication = http_createHeader('X-Authentication',token');
header_content = http_createHeader('content-type','application/json');
header_list = [header_application, header_authentication, header_content];
json_body = '{"filter":{ }}';
[list,extras] = urlread2(url,'POST',json_body,header_list)