I have a line of code that performs a request to an API but I can't figure out the exact format of the request.
mapper.writeValueAsString from here.
mockMvc from here.
mockMvc.perform(post("/press/group").param("filterId", filterId).content(mapper.writeValueAsString(someObject)).contentType(MediaType.APPLICATION_JSON))
I'm trying to convert the code to Python and if there's a way to have my mockMvc output the corresponding HTML request it would be very helpful. The API I'm querying lacks documentation
Thanks and any guidance is much appreciated
MockMvc allows you to print both the request and the response.
In your case, you should do:
mockMvc.perform(post("/press/group").param("filterId", filterId).content(mapper.writeValueAsString(someObject)).contentType(MediaType.APPLICATION_JSON)).andDo(print());
This will print the output to the console, and it will look something like this:
MockHttpServletRequest:
HTTP Method = POST
Request URI = /press/group
Parameters = {filterId=[filterId_val]}
Headers = {}
Handler:
Type = com.yourCompany.yourController
Method = public ReturnType com.yourCompany.yourController.yourHandlerMethod(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse,java.lang.String)
Async:
Async started = false
Async result = null
Resolved Exception:
Type = null
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
MockHttpServletResponse:
Status = 200
Error message = null
Headers = {}
Content type = null
Body = {"val1" : "val_one"}
Forwarded URL = null
Redirected URL = null
Cookies = []
This should be enough info for you to construct the http request in python.
Don't know about mockMVC, but if this gets rendered in an HTML page, you could use the Chrome developer tools to generate the curl statement for you.
Start Tools/Developer Tools, click the network tab, click the link/button/thing that causes the request, find the request in the Network tab, right click, copy as cUrl.
Obviously, if it's not rendered in an HTML page, this isn't going to be a great deal of help.
Extract value of string of mapper.writeValueAsString(someObject)
this string is JSON (MediaType.APPLICATION_JSON) so it should look like:
{"attribute":"value","attribute":"value"}
And param("filterId", filterId)
is added to your url (variable filterId is some string so extract it)
/press/group?filterId:filterIdString
Paste it to the curl message:
curl -X POST -d '{"attribute":"value","attribute":"value"}' -H "Content-Type: application/json" "admin:password#localhost:8080/press/group?filterId:filterId" -i
Look at response
Explanation
X type of request
-d data
-H content type
admin:passwor# credentials
-i informations
Related
I have the following scenario. I have an XML file:
query-users.xml
<?xml version="1.0"?>
<q:query xmlns:q="http://prism.evolveum.com/xml/ns/public/query-3">
</q:query>
When executing the curl commend:
curl.exe --user administrator:5ecr3t -H "Content-Type: application/xml" -X POST http://localhost:8080/midpoint/ws/rest/users/search -d #C:\Users\user\query-users.xml
I get the desired response in XML.
I am trying to do the same POST request using RestTemplate from JAVA code:
try{
StringBuilder builder = new StringBuilder();
builder.append("http://localhost:8080/midpoint/ws/rest/users/search");
builder.append("?query=");
builder.append(URLEncoder.encode("<?xml version=\"1.0\"?><q:query xmlns:q=\"http://prism.evolveum.com/xml/ns/public/query-3\"></q:query>"));
URI uri = URI.create(builder.toString());
restOperations.postForEntity(uri, new HttpEntity<String>(createHeaders("username", "pass")), String.class);
logger.info(response);
}catch(Exception e){
logger.info(e.getMessage());
}
}
I get Internal Servel Error .
There is something that I am doing wrong passing the XML string to the POST request with RestTemplate, but I am not figuring out what it is.
Is there a way how to solve this?
Thanks
Your curl invocation and RestTemplate call are not equivalent. In first one you pass your xml as a a body of HTTP Request (this is what -d option does). In your RestTemplate you assign your xml to query and consequently HTTP Request has no payload and your data is encoded in URL.
If you want to pass your xml as a HTTP Body, you should use different HttpEntity constuctor: http://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/HttpEntity.html#HttpEntity-T-org.springframework.util.MultiValueMap-
Confirmed the following in Curl:
This is working fine-
curl -X GET 'http://remoteUrl.com:8080/public/private/request/data?begin=12&end=20'
This is not working-
curl -X GET http://remoteUrl.com:8080/public/private/request/data?begin=12&end=20
So the whole purpose is to use the way first curl command in a java code with restlet to send the paramters in a GET request but unfortunately my code is not working.
Code:
ClientResource clientResource = new
ClientResource("http://remoteUrl.com:8080/public/private/request/
data?begin=12&end=20");
Representation clientText = clientResource.get();
Error Log:
INFO: Unable to read a header
java.io.IOException: Parameter or extension has no name. Please check your value
at org.restlet.engine.header.HeaderReader.readNamedValue(HeaderReader.java:499)
at org.restlet.engine.header.CacheDirectiveReader.readValue(CacheDirectiveReader.java:65)
at org.restlet.engine.header.CacheDirectiveReader.readValue(CacheDirectiveReader.java:38)
at org.restlet.engine.header.HeaderReader.addValues(HeaderReader.java:282)
at org.restlet.engine.header.CacheDirectiveReader.addValues(CacheDirectiveReader.java:50)
at org.restlet.engine.header.HeaderUtils.copyResponseTransportHeaders(HeaderUtils.java:776)
at org.restlet.engine.adapter.ClientAdapter.readResponseHeaders(ClientAdapter.java:129)
at org.restlet.engine.adapter.ClientAdapter.updateResponse(ClientAdapter.java:191)
at org.restlet.engine.adapter.ClientAdapter.commit(ClientAdapter.java:105)
at org.restlet.engine.adapter.HttpClientHelper.handle(HttpClientHelper.java:119)
at org.restlet.Client.handle(Client.java:153)
From the exception you give in your question, it seems that the value of the header Cache-Control isn't correct within the response. Restlet isn't able to parse it.
I guess that the value of this header is an empty string in the response...
Could you give us in your question the exact content of the response (mainly headers)?
Hope it helps you,
Thierry
This question already has answers here:
HTTP GET with request body
(23 answers)
Closed 7 years ago.
I don't understand why this curl invocation gives me a 400 bad request.
curl -v -XGET -H "Content-Type:application/json" -d '{"match":{"first":"james"}}' http://localhost:8080/geocon/search/
Considered that this is the code part who should handle everything
#Path(Paths.SEARCH)
public class SearchService {
#GET
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public String search(#DefaultValue(NO_TYPE) #QueryParam("type") String type, String query) {
// do interesting stuff with the query
System.out.println(type);
System.out.println(query);
return //the result of the query
}
Obviously, I don't see in the console the two print lines and the answer from the web service is 400 Bad request
If I change the verb in curl and in the code (POST instead of GET), the results are OK and everything works as it should.
Why?
Can't I use GET passing data? If you think about it, I am not modifying stuff, I'd just receive data so GET should be the most RESTful translation for it.
You are allowed to send a body with a GET request, but it must not have any semantics; it should essentially be ignored. Not doing so violates the HTTP/1.1 specification. I suggest avoiding this practice because no one expects a request body with a GET request.
Now I'm not sure if the MVC framework you're using is stricter in the sense that it automatically rejects any GET request sent with a body, because in general a server can accept a GET request with a body, but is just supposed to ignore it.
Hence, what you're doing is not RESTful. The only way you can pass in data through a GET is through query parameters.
UPDATE
This is in response to your comment.
You could expose an explicit resource called searchResult or search. To create a searchResult or search resource instance, you pass in a body that is essentially a query. If you are using semantic media types (as you should for proper RESTfulness), your search-result resource could have the media type application/vnd.myservice.search-result+json and the query can have the media type application/vnd.myservice.search-query+json. Then, you can POST a request to /searchResults that has a request body that contains the complex query. The media-type of the response would be application/vnd.myservice.search-result+json and it can contain the search results.
So how does this play out? A search query comes in and you parse out the body and run the query. Then you should persist the results (not for ever; give it some sane TTL value). Once you have done that, you return a 303 See Other with a Location header that has a link to the search results (maybe something like /searchResults/4334, where 4334 is the id of this particular result). The client can then access this URI to retrieve the search results. If the client requests a search result that has expired (i.e., the server cleaned it up because the TTL expired), then the server should respond with a 410 Gone.
Also read this for more pointers.
It seems that syntax you are using has a typo.Try using the below ones for json and xml format. -XGET is wrong. it should be -X GET.
For xml
curl -H "Accept: application/xml" -H "Content-Type: application/xml" -X GET http://hostname/resource
For JSON
curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X GET http://hostname/resource
I have this controller in spring
#RestController
public class GreetingController {
#RequestMapping(value = "/greeting", method = RequestMethod.POST)
public String greeting(#RequestParam("uouo") String uouo) {
return uouo;
}
}
and when I testing it
curl -k -i -X POST -H "Content-Type:application/json" -d uouo=test http://192.168.1.104:8080/api/greeting
the result of the testing
HTTP Status 400 - Required String parameter 'uouo' is not present
I tried may thing, but I think #RequestParam can't use for POST it always passed the parameter in URL using GET, I use post only if I had object JSON as parameter using #RequestBody, is there any way to make string parameter send using POST?
The Servlet container will only provide parameters from the body for POST requests if the content type is application/x-www-form-urlencoded. It will ignore the body if the content type is anything else. This is specified in the Servlet Specification Chapter 3.1.1 When Parameters Are Available
The following are the conditions that must be met before post form
data will be populated to the parameter set:
The request is an HTTP or HTTPS request.
The HTTP method is POST.
The content type is application/x-www-form-urlencoded.
The servlet has made an initial call of any of the getParameter family of methods on the request object.
If the conditions are not met and the post form data is not included
in the parameter set, the post data must still be available to the
servlet via the request object’s input stream. If the conditions are
met, post form data will no longer be available for reading directly
from the request object’s input stream.
Since you aren't sending any JSON, just set the appropriate content type
curl -k -i -X POST -H "Content-Type:application/x-www-form-urlencoded" -d uouo=test http://192.168.1.104:8080/api/greeting
or let curl infer it
curl -k -i -X POST -d uouo=test http://192.168.1.104:8080/api/greeting?uouo=test
Note that you can still pass query parameters in the URL
curl -k -i -X POST -H "Content-Type:application/json" http://192.168.1.104:8080/api/greeting?uouo=test
i know you shouldn't send a HTTP GET Request with a body, but ceilometer web api forces me to do so.
I'm developing a ceilometer scala client, so I need a scala/java way to make a get request with a body.
So far I tried with beeClient (http://www.bigbeeconsultants.co.uk) and in plain Java using httpConnection but I get a 404 error.
In curl I can achieve the result in this way:
curl -X GET -H "X-Auth-Token: ..long long token here.."
-H "Content-Type: application/json"
-d '{"q": [{"field": "resource", "op": "eq", "value": "gdfsf"}]}'
http://137.204.57.150:8777/v2/meters/
That's my scala code that uses java HttpURLConnection:
import java.io._
import java.net._
val token = "myToken"
val url = new URL("http://137.204.57.150:8777/v2/meters/")
val body = "{\"q\": [{\"field\": \"resource\", \"op\": \"eq\", \"value\": \"gdfsf\"}]}"
val bodyLenght = body.length.toString
val connection = url.openConnection().asInstanceOf[HttpURLConnection]
connection.setRequestMethod("GET")
connection.setRequestProperty("Content-Type", "application/json")
connection.setRequestProperty("Content-Length", bodyLength)
connection.setRequestProperty("Accept", "*/*")
connection.setRequestProperty("X-Auth-Token", token)
connection.setDoInput(true)
connection.setDoOutput(true)
//SEND REQUEST
val wr = new DataOutputStream(connection.getOutputStream)
wr.write(body.getBytes)
wr.flush
wr.close
if (connection.getResponseCode == 200)
println("ok")
else
println("error")
What's the difference between my Java implementation and the curl command? I can't see any, I tried checking the header of curl calling it with the -v argument and that's what I get:
* Hostname was NOT found in DNS cache
* Trying 137.204.57.150...
* Connected to 137.204.57.150 (137.204.57.150) port 8777 (#0)
> GET /v2/meters/ HTTP/1.1
> User-Agent: curl/7.37.1
> Host: 137.204.57.150:8777
> Accept: */*
> X-Auth-Token: ...Token....
> Content-Type: application/json
> Content-Length: 60
>
* upload completely sent off: 60 out of 60 bytes
* HTTP 1.0, assume close after body
And then I get the response.
Thank you in advance
I resolved the problem using jetty-client implementation, that lets build http requests in anyway you want. Here's the code (it's not immutable but it's not that bad in scala):
val httpClient = new HttpClient()
httpClient.setConnectTimeout(connectTimeout)
httpClient.setFollowRedirects(false)
httpClient.setStopTimeout(readTimeout)
httpClient.start()
val resp = httpClient.newRequest(uri).
method(HttpMethod.GET).
header("X-Auth-Token",s).
send()
Look that i'm using the blocking API but jetty provides also a Java NIO API.
I found a working plain java solution here, using apache's httpclient, httpcore, and commons-logging libs.
You need to create a class and extend HttpEntityEnclosingRequestBase, overriding the method name:
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
public class HttpGetWithEntity extends HttpEntityEnclosingRequestBase {
public final static String METHOD_NAME = "GET";
#Override
public String getMethod() {
return METHOD_NAME;
}
}
Then you just use it like this:
HttpClient httpClient = HttpClientBuilder.create().build();
HttpGetWithEntity e = new HttpGetWithEntity();
e.setURI(new URI(yourURL))
e.setEntity(yourEntity);
HttpResponse response = httpclient.execute(e);
Hope it helps.
In general, the specification does not prohibit body on any type of http request (GET, DELETE etc), so you can do it if needed. However by convention this is atypical.
The problem you're having is that there are assumptions about what you can and can't do in the implementation of URLConnection you're using. In general, you'll be using a HttpUrlConnection (as you cast to), which will actually be implemented by your jvm. For example, here is a sun specific implementation.
If you look at this implementation, you will see it assumes that a GET request where you need the output stream is actually a POST.
If you want a GET with a body, you need to use a different connection method, for example a library like apache-http-client. You could start by looking at this question. There may be better scala alternatives for you to start with.
You use HTTP PUT or POST request when sending request body for Celiometer API.
I checked the Ceilometer documentation and found that all requests with request body use HTTP PUT or POST methods. No GET method with request body.
http://docs.openstack.org/developer/ceilometer/webapi/v2.html
After checking the documentation of Ceilometer and cURL I can suggest two things.
Use URL parameters instead of JSON
As per the documentation you can use the URL parameters or JSON. You can modify your request as specified below to achieve the same thing with URL parameters rather than JSON.
URL("http://YOURHOST.COM:8777/v2/meters/?q.field=resource&q.op=eq&q.value=gdfsf")
In case you have a specific reason not to use URL parameters for your JSON approach I guess encoding is what is missing in your request. Parameters are required to be sent in query parameters only rather than body content. For that I guess you need to try with below encoded data as shown below based on your request in the question.
URL("http://YOURHOST.COM:8777/v2/meters/?q=%5B%7B%22field%22%3A%20%22resource%22%2C%20%22op%22%3A%20%22eq%22%2C%20%22value%22%3A%20%22gdfsf%22%7D%5D%7D")
Here q is the root query parameter name, without token I was not able to validate it.
Replace YOURHOST.COM with ip address for your server as it was showing problem to me even after putting them in code block and please let me know.
you can try like this also
#RequestMapping(value = "/listcategories", method = RequestMethod.GET)
private ModelAndView getCategories() {
ModelAndView modelAndView = new ModelAndView("list-of-categories");
List<Category> categories = categoryService.getAllCategories();
modelAndView.addObject("categories", categories);
return modelAndView;
}