Can't send InputStream object using grails rest-client-builder - rest

I've been using rest-client-builder plugin (http://grails.org/plugin/rest-client-builder) and faced with problem to send a file as inputStream object.
From plugin documentation:
Multipart requests are possible by setting properties of the request body to File, URL, byte[] or InputStream instances:
def resp = rest.post(url) {
contentType "multipart/form-data"
zip = new File(pluginPackage)
pom = new File(pomFile)
xml = new File(pluginXmlFile)
}
My code:
def post(String url, InputStream photo, String contentType, Cookie[] cookies = null) {
def rest = new RestBuilder()
def cookiesHeaderString = ""
if (cookies) {
cookiesHeaderString = WebUtils.buildCookiesHeader(cookies)
}
def resp = rest.post(url) {
header "Cookie", cookiesHeaderString
file = photo
contentType "multipart/form-data"
}
return resp?.responseEntity?.body
}
Could somebody suggest how can I send an InputStream object or what I'm doing wrong?

For File type we need to set "file" property on the RequestCustomizer. The below code worked for me.
File myFile = new File("myFile.txt")
def restResponse = rest.post(url) {
header headerName, headerValue
contentType "multipart/form-data"
setProperty "file", myFile
}

I know I am quite late for this answer but I was searching for the answer and nothing seemed to work. So, by trial and error I finally have found my answer working, so would like to post it here.
RestTemplate restTemplate=new RestTemplate()
restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory());
def restBuilder=new RestBuilder(restTemplate)
File f = new File("C:/Users/USER/Documents/hello.txt")
MultiValueMap<String, File> form = new LinkedMultiValueMap<String, File>()
form.add("fileUpload", f)
return client.post(path) {
auth('ngtest1', 'ngtest1')
header :['contentType':"multipart/form-data"]
setProperty "fileUpload", f
body (form)
}
This worked for me. I have given the name as 'fileUpload' in my application. Hope this helps.

Related

making a REST calls from unity3d - Need to pass JSON object using HTTPWebRequest

How to make a REST call in unity3d? especially POST method. I have tried with GET request. Pls see the below get request. so i need to write POST request in Unity3d. The post rquest should be in JSON format. I tried with below code. It's hit the my service but the receiving JSON object is null. Hope your support.
var httpWebReq = WebRequest.Create("http://localhost:6091/UserService.svc/RegisterUser/") as HttpWebRequest;
httpWebReq.ContentType = "text/json;charset=utf-8";
httpWebReq.Method= "POST";
using(var streamWriter = new StreamWriter(httpWebReq.GetRequestStream()))
{
string user = "{UserID:0," +
"Email:'ruwan#gmail.com'," +
"Password:'ruwan123'," +
"NickName:'ruwa'," +
"Age:35" +
"}";
byte[] formData = UTF8Encoding.UTF8.GetBytes(user);
httpWebReq.ContentLength = formData.Length;
streamWriter.Write(formData);
}
var httpResponse = (HttpWebResponse)httpWebReq.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var responseText = streamReader.ReadToEnd();
//Now you have your response.
//or false depending on information in the response
Debug.Log(responseText);
}
use WWW for GET,
use WWW with WWWForm for POST.
Finally i got the solution thanks to all for help.
Actually the easiest way to make rest call for WCF is we have to add the Newtonsoft.Json. Finally my code is-
GET --
WebClient myWebClient = new WebClient();
myWebClient.Encoding = Encoding.UTF8;
myWebClient.Headers.Add("Content-Type", "text/json");
var json = JsonConvert.DeserializeObject<Room[] >(new WebClient().DownloadString("Your URL"));
List<yourclass> test1= new List<yourclass>();
foreach (var test in json)
{
test1.Add(new yourclass()
{
yourclass.property1 = test.property1
});
}
Debug.Log(test1);
POST---
WebClient myWebClient = new WebClient();
var Test = JsonConvert.SerializeObject(new
{
YourProperty= 0
}, new JsonSerializerSettings() { Formatting = Newtonsoft.Json.Formatting.None });
myWebClient.Encoding = Encoding.UTF8;
myWebClient.Headers.Add("Content-Type", "text/json");
string responsebody = myWebClient.UploadString("Your URL", "POST", Test );
//if(responsebody == true)
Debug.Log(responsebody);

Nancy : parsing "multipart/form-data" requests

