The URI myresourceUrl when hit in browser shows the json content in browser.
Requirement:
Need to use the get method of httpbuilder-ng to call GET of URI and response should have the content as json.
This json file will be necessary as input for another task.
How to achieve this. Do we need any parser to get the returned response as json using http-builder-ng.
Expected response format:
{"name":"Abc","info":{"age":45,"height":"5.5"}}
Tried the below get request using:
// setting the request URI
HttpBuilder http = HttpBuilder.configure(config -> {
config.getRequest().setUri(myresourceUrl);
});
String response = http.get(LazyMap.class, cfg -> {
cfg.getRequest().getUri().setPath(myPath);
}).toString();
Actual format we are getting:
{name:Abc,info:{age:45,height:5.5}}
How to get the response indicated above in expected response format.
First, confirm that you http request is indeed returning a JSON response. If so, you can use the gson library. Try
import com.google.code.gson;
String response = gson.toJSON(http.get(LazyMap.class, cfg -> {
cfg.getRequest().getUri().setPath(myPath);
}));
By default a content-type of "application/json" will be parsed rather than returned as a String. You need to define a custom parser for the content-type. I put together an example using a fake server that returns "application/json" content and then shows how to return it as a string in HttpBuilder-NG:
import com.stehno.ersatz.ErsatzServer;
import groovyx.net.http.HttpBuilder;
import static com.stehno.ersatz.ContentType.APPLICATION_JSON;
import static groovyx.net.http.NativeHandlers.Parsers.textToString;
public class Runner {
public static void main(final String[] args) {
final ErsatzServer server = new ErsatzServer();
server.expectations(expects -> {
expects.get("/something").responder(response -> {
response.body("{\"name\":\"Abc\",\"info\":{\"age\":45,\"height\":\"5.5\"}}", APPLICATION_JSON);
});
});
final String response = HttpBuilder.configure(cfg -> {
cfg.getRequest().setUri(server.getHttpUrl());
cfg.getResponse().parser("application/json", (chainedHttpConfig, fromServer) -> textToString(chainedHttpConfig, fromServer));
}).get(String.class, cfg -> {
cfg.getRequest().getUri().setPath("/something");
});
System.out.println(response);
System.exit(0);
}
}
Note the cfg.getResponse().parser("application/json", (chainedHttpConfig, fromServer) -> textToString(chainedHttpConfig, fromServer)); line which is where the parsing happens (overrides the default behavior) - see also the import import static groovyx.net.http.NativeHandlers.Parsers.textToString;.
Related
What is the data file that should be provided in Postman runner to execute multiple calls to a POST endpoint that expects multiplart/form-data?
I have an Azure function which looks like this (simplified for this post):
[FunctionName("UploadImage")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequest req, ILogger log)
{
var form = await req.ReadFormAsync();
if (!form.Files.Any()) return new BadRequestObjectResult("form.Files is empty");
var uploadedFile = form.Files.First();
form.TryGetValue("fileName", out var fileNames);
return new OkObjectResult($"Uploaded image length: {uploadedFile.Length} file name {fileNames.First()}");
}
I use Postman to send it a request successfully like this:
Postman request body params
I want to call this function 100 times concurrently to test its performance using the "Run Collection" selection of Postman. It asks to provide a csv datafile. So I tried a file that has only 2 lines like this:
FileName, Photo
Attachment1, Regina.jpg
But it does not work with that data file. I get a response message that "form.Files is empty"
How to correctly provide a data file for this Postman runner to test calling the endpoint (n) times async?
I`m trying to create cdc test for uploading file verifying. I use DIUS library. I do not find any examples how to work with .withFileUpload() in DIUS. My code for pact is next:
#Pact(provider = PROVIDER, consumer = CONSUMER)
public RequestResponsePact createPact(PactDslWithProvider builder) throws Exception {
DslPart responseBody = new PactDslJsonBody()
.stringType("resource", DESTINATION_FILENAME)
.stringType("requestId", null)
.stringType("code", "201")
.array("response")
.closeArray()
.asBody();
return builder.given("UploadOperation")
.uponReceiving("Upload operation")
.path("/files/upload")
.matchQuery("overwrite", "true")
.matchQuery("destination_filename", DESTINATION_FILENAME)
.withFileUpload("file",
".gitignore",
"multipart/form-data",
new byte[]{11,44,66,123,66}) // some bytes
.willRespondWith()
.status(201)
.body(responseBody)
.toPact();
}
Code for pact creation and verification:
#Test
#PactVerification
public void doTest() throws IOException {
String url = String.format("Http://localhost:%d/files/upload?overwrite=true&destination_filename=%s", PORT, DESTINATION_FILENAME);
// HttpEntity for request
HttpEntity multipart = MultipartEntityBuilder.create()
.setMode(HttpMultipartMode.BROWSER_COMPATIBLE)
.addBinaryBody("file", new byte[]{11,44,66,123,66},
ContentType.create("multipart/form-data"), ".gitignore")
.build();
// I make the request and get an answer
HttpResponse response = Request.Put(url)
.addHeader("Content-Type", "multipart/form-data;
boundary=j72BRjsEynnAqDw43KTlsjxoKWsjdF_tl6N5")
.body(multipart)
.execute()
.returnResponse();
String json = EntityUtils.toString(response.getEntity());
System.out.println("json=" + json);
JSONObject jsonObject = new JSONObject(json);
assertTrue(jsonObject.getString("code").equals("201"));
assertTrue(response.getStatusLine().getStatusCode() == 201);}
but when I run the test i get: json={"error": Missing start boundary}
java.lang.AssertionError: Pact Test function failed with an exception, possibly due to ExpectedButNotReceived(expectedRequests=[ method: PUT
path: /files/upload
query: [destination_filename:[test], overwrite:[true]]
headers: [Content-Type:multipart/form-data; boundary=iYxVLiQ0ZrP5g0SUP2pWa-rg20UM4JFe90p]
matchers: MatchingRules(rules={query=Category(name=query, matchingRules={overwrite=MatchingRuleGroup(rules=[RegexMatcher(regex=true, example=null)], ruleLogic=AND), destination_filename=MatchingRuleGroup(rules=[RegexMatcher(regex=test, example=null)], ruleLogic=AND)}), header=Category(name=header, matchingRules={Content-Type=MatchingRuleGroup(rules=[RegexMatcher(regex=multipart/form-data;(\s*charset=[^;]*;)?\s*boundary=.*, example=multipart/form-data; boundary=iYxVLiQ0ZrP5g0SUP2pWa-rg20UM4JFe90p)], ruleLogic=AND)}), path=Category(name=path, matchingRules={})})
generators: Generators(categories={})
body: OptionalBody(state=PRESENT, value=--iYxVLiQ0ZrP5g0SUP2pWa-rg20UM4JFe90p
Content-Disposition: form-data; name="file"; filename=".gitignore"
Content-Type: multipart/form-data
,B{B
--iYxVLiQ0ZrP5g0SUP2pWa-rg20UM4JFe90p--
)])
...
Caused by: org.json.JSONException: JSONObject["code"] not found.
Whats wrong in my code? I suppose something wrong with Content type, with 'boundary' part. But I dont know how to specify arbitrary boundary.
Maybe anybody knows another library where multipart/form-data uploading requests realized.
Thanks.
I found the solution from test example in DIUS library
contentType in .withFileUpload() and accordingly in .addBinaryBody() methods shouldn`t be "multipart/form-data". It may be "form-data" for example.
.addHeader in request method is not necessary because content type was already defined in body.
I'm using devise on ruby on rails for authentication. Taking it one step at a time, I have disabled the cookie authentication in order to test retrieving results prior to authentication.
If I go to my browser and navigate to the url that Alamofire is visiting, I get results in JSON format like this :
{"id":250,"name":null,"username":"walker","bio":null,"gender":null,"birth_date":null,"profile_image_url":null}
I'm requesting the alamofire request like this:
Alamofire.request(requestPath, method: .get, parameters: [:], encoding: JSONEncoding.default, headers: [:]).responseJSON { (response) in
if (response.result.isFailure) {
completion(false, "")
} else {
if let result = response.result.value {
completion(true, result)
}
}
}
This is all inside of another method which simply provides with a completion handler as you can see inside of the completion handler of the Alamofire request.
I get an error every single time.
The error says:
responseSerializationFailed : ResponseSerializationFailureReason
What am i doing wrong?
This error indicates that your response is not a JSON formatted data(or something wrong with your API Response), try to use something like post man to check your API response and to make sure every thing is ok before requesting with to swift
I am currently developing a web app which should do restful service calls to existing web service api.
What I have is the base URL and the API names.
Any help on how do I start working on it?
I suppose I need to use httpbuilder for the base url I have, then followed by /api name. But how do I test it on grails if its working?
When I paste the base url on the browser it does return some xml information, so what I need is to do it on grails instead.
XML response when I paste the url through browser
<ns1:createNewUserResponse>
<userId>21</userId>
</ns1:createNewUserResponse>
So I need to be able to get this response through my web-app (grails) instead of pasting it on the browser.
EDIT*
this is a good example I found useful
#Grab(group='org.codehaus.groovy.modules.http-builder', module='http-builder', version='0.5.0-RC2' )
import groovyx.net.http.*
import static groovyx.net.http.ContentType.*
import static groovyx.net.http.Method.*
def http = new HTTPBuilder( 'http://ajax.googleapis.com' )
// perform a GET request, expecting JSON response data
http.request( GET, JSON ) {
uri.path = '/ajax/services/search/web'
uri.query = [ v:'1.0', q: 'Calvin and Hobbes' ]
headers.'User-Agent' = 'Mozilla/5.0 Ubuntu/8.10 Firefox/3.0.4'
// response handler for a success response code:
response.success = { resp, json ->
println resp.statusLine
// parse the JSON response object:
json.responseData.results.each {
println " ${it.titleNoFormatting} : ${it.visibleUrl}"
}
}
// handler for any failure status code:
response.failure = { resp ->
println "Unexpected error: ${resp.statusLine.statusCode} : ${resp.statusLine.reasonPhrase}"
}
}
but i do not understand the query part and how do I alter it to my need?
the URL I have contains credential of username and password, the response should return a securityToken which I need to get it out from the results. Any help would be greatly appreciated!
You can start with groovy-wslite, it provides both SOAP and REST webservice clients.
To make a call to a resfull service look at Groovy HttpBuidler - http://groovy.codehaus.org/HTTP+Builder
While working with javascript that uses REST services extensively -- including using vocabs like GET, PUT, POST, DELETES, etc; I have found it hard to mock the server side so front end development can go on independently (of back end).
It is also useful to sometimes capture multi-step data, so we can help reproduce the entire chain of REST even (or bugs related to the front end that are triggered from these chains)
What tools can I use to mock REST calls, esp stateful ones? (i.e. if I do a PUT on some resource, I expect the next GET on it to change somehow)
I tried SOAPUI 4.0.1 and it's REST mocking is disappointing. Plus, my need is beyond single state mocking (which anyone can do with a static .json file). I need to do state transition type of mocks; working with Content-Range headers would be best.
Anyone?
I actually ended up creating my own Java REST Mock Engine that can basically mock any response. As long as you can handcraft or cut-paste a text file that simulates the entire http response, you can use my solution to mock the service.
Here's the servlet:
package com.mockrest.debug;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* Servlet implementation class MockGridData
*/
public class MockRest extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* #see HttpServlet#HttpServlet()
*/
public MockRest() {
super();
// TODO Auto-generated constructor stub
}
#Override
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException {
sub:{
HttpServletRequest request = (HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse)res;
String setdata = request.getParameter("__setdata");
if (setdata!=null && setdata.length()>0){
System.err.println("Setting Data...");
HttpSession sess = request.getSession(true);
String data = "/"+request.getParameter("__setdata");
sess.setAttribute("data", data);
try{
InputStream is = getServletContext().getResourceAsStream(data);
if (is!=null){
is.close();
response.getWriter().write("Successfully pointed next REST call to:"+data);
}
else{
response.sendError(500, "Cannot find resource:"+data);
}
}
catch (IOException ioe){
response.sendError(500, Arrays.deepToString(ioe.getStackTrace()));
}
}
else{
System.err.println("Fetching Data...");
HttpSession sess = request.getSession(false);
if (sess==null || sess.getAttribute("data")==null){
response.sendError(500,"Session invalid or no Previous Data Set!");
}
String rsrc = (String)sess.getAttribute("data");
System.err.println("Resource Being used:"+rsrc);
InputStream is = getServletContext().getResourceAsStream(rsrc);
if (is!=null){
String statusline = readLine(is);
Pattern statusPat = Pattern.compile("^HTTP/1.1 ([0-9]+) (.*)$");
Matcher m = statusPat.matcher(statusline);
if (m!=null && m.matches()){
int status = Integer.valueOf(m.group(1));
response.setStatus(status, m.group(2));
}
else{
throw new ServletException("Bad input file: status line parsing failed, got this as status line:"+statusline);
}
String line;
Pattern httpHeaderPat = Pattern.compile("^([^:]+): (.*)$");
while ((line=readLine(is))!=null){
if (line.length()==0){
// end of headers
break;
}
Matcher m2 = httpHeaderPat.matcher(line);
if (m2!=null && m2.matches()){
response.setHeader(m2.group(1), m2.group(2));
}
}
OutputStream os = response.getOutputStream();
byte[] buf = new byte[1024];
int size;
while ((size=is.read(buf))>0){
os.write(buf, 0, size);
}
os.flush();
}
}
}
}
private String readLine(InputStream is) throws IOException {
StringBuffer sb = new StringBuffer();
char c;
while ((c=(char)is.read())!='\n'){
sb.append(c);
}
if (sb.charAt(sb.length()-1) == '\r'){
sb.deleteCharAt(sb.length()-1);
}
return sb.toString();
}
}
To configure it, place prebuilt response files inside your WebContent folder. I usually end these files with .http extensions.
An example init.http file is below. Pretend we placed this file inside a folder called data inside WebContent:
HTTP/1.1 200 OK
Date: Wed, 26 Oct 2011 18:31:45 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
X-AspNet-Version: 4.0.30319
Content-Range: items 0-1/2
Content-Length: 385
Cache-Control: private
Content-Type: application/json
[
{
"id": "249F0",
"field1": " Global",
"displaystartdate": "2007-10-20",
"displayenddate": "2012-10-20",
"status": "Major Delay",
"children": true
},
{
"id": "962581",
"field2": "Europe",
"displaystartdate": "2007-10-20",
"displayenddate": "2012-10-20",
"status": "Major Delay",
"children": true
}
]
Headers must separate with body by an empty line (no spaces, nada). People familiar with http will notice it's a pure http response. This is on purpose.
You can use this tool to simulate any of the http headers you want the response to have; even going so far to respond with different server header(in my example, I simulated the response pretending to be IIS 6.0); or a different HTTP status code, etc.
To invoke it from your browser/javascript; first prime it with:
http://yourserver/yourweb/MockGridData?__setdata=data/init.http
Then in your javascript or REST AJAX call, if it goes to
http://yourserver/yourweb/MockGridData
with any method or parameter; it will get the http response you previously crafted with; even down to the Content-Range; Cache headers; etc. If you then need the subsequent AJAX call to return something else, simply call with __setdata again. I suggest you setup a few buttons to do the explicit state transition in your web app.
Assuming everything is setup, for a simulated REST chain, a developer may do:
invoke
http://yourserver/yourweb/MockGridData?__setdata=data/init.http
run a javascript module that will result in calling (say, with GET)
http://yourserver/yourweb/MockGridData
click a button that then does:
http://yourserver/yourweb/MockGridData?__setdata=data/step1.http
run another javascript step that will result in calling (say, with PUT)
http://yourserver/yourweb/MockGridData
click another button that then does:
http://yourserver/yourweb/MockGridData?__setdata=data/step2.http
run another javascript step that will result in calling (say, with GET)
http://yourserver/yourweb/MockGridData
but this time expecting different result than #4.
This should even work with binary and gzipped responses, but I haven't tested that.
Here is another homegrown rest-mocking tool: https://github.com/mkotsur/restito.