LoginSignup
4
5

More than 3 years have passed since last update.

nowで作成したAPIをKotlinとRetrofitとRxJavaとJacksonでGET/POSTする

Last updated at Posted at 2018-01-31

いつもAndroidでRetrofit+RxJavaを使ってAPI通信する処理を書いてるが、今回はKotlinで挑戦してみる。
ついでに、使ったことのないnowもJacksonも触ってみた。

作成するもの

  • nowを使ったnodejs製のAPIモック(express)
  • Androidアプリ(Kotlin/Retrofit/RxJava/Jackson)

環境

  • macOS Sierra
  • kotlin_version = '1.2.21'
  • Android Studio 3.0.1
  • node v9.4.0

API

準備

APIモックをexpressを使ったnodejsで作成し、nowにデプロイしていく。
nowについてはこの記事を参考にした。
以下、作業ログ


// APIモックのプロジェクト準備
$ mkdir try-now && cd try-now
// package.json作成
$ npm init -y
// expressを追加
$ npm i -S express
// apiの処理を書くjsを作成
$ touch index.js

// nowのインストール
$ npm i -G now
// nowのログイン(メールアドレスを入力すると確認メールが届くのでverifyする)
$ now login

実装

index.jsに以下を貼り付ける。
レスポンス変数は適当に作った。

index.js
var express = require('express')
var app = express()

app.get('/', function (req, res) {
  const json = {
    status: 1,
    card_status: 10,
    card_type: 'normal',
    card_id: "ca1111",
  }
  res.json(json)
})

app.post('/', function (req, res) {
  const json = {
    status: 2,
    card_status: 20,
    result_code: 1
  }
  res.json(json)
})

app.listen(3000)

ポートは3000を指定してるけど、なくても良い。

これでAPIモックはできあがった。

$ node index.js

としてローカルでも使えるが、今回はnowにデプロイする

デプロイ

nowでデプロイ、超簡単

$ now

https://try-now-kplvmhijbn.now.shというアドレスが表示されたので、これをAPIモックとして利用できる。

このアドレスに対してgetやpostをしていく。

Androidアプリ

使用するライブラリ

app/build.gradleに以下のライブラリ達を追加する

app/build.gradle
    // Retrofit2
    implementation 'com.squareup.retrofit2:retrofit:2.3.0'
    implementation 'com.squareup.retrofit2:converter-jackson:2.3.0'
    implementation 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'

    // RxJava2
    implementation "io.reactivex.rxjava2:rxjava:2.1.9"

    // RxAndroid
    implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'

    // Jackson
    implementation 'com.fasterxml.jackson.core:jackson-core:2.9.4'
    implementation 'com.fasterxml.jackson.core:jackson-databind:2.9.4'
    implementation 'com.fasterxml.jackson.core:jackson-annotations:2.9.4'
    implementation "com.fasterxml.jackson.module:jackson-module-kotlin:2.9.4"

ソース:https://github.com/ikemura23/try-now

実装

Retrofitのインタフェースを作成。
戻り値はRxjavaのObservableにする。

ApiService.kt
interface ApiService {
    @POST("/")
    fun post(): Observable<PostResponse>

    @GET("/")
    fun get(): Observable<GetResponse>
}

APIクライアントを作成していく。
今回、baseUrlにはnowで作成したurlを設定する。

class ApiClient {
    var apiService: ApiService

    init {
        val retrofit: Retrofit = Retrofit.Builder()
                .baseUrl("https://try-now-kplvmhijbn.now.sh")
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .addConverterFactory(JacksonConverterFactory.create(ObjectMapper()))
                .build()
        apiService = retrofit.create(ApiService::class.java)
    }

    /**
     * GETリクエスト
     */
    fun get(): Observable<GetResponse> =
            apiService.get()

    /**
     * POSTリクエスト
     */
    fun post(): Observable<PostResponse> =
            apiService.post()
}

APIクライアント呼び出しは以下
ラムダ初めて触った、すごい

  // get
        apiClient.post()
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(Schedulers.io())
                .subscribe(
                        { res -> Log.d(TAG, res.toString()) },
                        { error -> Log.e(TAG, "{$error.message}") },
                        { Log.d(TAG, "post completed") }
                )

  // post
        apiClient.post()
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(Schedulers.io())
                .subscribe(
                        { res -> Log.d(TAG, res.toString()) },
                        { error -> Log.e(TAG, "{$error.message}") },
                        { Log.d(TAG, "post completed") }
                )

モデルについては、
Response(共通レスポンス)を継承した各モデルが存在するイメージで作成した。

Response.kt
/**
 * 共通レスポンス
 */
open class Response(

        @field:JsonProperty("status") val status: Int = 0,
        @field:JsonProperty("card_status") val cardStatus: Int = 0
)
GetResponse
/**
 * GETレスポンスのモデル
 */
data class GetResponse(
        @field:JsonProperty("card_type") val cardType: String = "",
        @field:JsonProperty("card_id") val cardId: String = ""
) : Response() {
    override fun toString(): String =
            "GetResponse(status='$status' cardStatus='$cardStatus' cardType='$cardType', cardId='$cardId')"
}

kotlin: PostResponse
/**
* POSTレスポンスのモデル
*/
data class PostResponse(
@field:JsonProperty("card_type") val cardType: String = "",
@field:JsonProperty("card_id") val cardId: String = "",
@field:JsonProperty("result_code") val resultCode: Int = 0
) : Response() {
override fun toString(): String =
"PostResponse(status='$status' cardStatus='$cardStatus' resultCode='$resultCode')"
}

この継承してるあたり、もうちょいうまくできないだろうか。

ビルドして実際に動作させると、Logcatに以下のログが表示されていればGET/POSTが成功している

getのログ
D/AppCompatActivity: GetResponse(status='1' cardStatus='10' cardType='normal', cardId='ca1111')
D/AppCompatActivity: get completed

postのログ
D/AppCompatActivity: PostResponse(status='2' cardStatus='20' resultCode='1')
D/AppCompatActivity: post completed

ソース:https://github.com/ikemura23/Kotlin-Jackson-Sample

ハマったところ

Jacksonが@JsonPropertyを認識してくれない

APIレスポンスをJacksonでシリアライズする際、共通レスポンスモデルであるResponse.ktがKotlin用のアノテーションでないとエラーになる。

Jacksonがエラーが継承元の変数を@JsonPropertyだと認識してくれなかった。
継承先は@JsonPropertyでも大丈夫なのに…

NG : @JsonProperty
OK : @field:JsonProperty

実際のコード

Response.kt
/**
 * 共通レスポンス
 */
open class Response(
        // NG
        //@JsonProperty("status") val status: Int = 0,
        //@JsonProperty("card_status") val cardStatus: Int = 0

        // OK
        @field:JsonProperty("status") val status: Int = 0,
        @field:JsonProperty("card_status") val cardStatus: Int = 0
)

同様の問題が起きてないか調べたところ、以下のリンクに辿り着き、kotlinアノテーションを使うことで解決できた。
- https://github.com/FasterXML/jackson-module-kotlin/issues/56#issuecomment-321932309
- https://github.com/FasterXML/jackson-module-kotlin/issues/98#issuecomment-352016501

感想

nowが楽すぎてすごい

kotlinだとJavaよりコード量少なくて楽で良い

4
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
5