I have a RestSharp Client and Nancy Self Host Server.
What I want is
To send multipart form data from client and parse that data easily
from server :
Send binary file and Json data As Multipart Form Data from RestSharp client
and able to get binary file and Json object from Nancy Server
At Client using Restsharp : [ http://restsharp.org/ ] I try to send "multipart/form-data" requests which contains a binary file plus some meta data in json format:
var client = new RestClient();
...
IRestRequest restRequest = new RestRequest("AcmeUrl", Method.POST);
restRequest.AlwaysMultipartFormData = true;
restRequest.RequestFormat = DataFormat.Json;
// I just add File To Request
restRequest.AddFile("AudioData", File.ReadAllBytes("filePath"), "AudioData");
// Then Add Json Object
MyObject myObject = new MyObject();
myObject.Attribute ="SomeAttribute";
....
restRequest.AddBody(myObject);
client.Execute<MyResponse>(request);
At Server using Nancy[ http://nancyfx.org/ ], Itry to get File and Json Object [Meta Data ]
// Try To Get File : It Works
var file = Request.Files.FirstOrDefault();
// Try To Get Sended Meta Data Object : Not Works.
// Can Not Get MyObject Data
MyObject myObject = this.Bind<MyObject>();
For multipart data, Nancy's code is a bit more complex.
Try something like this:
Post["/"] = parameters =>
{
try
{
var contentTypeRegex = new Regex("^multipart/form-data;\\s*boundary=(.*)$", RegexOptions.IgnoreCase);
System.IO.Stream bodyStream = null;
if (contentTypeRegex.IsMatch(this.Request.Headers.ContentType))
{
var boundary = contentTypeRegex.Match(this.Request.Headers.ContentType).Groups[1].Value;
var multipart = new HttpMultipart(this.Request.Body, boundary);
bodyStream = multipart.GetBoundaries().First(b => b.ContentType.Equals("application/json")).Value;
}
else
{
// Regular model binding goes here.
bodyStream = this.Request.Body;
}
var jsonBody = new System.IO.StreamReader(bodyStream).ReadToEnd();
Console.WriteLine("Got request!");
Console.WriteLine("Body: {0}", jsonBody);
this.Request.Files.ToList().ForEach(f => Console.WriteLine("File: {0} {1}", f.Name, f.ContentType));
return HttpStatusCode.OK;
}
catch (Exception ex)
{
Console.WriteLine("Error!!!!!! {0}", ex.Message);
return HttpStatusCode.InternalServerError;
}
};
Have a look at:
http://www.applandeo.com/en/net-and-nancy-parsing-multipartform-data-requests/

encoder function for multipart/form-data in groovy

I need to form a 'multipart/form-data' REST request with jpeg image and JSON file as the content.I am stuck with encoding the 'multipart/form-data' as a zip file.
Can someone tell me, how I can achieve this with groovy RESTClient? I could not find any documentation regarding this.
As it can be seen in the docs RESTClient extends HTTPBuilder. HTTPBuilder has a getEncoder method that can be used to add dedicated encoder (with type and method). See the following piece of code:
import org.codehaus.groovy.runtime.MethodClosure
import javax.ws.rs.core.MediaType
//this part adds a special encoder
def client = new RESTClient('some host')
client.encoder.putAt(MediaType.MULTIPART_FORM_DATA, new MethodClosure(this, 'encodeMultiPart'))
//here is the method for the encoder added above
HttpEntity encodeMultiPart(MultipartBody body) {
MultipartEntityBuilder.create()
.addBinaryBody(
'file',
body.file,
ContentType.MULTIPART_FORM_DATA,
body.filename
).build()
}
//here's how MultipartBody class looks:
class MultipartBody {
InputStream file
String filename
}
Now to create a multipart request You need to pass an instance of MultipartBody as a body argument to the request.
I was writing test using Groovy rest client to upload a .zip file.
None of the above answer's worked for me directly when testing with Groovy Rest Client. I had to make some adjustsment to the above answers. I am posting here so that some-one wants to post using Groovy Rest client can get benefits.
import groovyx.net.http.RESTClient
import org.apache.http.HttpEntity
import org.apache.http.entity.mime.MultipartEntityBuilder
import org.codehaus.groovy.runtime.MethodClosure
import static groovyx.net.http.ContentType.JSON
def uploadFile() {
def httpClient = new RESTClient(this.host)
File fileToUpload = new File("src/test/resources/fileName.zip")
httpClient.encoder.putAt(javax.ws.rs.core.MediaType.MULTIPART_FORM_DATA, new MethodClosure(this, 'encodeMultiPart'))
def multipartBody = new MultipartBody()
multipartBody.file = new FileInputStream(fileToUpload)
multipartBody.filename = fileToUpload.name
def response = httpClient.post(
path: '/app/uploadfile/path',
headers: [Accept : JSON,
User : "user",
Password: "password"
],
body: multipartBody,
requestContentType: 'multipart/form-data')
}
// register multipart encoder
HttpEntity encodeMultiPart(MultipartBody body) {
MultipartEntityBuilder.create()
.addBinaryBody(
'file',
body.file,
org.apache.http.entity.ContentType.MULTIPART_FORM_DATA,
body.filename
).build()
}
class MultipartBody {
InputStream file
String filename
}
Realise this is an oldy but might help others, although the question answers it from a beginner point of view it is difficult to fully understand how to reuse all of above properly.
Firstly the last comment on the question points to this link :
Which attempts to re-use the answer incorrectly. It has mixed above answer with an answer from this link
def content1 = new ContentDisposition("filename=aa.json")
def json1 = new File("resources/aa.json")
def attachments1 = new Attachment("root", new ByteArrayInputStream(json1.getBytes()), content1)
InputStream is2 = getClass().getResourceAsStream("resources/aa.json");
InputStream is1 = getClass().getResourceAsStream("resources/img.png");
ContentDisposition content2 = new ContentDisposition("attachment;filename=img.png")
Attachment attachments2 = new Attachment("root1", is1, content2)
def attachments = [attachments1, attachments2]
def body1 = new MultipartBody(attachments)
def client = new RESTClient( "https://somehost.com" )
ocutag.encoder.putAt(MediaType.MULTIPART_FORM_DATA, new MethodClosure(this, 'encodeMultiPart1'))
ocutag.encoder.putAt(MediaType.MULTIPART_FORM_DATA, new MethodClosure(this, 'encodeMultiPart2'))
The above is never going to work, I have it working like so:
def http = new RESTClient('http://localhost:8080')
http.encoder.putAt(MediaType.MULTIPART_FORM_DATA, new MethodClosure(this, 'encodeMultiPart'))
def body1 = new MultipartBody() //This is that MultipartBody class in the first answer example not the one from your imports......
body1.file=file.getInputStream()
body1.filename=file.name
def response = http.put( path: url, body:body1, query:['query':action, ], requestContentType: 'multipart/form-data' )
You also have encodeMultiPart2 and encodeMultiPart1, I think this is a misunderstanding just reuse 1 declaration of this method in both cases.. you don't need to do none of the attachments etc you have in your example..
Encoder registrations are so messy in previous responses, here is my working example:
import org.apache.cxf.jaxrs.ext.multipart.Attachment
import org.apache.cxf.jaxrs.ext.multipart.ContentDisposition
import org.apache.cxf.jaxrs.ext.multipart.MultipartBody
import org.apache.http.entity.ContentType
import org.apache.http.entity.mime.MultipartEntityBuilder
import javax.ws.rs.core.MediaType
...
def filenameToUpload = "doggo.jpg"
def expectedRequestParamName = "file"
def static uploadFile() {
// create attachment
def fileToUpload = new File(filenameToUpload)
def attachment = new Attachment(expectedRequestParamName, new ByteArrayInputStream(fileToUpload.getBytes()), new ContentDisposition("filename=" + filenameToUpload))
def body = new MultipartBody(attachment)
// create REST client
def httpClient = new RESTClient('http://localhost:8080')
// register encoder
httpClient.encoder.putAt(MediaType.MULTIPART_FORM_DATA, customMultipartEncoder)
// call REST
httpClient.post(
path: "upload",
body: body,
requestContentType: MediaType.MULTIPART_FORM_DATA)
}
// register multipart encoder
private def static customMultipartEncoder = { body ->
def builder = MultipartEntityBuilder.create()
body.allAttachments.collect {
builder.addBinaryBody(
it.contentId,
it.dataHandler.inputStream,
ContentType.MULTIPART_FORM_DATA,
it.contentId) }
return builder.build()
}

How to PUT XmlSlurper back to REST with HttpBuilder

I'm trying to make GET and then PUT call on XML REST web service.
I do it this way:
#Grab('org.codehaus.groovy.modules.http-builder:http-builder:0.7')
import groovyx.net.http.HTTPBuilder
import static groovyx.net.http.ContentType.*
import static groovyx.net.http.Method.*
import groovy.xml.XmlUtil
def url = "http://localhost:81"
def pathPrefix = "/api/v1"
def http = new HTTPBuilder(url)
def profile = http.request(GET, XML) { req ->
uri.path = "$pathPrefix/profiles/55"
response.success = {resp, xml ->
xml
}
}
println XmlUtil.serialize(profile) // this is fine!
Now i'm going to change and save
profile.name = "New Name"
// this is not fine (i have 400 Bad Request)
// because it sends body not in XML
def savedProfile = http.request(PUT, XML) { req ->
uri.path = "$pathPrefix/profiles/55"
body = profile
response.success = {resp, xml ->
xml
}
}
println XmlUtil.serialize(savedProfile)
When i make PUT request HTTPBuilder do not send XML. It sends string, made of profile.toString().
It it not what i'm expecting.
How to send XmlSlurper object (that i obtained earlier) in PUT request?
Thank you.
I think i found the solution.
When i define body configuration value, i have to write
body = {
mkp.yield profile
}

REST Windows Phone Photo upload

I'm trying to upload a photo to a REST api in a Windows Phone 7 application using RestSharp for my Gets/Posts.
The post parameters are as follows:
photo:
The photo, encoded as multipart/form-data
photo_album_id:
Identifier of an existing photo album, which may be an event or group
album
I've created my request, but every time I get back "{\"details\":\"missing photo parameter\",\"problem\":\"The API request is malformed\"}\n
My photo parameter looks like this:
"---------------------------8cd9bfbafb3ca00\r\nContent-Disposition: form-data; name=\"filename\"; filename=\"somefile.jpg\"\r\nContent-Type: image/jpg\r\n\r\n(some binary junk listed here)\r\n-----------------------------8cd9bfbafb3ca00--"
I'm not quite sure if it's a problem with how I'm presenting the binary data for the image (currently in my PhotoTaskCompleted event, I read the contents of e.ChosenPhoto into a byte[] and pass that to a helper method to create the form data) or if I just don't create the form correctly.
I'm just trying to do this a simple as possible, then I can refactor once I know how it all works.
void ImageObtained(object sender, PhotoResult e)
{
var photo = ReadToEnd(e.ChosenPhoto);
var form = PostForm(photo);
var request = new RequestWrapper("photo", Method.POST);
request.AddParameter("photo_album_id", _album.album_id);
request.AddParameter("photo", form);
request.Client.ExecuteAsync<object>(request, (response) =>
{
var s = response.Data;
});
}
private string CreateBoundary()
{
return "---------------------------" + DateTime.Now.Ticks.ToString("x");
}
private string PostForm(byte[] data)
{
string boundary = CreateBoundary();
StringBuilder post = new StringBuilder();
post.Append(boundary);
post.Append("\r\n");
post.Append("Content-Disposition: form-data; name=\"filename\"; filename=\"somefile.jpg\"");
post.Append("\r\n");
post.Append("Content-Type: image/jpg");
post.Append("\r\n\r\n");
post.Append(ConvertBytesToString(data));
post.Append("\r\n");
post.Append("--");
post.Append(boundary);
post.Append("--");
return post.ToString();
}
public static string ConvertBytesToString(byte[] bytes)
{
string output = String.Empty;
MemoryStream stream = new MemoryStream(bytes);
stream.Position = 0;
using (StreamReader reader = new StreamReader(stream))
{
output = reader.ReadToEnd();
}
return output;
}
Hammock for Windows Phone makes this real simple.
You just add the file to the request using the AddFile method and pass it the photo stream.
var request = new RestRequest("photo", WebMethod.Post);
request.AddParameter("photo_album_id", _album.album_id);
request.AddFile("photo", filename, e.ChosenPhoto);
Hum are you sure that your PostForm is correct ? The content-* params should be set in the headers of your POST and not in the body ?
var request = (HttpWebRequest)WebRequest.Create(url);
request.Headers.Add(HttpRequestHeader.Authorization,"blabla");
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";