using xdmp:eval in REST Service in Marklogic - rest

I am using the below REST service to insert the document(from DB Ingestion) into Rest DB which is configured for this service. I am using POST method and sending parameters in form-data.
URL: http://{hostname}:8010/v1/addDocument.
The issue is that the xml($DirectoryListing) picked from Ingestion DB is getting automatically serialized into text, so I am not getting the xml for insertion.
This is working fine when this code is directly ran on Qconsole, but from rest service call its not working.
ML Version I am using is 7.0-2.3​
Please help me on this.
let $PrefixURI := "/docs/"
let $Path := fn:concat('/processing/',$transId,'/validDocs/')
let $_ := xdmp:log(fn:concat("Path",$Path))
let $DirectoryListing as node() :=
xdmp:invoke-function(
function() {
xdmp:directory($Path)
} ,
<options xmlns="xdmp:eval">
<database>{xdmp:database("Ingestion")}</database>
</options>
)
let $logs :=
element docsUris {
for $FileEntry in $DirectoryListing
let $Filename := functx:substring-after-last(xdmp:node-uri($FileEntry),'/')
let $docUri := fn:concat($PrefixURI, $Filename)
let $_ := xdmp:log(fn:concat("uri",$docUri))
let $contents := $FileEntry
let $_ := xdmp:log(fn:concat("adding document",$contents))
return
(: Insert the document :)
(dls:document-insert-and-manage(
$docUri,
fn:false(),
$contents,
"created",
(xdmp:permission("dls-user", "read"),
xdmp:permission("dls-user", "update")),
"historic"),
xdmp:document-add-collections(
$docUri,
"latest"),
xdmp:document-remove-collections(
$docUri, "historic")
)

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.

Execute powershell command in running container via Docker API

I want to execute a powershell command in a docker container running on a windows host.
The specific command I want to execute is "powershell Get-PSDrive C | Select-Object Used,Free"
I have implemented this using the Docker API for python and it is simple like calling:
cmd = "powershell Get-PSDrive C | Select-Object Used,Free"
output = container.exec_run(cmd)
This works as intended, but I need to implement this in golang.
But somehow, it is not clear for me how to interact with the Docker API for golang. I looked into the API and was confused by the hijackedSession. How do I have to setup the calls for ContainerExecCreate, ContainerExecAttach and ContainerExecStart ?
I expect the golang script to deliver the same results like the python code does:
Used Free
---- ----
199181606912 307151622144
Which then can be parsed by me.
The HijackedResponse struct:
type HijackedResponse struct {
Conn net.Conn
Reader *bufio.Reader
}
You need to copy the response from the resp.Reader,here is my code:
package main
import (
"bytes"
"context"
"fmt"
"github.com/docker/docker/api/types"
"github.com/docker/docker/client"
"github.com/docker/docker/pkg/stdcopy"
"strings"
)
func readFromCommand() (string, error) {
cli, err := client.NewEnvClient()
if err != nil {
return "", err
}
ctx := context.Background()
config := types.ExecConfig{
Cmd: strings.Split("powershell Get-PSDrive C | Select-Object Used,Free", " "),
AttachStdout: true,
AttachStderr: true,
}
response, err := cli.ContainerExecCreate(ctx,
// container id
"cf59d65ab1", config)
if err != nil {
return "", err
}
execID := response.ID
resp, err := cli.ContainerExecAttach(ctx, execID, config)
if err != nil {
return "", err
}
defer resp.Close()
stdout := new(bytes.Buffer)
stderr := new(bytes.Buffer)
_, err = stdcopy.StdCopy(stdout, stderr, resp.Reader)
if err != nil {
return "", err
}
s := stdout.String()
fmt.Println(s)
i := stderr.String()
fmt.Println(i)
return s, nil
}
Do remember to change the container id.

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

MarkLogic: Committing multiple statements within a single transaction

I want to version a document, for which we are followed below approach to check-out and check-in the document in a single transaction.
(:--------------------------- XQuery Starts ---------------------------:)
xquery version "1.0-ml";
declare namespace html = "http://www.w3.org/1999/xhtml";
import module namespace dls = "http://marklogic.com/xdmp/dls" at "/MarkLogic/dls.xqy";
declare function local:ManageDocument($docUri)
{
let $query := fn:concat('
xquery version "1.0-ml";
declare namespace html = "http://www.w3.org/1999/xhtml";
import module namespace dls = "http://marklogic.com/xdmp/dls" at "/MarkLogic/dls.xqy";
declare variable $docUri as xs:string external;
dls:document-manage($docUri,fn:false(),fn:concat("First Version of ", $docUri))'
)
return xdmp:eval(
$query,
(xs:QName("docUri"), $docUri),
<options xmlns="xdmp:eval">
<prevent-deadlocks>true</prevent-deadlocks>
</options>
)
};
let $docUri := "/searchable/as-2018-1981_standard.pdf.xml"
let $isManaged := dls:document-is-managed($docUri)
let $manageDoc := if($isManaged) then() else local:ManageDocument($docUri)
let $chechoutStatus := dls:document-checkout-status($docUri)
let $checkOut := if($chechoutStatus and $isManaged) then (fn:error(xs:QName('Error'), "Already Editing")) else dls:document-checkout-update-checkin($docUri, element {"ROOT"} {"HELLO WORLD!"}, "document-checkout-update-checkin", fn:true())
return $manageDoc
(:--------------------------- XQuery Ends ---------------------------:)
However, it is throwing below exception:
[1.0-ml] XDMP-PREVENTDEADLOCKS: xdmp:eval("
xquery version "1.0-
ml";
declare ...", (fn:QName("","docUri"), "/searchable
/as-2018-1981_standard.pdf.xml"), <options xmlns="xdmp:eval"><prevent-
deadlocks>true</prevent-deadlocks></options>) -- Processing an update from an
update with different-transaction isolation could deadlock
To overcome this I modified the XQuery to solve our purpose:
(:--------------------------- New XQuery Starts ---------------------------:)
xquery version "1.0-ml";
declare namespace html = "http://www.w3.org/1999/xhtml";
import module namespace dls = "http://marklogic.com/xdmp/dls" at "/MarkLogic/dls.xqy";
declare function local:ManageDocument($docUri)
{
let $query := fn:concat('
xquery version "1.0-ml";
declare namespace html = "http://www.w3.org/1999/xhtml";
import module namespace dls = "http://marklogic.com/xdmp/dls" at "/MarkLogic/dls.xqy";
declare variable $docUri as xs:string external;
dls:document-manage($docUri,fn:false(),fn:concat("First Version of ", $docUri))'
)
return xdmp:eval(
$query,
(xs:QName("docUri"), $docUri),
<options xmlns="xdmp:eval">
<prevent-deadlocks>true</prevent-deadlocks>
</options>
)
};
declare function local:CheckouotDocument($docUri)
{
let $query := fn:concat('
xquery version "1.0-ml";
declare namespace html = "http://www.w3.org/1999/xhtml";
import module namespace dls = "http://marklogic.com/xdmp/dls" at "/MarkLogic/dls.xqy";
declare variable $docUri as xs:string external;
(: dls:document-checkout($docUri, fn:true(), "updating doc", 3600) :)
dls:document-checkout-update-checkin($docUri, element {"ROOT"} {"HELLO WORLD!"}, "document-checkout-update-checkin", fn:true())
')
return xdmp:eval(
$query,
(xs:QName("docUri"), $docUri),
<options xmlns="xdmp:eval">
<prevent-deadlocks>true</prevent-deadlocks>
</options>
)
};
let $docUri := "/searchable/as-2018-1981_standard.pdf.xml"
let $isManaged := dls:document-is-managed($docUri)
let $manageDoc := if($isManaged) then() else local:ManageDocument($docUri)
let $chechoutStatus := dls:document-checkout-status($docUri)
let $checkOut := if($chechoutStatus and $isManaged) then (fn:error(xs:QName('Error'), "Already Editing")) else local:CheckouotDocument($docUri)
return $manageDoc
(:--------------------------- New XQuery Ends ---------------------------:)
Above XQuery is working as expected, however, it would be great if anyone can help me in solving my purpose in more efficient and simplified manner.
You could simplify your code a bit by using xdmp:invoke-function() instead of constructing strings for xdmp:eval(), and avoid repeating the options by declaring a variable:
xquery version "1.0-ml";
declare namespace html = "http://www.w3.org/1999/xhtml";
import module namespace dls = "http://marklogic.com/xdmp/dls" at "/MarkLogic/dls.xqy";
declare variable $OPTIONS :=
<options xmlns="xdmp:eval">
<prevent-deadlocks>true</prevent-deadlocks>
</options>;
declare function local:ManageDocument($docUri)
{
xdmp:invoke-function(function() {
dls:document-manage($docUri, fn:false(), "First Version of "||$docUri)
}, $OPTIONS)
};
declare function local:CheckouotDocument($docUri)
{
xdmp:invoke-function(function() {
(: dls:document-checkout($docUri, fn:true(), "updating doc", 3600) :)
dls:document-checkout-update-checkin($docUri, element {"ROOT"} {"HELLO WORLD!"}, "document-checkout-update-checkin", fn:true())
}, $OPTIONS)
};
let $docUri := "/searchable/as-2018-1981_standard.pdf.xml"
let $isManaged := dls:document-is-managed($docUri)
let $manageDoc := if ($isManaged) then() else local:ManageDocument($docUri)
let $chechoutStatus := dls:document-checkout-status($docUri)
let $checkOut := if ($chechoutStatus and $isManaged) then (fn:error(xs:QName('Error'), "Already Editing")) else local:CheckouotDocument($docUri)
return $manageDoc

Sending mail on localhost smtp does not work

I am trying to send an email to the localhost stmp server. I am using fakesmtp program to receive email from localhost.
Look at following code snippet
package mail
import (
"encoding/base64"
"fmt"
"log"
"net/mail"
"net/smtp"
"strings"
)
func encodeRFC2047(String string) string {
// use mail's rfc2047 to encode any string
addr := mail.Address{String, ""}
return strings.Trim(addr.String(), " <>")
}
func Send() {
// Set up authentication information.
smtpServer := "127.0.0.1:2525"
auth := smtp.PlainAuth(
"",
"admin",
"admin",
smtpServer,
)
from := mail.Address{"example", "info#example.com"}
to := mail.Address{"customer", "customer#example.com"}
title := "Mail"
body := "This is an email confirmation."
header := make(map[string]string)
header["From"] = from.String()
header["To"] = to.String()
header["Subject"] = encodeRFC2047(title)
header["MIME-Version"] = "1.0"
header["Content-Type"] = "text/plain; charset=\"utf-8\""
header["Content-Transfer-Encoding"] = "base64"
message := ""
for k, v := range header {
message += fmt.Sprintf("%s: %s\r\n", k, v)
}
message += "\r\n" + base64.StdEncoding.EncodeToString([]byte(body))
// Connect to the server, authenticate, set the sender and recipient,
// and send the email all in one step.
err := smtp.SendMail(
smtpServer,
auth,
from.Address,
[]string{to.Address},
[]byte(message),
//[]byte("This is the email body."),
)
if err != nil {
log.Fatal(err)
}
}
When I executed the send function, I've got the error unencrypted connection. Why?
Most likely the server does not allow you to use plain-text authentication over an unencrypted connection, which is a sensible default for almost any MTA out there. Either change authentication info to e.g. digest, or enable SSL/TLS in you client code.
Remember to use tcpdump or wireshark to check what is actually transmitted.