読者です 読者をやめる 読者になる 読者になる

tumblr

tumblr(タンブラー)は、メディアミックスブログサービス。ブログとミニブログ、そしてソーシャルブックマークを統合したマイクロブログサービスである。アメリカのDavidville.inc(現: Tumblr, Inc.)により2007年3月1日にサービスが開始された。

retrofitでマルチパートなものをPOSTする

retrofitはHTTPクライアントだけあって当然formの要素や画像のようなマルチパートなものもPOSTできるのだけど、その方法があんまり見つからなかったので覚書。見つからなかったというよりか、現状の最新安定バージョンの2.0でのPOSTの方法と過去のバージョン1.9での方法がかなり違う上に1.9での情報ばっかりがあふれていたので見つけにくかった…というだけだったのだけど。

概要

1.9ではTypedFileというクラスを使ってそれに画像なり何なりをいれてPOSTするのだけど、2.0ではRequestBodyにPOSTしたい要素を入れるようにする。 インターフェース部分は以下のように。@Multipartアノテーションと@Partアノテーションを使う。@Partアノテーションをつけた引数としてRequestBodyを指定する。

public interface FileUploadService {  
    @Multipart
    @POST("/upload")
    Call<String> upload(
            @Part("file") RequestBody file
    );
}

で、使う場合は以下のようにする。RequestBodyのインスタンスを生成する時に、MediaTypeを指定する必要がある。

FileUploadService service = ServiceGenerator.createService(FileUploadService.class);

File file = new File("path/to/your/file");  
RequestBody requestBody = RequestBody.create(MediaType.parse("multipart/form-data"), file);

Call<String> call = service.upload(requestBody);  
call.enqueue(new Callback<String>() {  
    //...
});

たくさんの要素をPOSTしたい

formと言っても要素は複数あるとか、画像1枚だけじゃなくて複数枚POSTしたいという場合はPartMapを使う。 @Partアノテーションでなく、@PartMapアノテーションを使う。そして引数はその名の通りMap。

public interface FileUploadService {  
    @Multipart
    @POST("/upload")
    Call<String> upload(
            @PartMap Map<String, RequestBody> params
    );
}
FileUploadService service = ServiceGenerator.createService(FileUploadService.class);

Map<String, RequestBody> requestParams = new HashMap<>();

File file1 = new File("path/to/your/file1");  
RequestBody requestBody1 = RequestBody.create(MediaType.parse("multipart/form-data"), file1);

File file1 = new File("path/to/your/file2");  
RequestBody requestBody2 = RequestBody.create(MediaType.parse("multipart/form-data"), file2);

requestParams.put("files[]", requestBody1);
requestParams.put("files[]", requestBody2);

Call<String> call = service.upload(requestParams);  
call.enqueue(new Callback<String>() {  
    //...
});

という感じで本当にMapライクに使えるので便利

@Bodyと併用は出来ない

以下のようなインターフェースを書いてたらエラーが出た。

public interface FileUploadService {  
    @Multipart
    @POST("/upload")
    Call<String> upload(
            @Body ItemEntity item,
            @PartMap Map<String, RequestBody> params
    );
}

ItemEntityはjavaのオブジェクト<=>jsonの変換をしている。json<=>javaオブジェクトのコンバーターが絡む@Bodyとコンバートをしない@Partおよび@PartMapではうまくいかないみたい。なのでどっちかにする必要がある。画像をあげる必要があるなら@Partを素直に使ったほうが楽かもしれない。@Bodyだとfileはそのままjson変換されたらおかしくなるためbase64エンコードするとか色々面倒事があるので…

参考 :

Retrofit 2 — How to Upload Files to Server

How to Upload a File using Retrofit 2.0 · Issue #1063 · square/retrofit · GitHub