Multipart Form Data File Uploading Made Simple with REST Assured

From a client perspective it has always seemed to me that uploading a large file or stream to a server using multi-part form data encoding in Java is overly complex. To address this I implemented support for it in REST Assured 1.3.

Example

Let’s say you have a simple HTML page that performs file-uploading from a browser like this:

We also assume that we have a server that receives the file and return a JSON response like this if everything was ok:

Now let’s use REST Assured to upload a file and assert that the upload was OK:

With so little code you’ve now managed to POST a large file using multi-part form data encoding to the server and asserted that the expected JSON bundled in the response body was correct.

But how can this work? We haven’t even specified a control name? Well if you don’t define a control name specifically REST Assured will default to “file”. In many cases this is of course not the case. For example let’s say we change the control name in the HTML form to “file2” instead:

REST Assured still makes it simple:

Multiple parts

You can even send multiple files, streams, byte-arrays and form parameters in the same request:

Summary

As you’ve hopefully seen it’s very simple do multi-part form data uploading with REST Assured. Credits should of course also go to Apache HTTP Client for making it possible. To get started with REST Assured today just visit the web-site. Enjoy!

11 Comments

  1. balveer

    hi jay,

    i have payload as below, could you please help me sending the below payload as post request.

    {
    “createdBy”: “exchange@sdp.com”,
    “createdOn”: “2015-08-07T16:47:27.527+05:30”,
    “id”: 500050,
    “updatedBy”: “exchange@sdp.com”,
    “updatedOn”: “2015-08-11T12:35:29.606+05:30”,
    “accountContexts”: [
    “EXCHANGE”
    ],
    “accountReferenceId”: “C00000003”,
    “billPayer”: false,
    “changePassword”: false,
    “correspondenceAddress”: {
    “createdBy”: “exchange@sdp.com”,
    “createdOn”: “2015-08-07T16:47:27.528+05:30”,
    “id”: 500050,
    “updatedBy”: “exchange@sdp.com”,
    “updatedOn”: “2015-08-07T16:47:27.528+05:30”,
    “city”: “bangalore”,
    “country”: “india”,
    “postalCode”: “23167”,
    “state”: “KA”,
    “street”: “Sarjapur”
    },
    “emailAddress”: “operator111@cim.com”,
    “name”: “operator111@cim.com”,
    “parentInfo”: {
    “createdBy”: “superadmin”,
    “createdOn”: “2015-05-13T12:41:23.433+05:30”,
    “id”: 1011,
    “updatedBy”: “superadmin”,
    “updatedOn”: “2015-05-13T12:41:23.433+05:30”,
    “accountContexts”: [
    “EXCHANGE”
    ],
    “accountReferenceId”: “A1011”,
    “billPayer”: true,
    “emailAddress”: “exchange@sdp.com”,
    “name”: “EXCHANGE”,
    “phoneNumber”: “9181818181”,
    “representative”: false,
    “state”: “ACTIVE”,
    “typeId”: 1001,
    “typeName”: “EXCHANGE_ACCOUNT_TYPE”,
    “userName”: “exchange@sdp.com”
    },
    “phoneNumber”: “234567”,
    “representative”: false,
    “state”: “OBSOLETE”,
    “type”: {
    “createdBy”: “exchange@sdp.com”,
    “createdOn”: “2015-08-07T12:53:04.048+05:30”,
    “id”: 500000,
    “updatedBy”: “exchange@sdp.com”,
    “updatedOn”: “2015-08-07T12:53:04.048+05:30”,
    “name”: “CIM_USERS”,
    “ownerName”: “EXCHANGE”
    },
    “useExternalAuthentication”: false,
    “userName”: “operator111@cim.com”,
    “password”: “Cisco_123”
    }

  2. Dheeraj

    Helpful.. Thanks :)

  3. Cong

    Hello Johan! I met a problem using this feature. In my service I wanna to upload a html file and the Java code is as following:

    @RequestMapping(method = RequestMethod.POST)
    public ResponseEntity uploadDocument(@RequestPart(“file”) final MultipartFile file,
    final HttpServletRequest request) throws IOException {
    final String id = documentService.saveDocument(file);
    final String url = request.getScheme() + “://” + request.getServerName() + “:” + request.getServerPort() + “/documents/” + id;
    return ControllerUtil.resourceCreatedMessage(id, url);
    }

    Then I tried to test this function:

    given().multiPart(“file”, new File(path))
    .expect().statusCode(201)
    .when().post(HOST + “/documents”);

    but I got the error message:

    java.lang.AssertionError: 1 expectation failed.
    Expected status code doesn’t match actual status code .

    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at org.codehaus.groovy.reflection.CachedConstructor.invoke(CachedConstructor.java:83)
    at org.codehaus.groovy.reflection.CachedConstructor.doConstructorInvoke(CachedConstructor.java:77)
    at org.codehaus.groovy.runtime.callsite.ConstructorSite$ConstructorSiteNoUnwrap.callConstructor(ConstructorSite.java:84)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallConstructor(CallSiteArray.java:60)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callConstructor(AbstractCallSite.java:235)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callConstructor(AbstractCallSite.java:247)
    at io.restassured.internal.ResponseSpecificationImpl$HamcrestAssertionClosure.validate(ResponseSpecificationImpl.groovy:451)
    at io.restassured.internal.ResponseSpecificationImpl$HamcrestAssertionClosure$validate$1.call(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
    at io.restassured.internal.RequestSpecificationImpl.applyPathParamsAndSendRequest(RequestSpecificationImpl.groovy:1632)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1215)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1024)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:812)
    at io.restassured.internal.RequestSpecificationImpl.invokeMethod(RequestSpecificationImpl.groovy)
    at org.codehaus.groovy.runtime.callsite.PogoInterceptableSite.call(PogoInterceptableSite.java:48)
    at org.codehaus.groovy.runtime.callsite.PogoInterceptableSite.callCurrent(PogoInterceptableSite.java:58)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:52)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:154)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:182)
    at io.restassured.internal.RequestSpecificationImpl.applyPathParamsAndSendRequest(RequestSpecificationImpl.groovy:1637)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1215)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1024)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:812)
    at io.restassured.internal.RequestSpecificationImpl.invokeMethod(RequestSpecificationImpl.groovy)
    at org.codehaus.groovy.runtime.callsite.PogoInterceptableSite.call(PogoInterceptableSite.java:48)
    at org.codehaus.groovy.runtime.callsite.PogoInterceptableSite.callCurrent(PogoInterceptableSite.java:58)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:52)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:154)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:182)
    at io.restassured.internal.RequestSpecificationImpl.post(RequestSpecificationImpl.groovy:170)
    at io.restassured.internal.RequestSpecificationImpl.post(RequestSpecificationImpl.groovy)
    at integrationTest.DocumentsIT.testDocuments(DocumentsIT.java:29)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

    Thank you so much!

  4. Partha Sarathi

    You are awesome. Thank you so much. This article helped me a lot. :)

  5. Oded Kessler

    Hi
    I need help ,
    I have a multi part payload ( that has 5-6 part with zip file within the parts ) that I want to gzip the whole payload it and send it with rest assured .
    Can someone help understand the syntax ?
    How do I write it ?
    Thanks
    Please write mails and help me ….
    Odedkessler

  6. Sanjeet Singh

    Hi,
    Just now sure how to give the location of the file which i want to include in the code.As of now i am giving the location of the file till the filename but getting 500 error.

  7. Garima Jain

    Hi,

    The file that I am uploading is becoming of zero bytes when being sent as multipart.

Trackbacks for this post

  1. REST API Automation Testing using REST Assured – Software Automation QA
  2. REST Assured- Automating HTTP Post method – Software QA Automation

Leave a Reply