3

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.

Opal
  • 81,889
  • 28
  • 189
  • 210
sailakshmi
  • 45
  • 1
  • 2
  • 6
  • This is the code i am using. : : http://www.coderanch.com/t/646732/Groovy/form-multipart-requests-RestClient#2978425____for this i am getting an error " No encoder found for request content type multipart/form-data " – sailakshmi Mar 06 '15 at 06:35
  • Was my answer useful? – Opal Mar 08 '15 at 19:18
  • @opal :thanks for the code. But I am confused with adding two files (image file and json) as a single input stream file in the multipart body. – sailakshmi Mar 09 '15 at 05:36
  • These should be two separate requests. – Opal Mar 09 '15 at 06:32
  • @Opal :I am still stuck with some errors. throws an error "Could not find matching constructor for: FileUploadSpec$MultipartBody" please go through the link : ( https://drive.google.com/file/d/0Byf9LNy6os5IaVREUDRhNU1yUjQ/view?usp=sharing) – sailakshmi Mar 10 '15 at 05:32

4 Answers4

4

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.

Opal
  • 81,889
  • 28
  • 189
  • 210
2

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
}
Shirishkumar Bari
  • 2,692
  • 1
  • 28
  • 36
1

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..

V H
  • 8,382
  • 2
  • 28
  • 48
1

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()
}
bladekp
  • 1,529
  • 22
  • 29