LoginSignup
3
0

More than 1 year has passed since last update.

InfluxDBからKotlinで公式SDKを使わず値を読み取る

Last updated at Posted at 2021-12-13

この記事は、ゆめみ Advent Calendar 2021 の14日目の記事です。

概要

個人プロジェクトでInfluxDBを読み取るAndroidアプリをKMMで作ろうとした。
しかし、InfluxDBの公式SDKを追加すると、エラーでビルドができなくなってしまった。

色々調べた結果、KMMでは公式SDKが使えない事が分かった。

なぜ公式SDKを使わないのか?

GitHubで公式SDKである influxdb-client-kotlin を見ると、Java版をKotlinでwrapしているだけだった。

その何が問題かというと、KMMでKotlin SDKが使えない のである。
(KMMではJavaライブラリは使えず、全てKotlinで書かれたライブラリしか使えない)

InfluxDB APIを使えばいけそう

公式SDKを使わずAPIで値を取れないかと調べたところ、
「InfluxDB APIでFluxクエリーを使えば取得できる」という情報を見つけた。

Query with the InfluxDB API

このページを見て驚いたのは以下の2つ
* レスポンスがCSV形式である
* Fluxクエリを送信する必要がある

「え?CSVなの・・・?」
「Fluxクエリってなに・・・」

という驚きを今でも覚えている。
(Jsonが良かったな...)

InfluxDBから値を取得できたコード

以下が公式SDKを使わず、Kotlin値を取得できたコードである。

Ktor Clinetを使ってAPI通信している。

    // APIクライアント
    private val client: HttpClient by lazy {
        HttpClient(CIO) {
            defaultRequest {
                headers {
                    append(HttpHeaders.ContentType, "application/json")
                    append(HttpHeaders.Authorization, "Token ${InfluxCloudApiConfig.TOKEN}")
                    append(HttpHeaders.Accept, "application/csv")
                }
                url(InfluxCloudApiConfig.URL) // API URLは固定
            }
        }
    }

    // API通信処理
    suspend fun fetchInfluxDB(): String {
        // kotlinx.serializationでFluxクエリをJsonにする
        val json = Json.encodeToString(Query(query = firstRowQuery, org = InfluxCloudApiConfig.ORG))
        // InfluxDBにAPI通信スタート
        val response: HttpResponse = client.post {
            body = json
        }
        // レスポンス文字列を取得
        val stringBody: String = response.receive()
        println(stringBody) // CSVが表示される

        // あとはCSVをModelクラスに変換したりする
        return  stringBody
    }

/**
 * Queryクラス
 * FluxクエリをJsonに変換するクラス
 */
@Serializable
internal class Query(
    // 登録メールアドレス
    val org: String,
    // Fluxクエリ
    val query: String,
)
// Flux Query
private val firstRowQuery = """
from(bucket: "dev")
  |> range(start: -12h)
  |> filter(fn: (r) => r.location == "BedRoom" )
  |> filter(fn: (r) => r["_field"] == "pressure" or r["_field"] == "temperature" or r["_field"] == "humidity")
  |> sort(columns: ["_time"], desc: true)
  |> first()
""".trimIndent()

Flux Queryを軽く説明しておくと

  • GraphQLのようにクライアント側で取得する値を指定できる
  • |>のパイプ演算子?で取得した値を任意の条件で絞り込める
  • 上記のクエリだと「12時間前のデータを、指定した値に絞り込み、途中で並び替えて、最後に1件に絞る」

感想

  • とりあえず目的は達成できたので良かった。
  • InfluxDBの公式SDKのKotlin版がとても微妙なので、これを機にKotlinライブラリを作ってもいいかもしれない。
  • Fluxクエリは初めて使ったが、なかなか慣れない
  • ここまで書いておいてアレだが、クライアント側でInfluxDBを直接参照せず、Lambda等でCSV→Jsonに変換する処理を挟んだほうがい絶対にいい。 CSVの変換が超絶めんどくさすぎる...
    • その時にこそ、この記事のコードが役立つと思う。
3
0
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
3
0