Groovy httpbuilder post list params - grails

I'm trying to consume a web service from my grails project. I'm using httpbuilder 0.7.2. Below is my http client.
static def webServiceRequest(String baseUrl, String path, def data,method=Method.GET,contentType=ContentType.JSON){
def ret = null
def http = new HTTPBuilder(baseUrl)
http.request(method, contentType) {
uri.path = path
requestContentType = ContentType.URLENC
if(method==Method.GET)
uri.query = data
else
body = data
headers.'User-Agent' = 'Mozilla/5.0 Ubuntu/8.10 Firefox/3.0.4'
response.success = { resp, json ->
println "response status: ${resp.statusLine}"
ret = json
println '--------------------'
}
}
return ret
}
The issue is coming when i'm trying to send something like this:
def input = [:]
input['indexArray'] = [1,5]
api call
def response = webServiceRequest(url,uri,input,Method.POST)
when i'm printing the value of post data in my server it shows only last value of list.
{"indexArray":"5"}
it should show both 1 and 5

If you want to send json data using contenttype application/x-www-form-urlencoded you have to explicitly convert the data before adding it to the body, you can use (data as JSON).

I am using RESTClient (nice convenience wrapper on HTTPBuilder, https://github.com/jgritman/httpbuilder/wiki/RESTClient). It is as simple as this with Spock.
RESTClient restClient = new RESTClient("http://localhost:8080")
restClient.contentType = ContentType.JSON
Also it automatically parses the JSON data, so my Spock test is:
when: "we check the server health"
HttpResponseDecorator response = restClient.get([path : "/health"]) as HttpResponseDecorator
then: "it should be up"
response != null
200 == response.status
'application/json' == response.contentType

Related

C# WebClient.UploadData in Rails

I have a c# method that I'm trying to convert to ruby on rails . I'm using unirest but I think something is not working correctly. This is my C# method :
private static string HTTPPoster(string url, string prmSendData)
{
try
{
WebClient wUpload = new WebClient();
wUpload.Proxy = null;
Byte[] bPostArray = Encoding.UTF8.GetBytes(prmSendData);
Byte[] bResponse = wUpload.UploadData(url, "POST", bPostArray);
Char[] sReturnChars = Encoding.UTF8.GetChars(bResponse);
string sWebPage = new string(sReturnChars);
return sWebPage;
}
catch
{
return "-1";
}
}
And This is what I tried so far in rails with unirest :
def HTTPPoster(url)
xml = "My XML Goes Here"
byte_array = xml.bytes
headers = {}
headers['Content-Type'] = "application/json"
headers['Accept'] = "application/json"
response = Unirest.post(url,
headers: headers,
parameters: {
body: byte_array
})
puts "response #{response.body}"
if ![200,201].include?(response.code)
raise "Mblox Error: #{response.code}, #{response.body}"
end
end
If you also know other libraries that can achieve what I need please let me know.
I used Faraday gem and sent the data as xml and not as byte array. And now I am achieving want I wanted.
response = Faraday.post(url) do |req|
req.headers['Content-Type'] = "application/xml"
req.headers['Accept'] = "*/*"
req.headers['Accept-Encoding'] = "gzip, deflate, br"
req.body = xml
end

Uploading txt file via POST request with HttpBuilder

I want to upload a txt file to a website using a POST request with HTTPBuilder and multipart/form-data
I've tried running my function and I get a HTTP 200 OK response, but the file doesn't appear on the website anywhere.
private Map fileUpload(String url, File file){
log.debug "doPost: $url body: ${file.getName()}"
FileBody fileBody = new FileBody(file,ContentType.APPLICATION_OCTET_STREAM)
def result = [:]
try {
def authSite = new HTTPBuilder(url)
authSite.auth.basic(user, password)
authSite.request(POST) { req ->
headers.Accept = "application/json, text/javascript, */*; q=0.01"
req.params.setParameter(CoreConnectionPNames.SO_TIMEOUT, 20000)
req.params.setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 60000)
def mpe = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE)
mpe.addPart("gxt",fileBody)
req.setEntity(mpe)
response.success = { resp, reader ->
result = reader
}
response.failure = { resp, reader ->
println "My response handler got response: ${resp.statusLine}"
}
}
}
catch (e) {
log.debug("Could not perform POST request on URL $url", e)
throw e
}
return result
}
From debugging this is the status recieved
3695 [main] DEBUG org.apache.http.wire - << "HTTP/1.1 200 OK[\r][\n]"
3695 [main] DEBUG org.apache.http.wire - << "Date: Thu, 10 Jan 2019 07:34:06 GMT[\r][\n]"
Anything I'm doing wrong? I don't get any errors but it just seems like nothing happens.
I don't have anything conclusive, but I suspect there is something invalid with the way you set up the multipart upload.
To help figure this out, below is a standalone, working, multipart upload groovy script using HttpBuilder:
#Grab('org.codehaus.groovy.modules.http-builder:http-builder:0.7.1')
#Grab('org.apache.httpcomponents:httpmime:4.2.1')
import org.apache.http.entity.mime.content.*
import org.apache.http.entity.mime.*
import groovyx.net.http.HTTPBuilder
import static groovyx.net.http.Method.POST
fileUpload('https://httpbin.org/post', new File('data.txt'))
Map fileUpload(String url, File file){
println "doPost: $url body: ${file.name}"
def result
try {
new HTTPBuilder(url).request(POST) { req ->
requestContentType = "multipart/form-data"
def content = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE)
content.addPart(file.name, new InputStreamBody(file.newInputStream(), file.name))
req.entity = content
// json might be something else (like a reader)
// depending on the response content type
response.success = { resp, json ->
result = json
println "RESP: ${resp.statusLine}, RESULT: $json"
}
response.failure = { resp, json ->
println "My response handler got response: ${resp.statusLine}"
}
}
} catch (e) {
println "Could not perform POST request on URL $url"
throw e
}
result
}
The script assumes a file data.txt with the data to post in the current directory. The script posts to httpbin.org as a working test endpoint, adjust accordingly to post to your endpoint instead.
Saving the above in test.groovy and executing will yield something like:
~> groovy test.groovy
doPost: https://httpbin.org/post body: data.txt
RESP: HTTP/1.1 200 OK, RESULT: [args:[:], data:, files:[data.txt:{ "foo": "bar" }], form:[:], headers:[Accept:*/*, Connection:close, Content-Type:multipart/form-data; boundary=ZVZuV5HAdPOt2Sv7ZjxuUHjd8sDAzCz9VkTqpJYP, Host:httpbin.org, Transfer-Encoding:chunked], json:null, origin:80.252.172.140, url:https://httpbin.org/post]
(note that first run will take a while as groovy grapes need to download the http-builder dependency tree)
perhaps starting with this working example and working your way back to your code would help you pinpoint whatever is not working in your code.

Set headers in a groovy post request

I need to set a header in a post request: ["Authorization": request.token]
I have tried with wslite and with groovyx.net.http.HTTPBuilder but I always get a 401-Not authorized which means that I do cannot set the header right.
I have also thought of logging my request to debug it but I am not able to do that either.
With wslite this is what I do
Map<String, String> headers = new HashMap<String, String>(["Authorization": request.token])
TreeMap responseMap
def body = [amount: request.amount]
log.info(body)
try {
Response response = getRestClient().post(path: url, headers: headers) {
json body
}
responseMap = parseResponse(response)
} catch (RESTClientException e) {
log.error("Exception !: ${e.message}")
}
Regarding the groovyx.net.http.HTTPBuilder, I am reading this example https://github.com/jgritman/httpbuilder/wiki/POST-Examples but I do not see any header setting...
Can you please give me some advice on that?
I'm surprised that specifying the headers map in the post() method itself isn't working. However, here is how I've done this kind of thing in the past.
def username = ...
def password = ...
def questionId = ...
def responseText = ...
def client = new RestClient('https://myhost:1234/api/')
client.headers['Authorization'] = "Basic ${"$username:$password".bytes.encodeBase64()}"
def response = client.post(
path: "/question/$questionId/response/",
body: [text: responseText],
contentType: MediaType.APPLICATION_JSON_VALUE
)
...
Hope this helps.
Here is the method that uses Apache HTTPBuilder and that worked for me:
String encodedTokenString = "Basic " + base64EncodedCredentials
// build HTTP POST
def post = new HttpPost(bcTokenUrlString)
post.addHeader("Content-Type", "application/x-www-form-urlencoded")
post.addHeader("Authorization", encodedTokenString)
// execute
def client = HttpClientBuilder.create().build()
def response = client.execute(post)
def bufferedReader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()))
def authResponse = new JsonSlurper().parseText(bufferedReader.getText())

HTTPBuilder encoding utf-8 in Grails

I have a problem using HTTPBuilder in Grails.
The code is something like this.
def http = new HTTPBuilder("theURL")
http.request(method, ContentType.JSON) {
uri.path = "theURI"
headers.'Authorization' = "OAuth $accessToken"
headers.'Accept' = "application/json"
headers.'content-type' = "application/json;charset=utf-8"
response.success = { resp, json ->
result = json
}
}
return result
Now the response is a JSON with "Cobro N�� 1234" but i need "Cobro Nº 1234"
I tried this with curl and the response is fine "Cobro Nº 1234", this made me think that the problem is the HTTPBuilder and not my API who response the request.
I think that it is a problem with the response encoding.
http.encoders.charset = Charsets.UTF_8
Try this:
headers.'content-type' = "application/JSON;charset=UTF-8" //capitalized
Either, try this:
#Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
Try adding this after your 'http' declaration:
http.encoderRegistry = new EncoderRegistry( charset: 'utf-8' )
I couldn't follow if the content you are sending needs to be encoded with UTF-8, or if the content you are receiving needs to be read with UTF-8.
I was having a problem sending content with UTF-8, and this is what I did.
http.request(Method.PUT) { request ->
// set headers here
request.entity = new StringEntity(json.toString(), "UTF-8")
}
I'm converting a net.sf.json.JSONObject to a String in order to pass it along as the body of the PUT call. I'm using StringEntity, and previously I wasn't setting the encoding on the StringEntity, but there is a constructor that takes an encoding. Now that I'm setting "UTF-8" there, it is working.

Post request by ruby code and JAva code for Rails application

i am trying to call my Rails app using Ruby code .
I m having 2 tables .
Blogposts (id,name,slug,desc)
Comments (id,data,node_id,node_type)
I m trying to post a comment through my ruby code.
The Url for me is like
http://localhost:3000/api/blogs/comment.xml?slug=blogtitle-0&comment=aaaaaaaaaaaaaaa
I dont know how to write Ruby post code for this.
The one is tried is
require 'net/http'
require 'uri'
url = URI.parse('http://localhost:3000/api/blogs/comment.xml?slug=blogtitle-0')
req = Net::HTTP::Post.new(url.path)
req.basic_auth 'aruna', 'aruna'
req.set_form_data({'comment[data]'=>'aaaaaaaaaaaaaaa'}, ';')
res = Net::HTTP.new(url.host, url.port).start {|http| http.request(req) }
case res
when Net::HTTPSuccess, Net::HTTPRedirection
puts res.body
else
res.error!
end
end
Please help in fixing this
Edit: The same thing i am trying using Java using Jersey library file .
Here also i am not getting the result.
The one i tried in Java is,
blogBean = objBlogWrapper.postComment(slug,comment);
public BlogBean postComment(String slug, String comment) {
System.out.println(slug+""+comment);
// Create a multivalued map to store the parameters to be send in the REST call
MultivaluedMap<String, String> newBlogParam = new MultivaluedMapImpl();
// newBlogParam.add("blogpost[slug]", slug);
// newBlogParam.add("comment[data]", comment);
newBlogParam.add("slug", slug);
newBlogParam.add("comment", comment);
BlogBean blogBean = null;
try {
blogBean = webResource.path(ConfigurationUtil.POST_COMMENT).header(ConfigurationUtil.AUTHENTICATION_HEADER, authentication)
.type(MediaType.APPLICATION_FORM_URLENCODED_TYPE).accept(MediaType.APPLICATION_XML_TYPE).post(BlogBean.class, newBlogParam);
}catch (UniformInterfaceException uie) {
if (uie.getResponse().getStatus() == 401) {
System.out.println("Can not authenticate user "+ConfigurationUtil.userName +
". Please check your username/password and try again." );
} else {
System.out.println("Error when trying to talk to app. " +
"HTTP status code "+uie.getResponse().getStatus()+"returned. Finishing.");
}
return null;
} catch (ClientHandlerException che) {
System.out.println("Error when trying to talk toapp. Network issues? " +
"Please check the following message and try again later: "+che.getMessage());
return null;
}
return blogBean;
}
where my ConfigurationUtil.POST_COMMENT="api/blogs/comment.xml";
The above doesnt show me any error nor the comment is posted ..
Please give suggestions.
Here you go,
host, phost = ['http://localhost:3000', 'http://proxyhost:2521' ]
user, password = [ 'user_name' , 'password' ]
url, p_url = [URI.parse(host), URI.parse(phost)]
resp = nil
http = Net::HTTP.new(url.host, url.port, p_url.host, p_url.port)
req = Net::HTTP::Post.new(url.path)
req.basic_auth user, password
req.set_content_type 'application/xml'
req.body = 'your_request_body'
resp = http.start{|h| h.request(req)}
You may not need a proxy host at all. But just in case if you want your request proxied through, you can use that. The resp object will have your response.
With Faraday you just do
body_resp = Faraday.post 'http://localhost:3000/api/blogs/comment.xml', {:slug => 'blogtitle-0', :comment => 'aaaaaaaaaaaaaaa'}.body
Using some external gem can help because Net::Http class in Ruby is not the most simplest API.

Resources