protocol buffersとは
API通信などで、Jsonのようなテキスト形式で通信を行わずに、protocol buffersはバイナリ形式で通信を行います。
proto file(事前にスキーマを定義するファイル)から、サーバー側とクライアント側に、シリアライズ・デシリアライズ用のファイルを書き出し、それらを利用してデータの送受信を行います。
proto fileの定義
今回は都道府県のリストを返すAPIを作成して行きたいと思います。
まず、以下のようにproto fileを定義して行きいます。
syntax = "proto3";
option java_package = "com.takusemba.gouda.protos";
option java_outer_classname = "Prefectures";
option go_package = "proto";
package prefectures;
message Prefecture {
int64 id = 1; // ID
string name = 2; // 名前
string romaji = 3; // 読み方(ローマ字)
}
message GetPrefecturesResponse {
repeated Prefecture prefectures = 1;
}
実際のprotoのコードはこちらに上がっています。
Protoからjavaのfileを書き出す
先ほど定義したproto fileから、client側のシリアライズ・デシリアライズ用のファイルを書き出します。
こちらのsquare製のwireを使って書き出していきます。
https://github.com/square/wire
read.meからjarファイルをダウンロードして、protoを定義したフォルダに入れます。
その後以下のコマンドでjavaファイルが書き出せます。
java -jar wire-compiler-VERSION-jar-with-dependencies.jar \
--proto_path=your/proto/path \
--java_out=your/output/path
実行するとこのようなファイルが書き出されると思います。
ProtoでAPI通信を行う
必要なライブラリをgradleに追加
// retrofit
compile "com.squareup.retrofit2:retrofit:$retrofitVersion"
compile "com.squareup.retrofit2:adapter-rxjava2:$retrofitVersion"
compile "com.squareup.retrofit2:converter-wire:$retrofitVersion"
compile "com.squareup.okhttp3:logging-interceptor:$okhttpVersion"
compile "com.squareup.okhttp3:okhttp:$okhttpVersion"
retrofitのclientを定義
今回はkotlinを使って書いていきます。
private val okHttpClient: OkHttpClient = OkHttpClient
.Builder()
.addNetworkInterceptor(HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.HEADERS))
.connectTimeout(15, TimeUnit.SECONDS)
.readTimeout(15, TimeUnit.SECONDS)
.writeTimeout(15, TimeUnit.SECONDS)
.build()
private val protoRetrofit: Retrofit = Retrofit
.Builder()
.baseUrl(endpoint)
.client(okHttpClient)
.addConverterFactory(WireConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build()
インターフェースを定義
レスポンスの型は生成されたptoroの型(ここではGetPrefecturesResponse)にします。
interface Service {
@GET("prefectures") fun getProtoPrefectures(): Single<GetPrefecturesResponse>
}
APIを叩く
fun getProtoPrefectures(): Single<List<Prefecture>> {
return protoRetrofit
.create(Service::class.java)
.getProtoPrefectures()
.map(GetPrefecturesResponse::prefectures)
.map {
val prefectures: ArrayList<Prefecture> = ArrayList()
it.mapTo(prefectures) { value ->
Prefecture().apply {
id = value.id
name = value.name
romaji = value.romaji
}
}
prefectures.toList()
}
}
//APIを叩く
apiClient.getProtoPrefectures()
.doOnSubscribe({ disposables.add(it) })
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
Timber.d("success: " + it?.toString())
},
{
Timber.d("error: " + it.message)
}
)
実際のコードは、こちらのレポジトリ
で公開しているので、ぜひ見て見てくだい。