I'm trying to get the id generated when I make the post and use it in the future (maybe when testing the delete), but I'm not getting it.
My method that tests POST:
#Test
public void givenData_WhenPost_Then200() throws Exception {
String path = given()
.body("{\r\n"
+ " \"nome\":\"teste\",\r\n"
+ " \"valor\": 2.5\r\n"
+ "}")
.contentType(ContentType.JSON)
.when()
.post("/acessorios")
.then()
.log().all()
.assertThat()
.statusCode(200).extract().jsonPath().getString("nome");
System.out.println(path);
}
This code returns:
Failed to parse the JSON document.
And at last: is possible to use the id generate in others methods even its not global?
If you'd like to use id from response in other tests, you can create static field id in the test class and assign value of response.jsonPath.getString("id");
The first thing you need to do is to make sure response is actually in json format.
You can add accept header in your chain of methods like:
String path = given()
.body("{\r\n"
+ " \"nome\":\"teste\",\r\n"
+ " \"valor\": 2.5\r\n"
+ "}")
.contentType(ContentType.JSON)
.accept(ContentType.JSON)
.when()
.post("/acessorios")
.then()
.log().all()
.assertThat()
.statusCode(200).extract().jsonPath().getString("$.id");
(eXist 4.4, XQuery 3.1)
I offer the user the ability to download PDF documents which are dynamically created at the moment of request. The request has two parameters: the document name (ie doc=MS609-0002.pdf) and the document language version (ie lang=EN).
The function that outputs is in download.xql:
declare function download:download($node as node(), $model as map(*), $doc as xs:string, $lang as xs:string)
{
...
return response:stream-binary($pdf,"application/pdf", $filename)
}
It outputs a PDF fine in both a direct call in an IDE and if I call the function through an eXist HTML template, for example:
http://localhost:8081/exist/apps/deheresi/download?doc=MS609-0002.pdf&lang=EN
However, using HTML means opening another browser window.
Instead I'd like to request a REST GET from a button. I've looked at the eXist REST documentation and I can't get it to work.
According to the documentation, I should issue a GET structured as follows :
http://localhost:8081/exist/rest/db/deheresi/download.xql?doc=MS609-0002.pdf&lang=EN
But when make that request, I get :
HTTP ERROR 404
Problem accessing /exist/rest/db/deheresi/download.xql.
Reason: Document /db/deheresi/download.xql not found
This variation with /exist/rest/apps/: http://localhost:8081/exist/rest/apps/deheresi/download.xql?doc=MS609-0002.pdf&lang=EN
Returns the following message with a blank tree:
This XML file does not appear to have any style information associated with it. The document tree is shown below.
And this variation with /exist/db/apps/: http://localhost:8081/exist/db/apps/deheresi/download.xql?doc=MS609-0002.pdf&lang=EN
Returns:
XQueryServlet Error
Error found
Message: Cannot read source file
/Applications/eXist-db.app/Contents/Resources/eXist-db/webapp/db/apps/deheresi/download.xql
I've tested file permissions and there seems to be no problem. Although there may be a REST permission/configuration requirement that I am not aware of? Are there issues with REST on localhost?
EDIT: this is the full function that should process the REST request:
xquery version "3.1";
module namespace get="/db/apps/deheresi/modules/download”;
declare namespace templates="http://exist-db.org/xquery/templates";
declare namespace tei="http://www.tei-c.org/ns/1.0";
declare namespace xsl = "http://www.w3.org/1999/XSL/Transform";
import module namespace xslfo = "http://exist-db.org/xquery/xslfo";
import module namespace document="/db/apps/deheresi/modules/document" at "/db/apps/deheresi/modules/document.xql";
import module namespace document-view="/db/apps/deheresi/modules/document-view" at "/db/apps/deheresi/modules/document-view.xql";
import module namespace document-preprint="/db/apps/deheresi/modules/document-preprint" at "/db/apps/deheresi/modules/document-preprint.xql";
import module namespace document-print="/db/apps/deheresi/modules/document-print" at "/db/apps/deheresi/modules/document-print.xql";
import module namespace functx="http://www.functx.com" at "/db/apps/deheresi/modules/functx.xql";
import module namespace globalvar="/db/apps/deheresi/modules/globalvar" at "/db/apps/deheresi/modules/globalvar.xqm";
declare function download:download($doc as xs:string?, $lang as xs:string?)
{ (: parse $doc to get name of XML to transform, send back pdf with same name :)
let $docset := upper-case(substring-before($doc,"."))
let $filename := concat($docset,".pdf")
let $document := doc(concat($globalvar:URIdata,concat($docset,".xml")))
let $language := if (lower-case($lang) = "fr")
then lower-case($lang)
else "en"
let $filename := concat($docset,".pdf")
(: get XSLT stylesheet :)
let $fostylesheet := document-print:single-doc-fo-stylesheet($language)
(: get XEP FO config:)
let $config := util:expand(doc("/db/apps/deheresi/xep.xml")/*)
(: get xml for transformation in correct language :)
let $xml := document-preprint:single-doc-preprint($document, $language)
(: create FO xml :)
let $fo := util:expand(transform:transform($xml, $fostylesheet, ()))
(: render pdf :)
let $pdf := xslfo:render($fo, "application/pdf", (), $config)
return response:stream-binary($pdf,"application/pdf", $filename)
};
NB: I've put a bounty on this in hopes of receiving an response which walks through the REST input and output function with an example of getting a PDF that is spontaneously generated. This includes any configuration / permission issues that could affect a REST request.
Since you state the PDF is returned when you call this:
http://localhost:8081/exist/apps/deheresi/download?doc=MS609-0002.pdf&lang=EN
Perhaps, what you should be doing is handling that response. A simple example would be this in jQuery using FileSaver.js. (You can google FileSaver.js and download and include that in your pages with jQuery):
function preview_cover(path){
var pdffilename="cover.pdf";
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if (this.readyState == 4 && this.status == 200){
saveAs(this.response, pdffilename);
}}
xhr.open('GET', 'cover-formatter.xq?cover=' + path + '&page_width=' + page_width + '&page_height=' + page_height);
xhr.setRequestHeader('Authorization','Basic ' + sessinfo);
xhr.responseType = 'blob';
xhr.send();
}
The above example will download the PDF using modern browsers (Chrome, Firefox, Edge).
The code behind is this (I snipped all the other stuff away, just leaving the formatting part):
let $fo := if ($territory = 'WALES') then util:expand(transform:transform($doc, doc("/db/EIDO/data/edit/xsl/EIDOcoverbilingual.xsl"), $parameters))
else util:expand(transform:transform($doc, doc("/db/EIDO/data/edit/xsl/EIDOcover.xsl"), $parameters))
let $pdf := xslfo:render($fo, "application/pdf", (), $config)
let $headers := response:set-header("Content-Disposition", "attachment;filename=document.pdf")
return
response:stream-binary($pdf, "media-type:application/pdf","document.pdf")
Below is a more lengthy jQuery Javascript code that attempts to handle the response at the Javascript side. There are a few tricks to note that I will mention first so as to understand. One hack is that iOS or IE9 browsers cannot handle binary downloads in the browser. So the server-side code actually has a hack to create the PDF and if the browser is iE9 or iOS, it stores the result in the DB (or AWS S3) and returns a link to that PDF so that it can be "clicked" to view. Other common browsers can automatically handle the binary data sent back if done correctly. For this we use FileSaver.js plugin Javascript that will download the PDF.
Other parts you can ignore frankly. Like logEvent which send an Event to Google Analytics, totformats variable tracks users downloads and limits them in any one session. The hack for Chrome downloads is likely not required as that was a bug in Chrome for Android. adding and loading 'loader' classes are for the GUI. The iE9, iOS solution using IP as a variable that is set, this is because the database is replicated and load balanced in many countries and because the data is written to the DB for this one call, we need the IP address of that exact server that has the result in it. This will go away with S3 integration.
Essentially the key is that is calls the same URL you would and saves the response using:
saveAs(this.response, pdffilename);
This is a call into FileSaver.js which handles saving the binary data from an XHR GET and downloading it for you. I have snipped this out from a much larger code which handles all of the downloads including dynamically generated ones from RenderX as yours is, but also static PDFs.
The call is straightforward, just a GET to customer-formatter.xq which is the same in my case as calling http://localhost/customer-formatter.xq (because I strip out /exist and my post for Jetty is 80):
xhr.open('GET', 'customer-formatter.xq?masterlang=' + masterlang + '&doclang=' + doclang + '&specialty='+ specialty + '&article=' + docnum + '&user_name=' + loggedInUser + '&territory=' + territory + '&expiry=' + expiry + '&page_width=' + page_width + '&page_height=' + page_height + '&column_count=' + column_count + '&phrasechange=' + phrasechange + '&genlink=' + genlink + '&access=' + access + '&scalefont=' + scalefont + '&skin=' + skin + '&watermark=' + watermarkmsg +'×tamp=' + timestamp);
totformats++;
if (totformats > maxformats)
window.location.href = '/user?logout=logout';
var docfilename = ((doclang) ? doclang : '') + ((doctype) ? doctype : '');
var pdffilename = docnum + '-' + docfilename + '.pdf';
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if (this.readyState == 4 && this.status == 200){
// Do IE9 stuff or iPhone/iPad
if (version == 9) {
var ip = this.responseText;
var a = document.createElement("a");
a.style = "cursor: pointer;";
document.body.appendChild(a);
var url = 'http://' + ip + '/IE9/' + loggedInUser + '-' + docnum + '-English.pdf';
a.href = url;
$(a).attr('target','_blank');
a.click();
$(a).remove();
$(doc).removeClass('loader');
$(doc).prop('disabled',false);
}
else if (isiOS) {
var ip = this.responseText.trim();
ioswindow.location.href = 'http://' + ip + '/IE9/' + loggedInUser + '-' + docnum + '-English.pdf';
$(doc).removeClass('loader');
$(doc).prop('disabled',false);
}
// Hack to partially fix Chrome error, file is now in Chrome downloads
else if (Math.max(document.documentElement.clientWidth, window.innerWidth || 0) <= 1024 && window.chrome) {
var blob = new Blob([this.response], {type: 'application/pdf'});
var a = document.createElement("a");
a.style = "display: none";
document.body.appendChild(a);
var url = window.URL.createObjectURL(blob);
a.href = url;
a.download = pdffilename;
a.click();
window.URL.revokeObjectURL(url);
$(doc).removeClass('loader');
$(doc).prop('disabled',false);
}
else {
saveAs(this.response, pdffilename);
$(doc).removeClass('loader');
$(doc).prop('disabled',false);
}
}
}
xhr.open('GET', 'customer-formatter.xq?masterlang=' + masterlang + '&doclang=' + doclang + '&specialty='+ specialty + '&article=' + docnum + '&user_name=' + loggedInUser + '&territory=' + territory + '&expiry=' + expiry + '&page_width=' + page_width + '&page_height=' + page_height + '&column_count=' + column_count + '&phrasechange=' + phrasechange + '&genlink=' + genlink + '&access=' + access + '&scalefont=' + scalefont + '&skin=' + skin + '&watermark=' + watermarkmsg +'×tamp=' + timestamp);
xhr.setRequestHeader('Authorization','Basic ' + sessinfo);
if (isiOS)
xhr.responseType = 'text';
else
xhr.responseType = 'blob';
xhr.send();
logEvent(docnum, doclang, 'format', specialty, source, docname);
Your download:download function is written in such a way that it works with eXist-db templating. I would suggest abstracting the actual download logic into a separate function in a separate library module.
You can then have your download:download function call your abstracted download logic function, and you can also create a new main module like direct-download.xq or whatever which just processes the URL and then calls your abstracted download logic function.
I have a very simple Web API app. Just 2 methods that put (edit or insert data) - I'd like to just hard code basic authentication into the 2 methods without hugely complicating it.
What is the minimum code I need in order to require authentication the two methods - and then how do I use this code (the APIs are called from some C# code in an MVC app).
All of the examples I find online are hugely complicated - with filters or overly elaborate authentication.
My web API methods look something like this:
public IHttpActionResult Put([FromBody]ImportObject impobj)
{
// Import data here
}
And I call it like this:
public async static Task<string> Caller(ImportObject impobj)
{
string responseString = "NA";
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// Post new object, get response
var response = await client.PutAsJsonAsync("myservice/api/meth", impobj);
// Get response content string
var resContent = response.Content.ReadAsStringAsync();
// Build user response string (just for testing)
responseString =
"<br />result: " + resContent.Result.ToString() +
"<br />status: " + resContent.Status.ToString() +
"<br />StatusCode: " + response.StatusCode + "<br />";
}
// Output response string
return responseString;
}
I just want to add basic auth to both ends - as it's so simple happy to just hard code it into both methods (this will also let me see easily how it works too).
thx.
I need to load a page from an HTML string, not from a server.
I use the method found in this answer :
String html = "<html><head><script>" +
"alert('hey 1'); " +
"function OnLoadEvent() { alert('hey 2'); }" +
"</script></head>" +
"<body onload='OnLoadEvent()'></body></html>"
URL url = new URL("http://www.example.com");
StringWebResponse response = new StringWebResponse(html, url);
WebClient client = new WebClient()
client.getOptions().setJavaScriptEnabled(true);
HtmlPage page = HTMLParser.parseHtml(response, client.getCurrentWindow());
I have also set an AlertHandler as follows:
client.setAlertHandler(new AlertHandler() {
#Override
public void handleAlert(Page arg0, String arg1) {
System.out.println("ALERT: " + arg1);
}
});
The example HTML above alerts "hey 1" only -- I would expect it to alert "hey 1" and "hey 2" -- this implies the body onload event is not firing.
Is there something extra I need to do to make the onload event fire?
I was missing a call to HtmlPage.initialize().
I am trying to get data from a page that dynamically appends data on load.
Specifications:
HTMLUnit : version : 2.14
But I am not able to get the new page after scroll. I tried using various browser versions and all possible code changes. It will be great if anyone can let me know what I am doing wrong.
Moreover document.documentElement.scrollTop; is always returning zero.
final WebClient webClient = new WebClient(BrowserVersion.FIREFOX_24);
webClient.getOptions().setThrowExceptionOnScriptError(false);
webClient.getOptions().setJavaScriptEnabled(true);
webClient.setAjaxController(new NicelyResynchronizingAjaxController());
webClient.waitForBackgroundJavaScript(60000);
HtmlPage page = webClient.getPage("http://www.snapdeal.com/products/mobiles-mobile-phones/?q=Brand:Samsung");
System.out.println(page.getTitleText());
final String pageAsXml = page.asXml();
System.out.println("Page1=\n" + pageAsXml);
String s = "window.scrollBy(0, window.innerHeight);document.documentElement.scrollTop;";
ScriptResult sr = page.executeJavaScript(s);
JavaScriptJobManager manager = page.getEnclosingWindow().getJobManager();
while (manager.getJobCount() > 4) {
System.out.println("SCript Job count = " + manager.getJobCount());
Thread.sleep(1000);
}
System.out.println("Result= " + sr.getJavaScriptResult() + "\n");
HtmlPage page2 = (HtmlPage) sr.getNewPage();
if(page == page2)
System.out.println("No difference");
else
System.out.println("Page2\n" + page2.asXml());
Thanks & Regards
Reeni