Retrofit — How to Upload Files to Server

This is the last post in our Retrofit series. File upload functionality is often required for mobile apps. Before we start, let’s have an overview of the previously released posts.

Retrofit Series Overview

  1. Introduction to Call Adapters (Coming soon)
  2. Custom Call Adapter to Separate OnResponse Callback (Coming soon)
  3. How to Integrate RxJava 1.x Call Adapter (Coming soon)
  4. How to Integrate RxJava 2.x Call Adapter (Coming soon)
  5. How to Integrate Guava Call Adapter (Coming soon)
  6. Custom Call Adapter to Separate Network and Gson Errors (Coming soon)
  1. Callbacks (Coming soon)
  2. Annotations (Coming soon)
  3. Fluent Interface with Builders (Coming soon)

Introduction

Most Android apps need some kind of upload functionality where you want to send your profile picture to the server or upload other files to share with your friends. However, this guide can be used for any kind of file and not just images.

File Upload with Retrofit 2.x

We’ve published an updated blog post on how to upload files using Retrofit 2.x. If you’re using Retrofit 2, please follow the linked guide.

Upload Files with Retrofit 1

Retrofit provides the ability to perform Multipart requests. That enables the feature to upload files to a server. The @Multipart annotation is required to perform those requests. The following code shows the method definition to upload a file to a given API endpoint.

public interface FileUploadService {  
    public static final String BASE_URL = "http://your.api/endpoint/base-url";

    @Multipart
    @POST("/upload")
    void upload(@Part("myfile") TypedFile file,
                @Part("description") String description,
                Callback<String> cb);
}

This FileUploadService interface is the client side API declaration. You’re going to request http://your.api/endpoint/base-url/upload hooked with two parameters: a file myfile and String description.

To perform the actual request, you need to instantiate a RestAdapter. Have a look at our Retrofit Getting Started Guide where we present a ServiceGenerator class to create services for defined interfaces.

The ServiceGenerator (described in the getting started post) creates and instantiates the required HTTP client for your service interface. In our case, we pass the FileUploadService to the static method createService and get a functional implementation to perform the upload.

The following code snippet illustrates the usage of previously described methods.

    FileUploadService service = ServiceGenerator.createService(FileUploadService.class, FileUploadService.BASE_URL);
TypedFile typedFile = new TypedFile("multipart/form-data", new File("path/to/your/file"));  
String description = "hello, this is description speaking";

service.upload(typedFile, description, new Callback<String>() {  
    @Override
    public void success(String s, Response response) {
        Log.e("Upload", "success");
    }

    @Override
    public void failure(RetrofitError error) {
        Log.e("Upload", "error");
    }
});

TypedFile is a class from Retrofit representing a file with mime type. We use multipart/form-data as mime type and create a file from given path.

That’s the upload part on Android side :)

Remember the Content-Type

Attention: keep an eye on the content type of the RestAdapter. If you specify the header request.addHeader("Content-Type", "application/json"); via RequestInterceptor, the request will probably fail at server side since your’re sending multipart data and not JSON.

Example hapi.js Server to Handle File Uploads

We’ve tested the upload functionality from Android to the backend with a hapi.js server. For that, we implemented a rudimentary functionality to just log the incoming data at server side. Multiparty was our module of choice for data parsing operations. Of course, you can use whatever you prefer.

The hapi.js route configuration for our file upload test.

server.route([  
    {
        method: 'POST',
                path: '/upload',
            config: {
        payload: {
            maxBytes: 209715200,
                    output: 'stream',
                    parse: false
        },
        handler: function(request, reply) {
            var multiparty = require('multiparty');
            var form = new multiparty.Form();
            form.parse(request.payload, function(err, fields, files) {
                console.log(err);
                console.log(fields);
                console.log(files);
            });
        }
    }
}]);

We want to separate the topics of file upload with Retrofit on Android and the hapi.js server. That’s why we just leave the code snippet above without any additional comments. If you run into any problems or questions regarding the server test code, you can for sure just let us know in the comments or via twitter @futurestud_io.

Nevertheless, here the server log for a successful request.

Server Log for incoming data

null  
{ description: [ 'hello, this is description speaking' ] }
{ myfile:
    [ { fieldName: 'myfile',
        originalFilename: 'IMG-20150311-WA0000.jpg',
        path: '/var/folders/rq/q_m4_21j3lqf1lw48fqttx_80000gn/T/wcvFPnGewEPCm9IHM7ynAS3I.jpg',
        headers: [Object],
    size: 34287 } ] }

The first null log is the err object. Afterwards the description field and finally myfile.

Questions & Problems

Things went south? Just let us know via @futurestud_io or the comments below and we’ll help you get things working.


Explore the Library

Find interesting tutorials and solutions for your problems.

Miscellaneous