post Image
Firebase Realtime Database を Rest API と Golang でいじってみる

FirebaseのRealtime Databaseは、iOS/Android SDKの他に、RestAPIで直接操作することもできます。リアルタイムの恩恵はないですが、アプリ側だけでなく、サーバ側からもDBにデータを仕込む必要があったので調べてました。オフィシャルではないですがGoのライブラリもあったので使ってみました。:grinning:
それから余談ですが、本日11月7日にベルリンにてFirebaseデブサミがあるようです。GoogleにはDeveloper Advocateという昔でいうエバンジェリストの職種があり、ドキュメントも分かりやすいですし、YouTubeでチュートリアルビデオがみれたり良いですね。アップルにもあると良いですが。(私は別にGoogleとは何の関係もないし、むしろアップル側ですが。:relaxed:)

RestAPI

まず、RestAPIの呼び出しに使用するAUTHトークンを払い出します。

Firebaseコンソールの画面左上のギアアイコンから、Project Settings > SERVICE ACCOUNTS > Database Secretsを選択します。SHOWをクリックするとトークンが表示されますのでコピーしておきます。

0Screen_Shot_2016-11-06_at_21_49_24.jpg

PUT/PATCH/POST/DELETE

更新系のメソッドです。

RestAPIのエンドポイントはURLの最後に、.jsonをつけます。

PUTでJSONノードの書き込み、PATCHでノードを部分的に書き込みます。POSTも書き込みですが、PUTとの違いはFirebaseが自動的にユニークキーを新規作成して登録します。

PUT
$ curl -X PUT -d '{                                                            
  "alanisawesome": {
    "name": "Alan Turing",
    "birthday": "June 23, 1912"
  }
}' 'https://fireblog-89e42.firebaseio.com/fireblog/users.json?auth=xoBbyJxuTryxfGBSP0EhQDKdhTLJIuBNgY4vSSs6'

:warning:以降、簡単のためauthキー省略

コンソールで確認します。
1Firebase_Console.jpg

PATCHで子ノードを追加します。
:warning:ここでPUTを使用すると既存の兄弟ノードが吹っ飛びます。

PATCH
$ curl -X PATCH -d '{                                                         
  "nickname": "Alan The Machine"
}' 'https://fireblog-89e42.firebaseio.com/fireblog/users/alanisawesome.json'

2Firebase_Console.jpg

パスの指定方法には色々あります。

キーに、alanisawesome/nickname
curl -X PATCH -d '{                                   
  "alanisawesome/nickname": "Alan is awesome!"
}' 'https://fireblog-89e42.firebaseio.com/fireblog/users.json'
値を、JSON形式
curl -X PATCH -d '{ 
"alanisawesome": {"nickname": "Alan The Machine"}
}' 'https://fireblog-89e42.firebaseio.com/fireblog/users.json'

ただ最後の例の場合は、既存のnamebirthdayが吹っ飛びます。

最後にPOSTの例です。

POST
curl -X POST -d '{
  "author": "alanisawesome",
  "title": "The Turing Machine"
}' 'https://fireblog-89e42.firebaseio.com/fireblog/posts.json'

5Firebase_Console.jpg

ブログポストpostsのようなトランザクショナルなデータはキーを自動生成させ、ユーザマスタusersのようなものはキーを指定して登録する感じでしょうか?(データ構造はFirebaseのドキュメントに沿ってます。)

GET

GETでデータを取得します。print=prettyをつけるとJSONレスポンスを整形します。

curl 'https://fireblog-89e42.firebaseio.com/fireblog.json?print=pretty'
{
  "posts" : {
    "-KVtoWZ09s5pQGSwFb9w" : {
      "author" : "alanisawesome",
      "title" : "The Turing Machine"
    }
  },
  "users" : {
    "alanisawesome" : {
      "birthday" : "June 23, 1912",
      "name" : "Alan Turing",
      "nickname" : "Alan The Machine"
    }
  }
}

簡単なクエリもサポートしてます。Firebaseのサンプルの恐竜DBを使用します。

身長heightが4メートル以上の恐竜を検索します。(:warning:JSONレスポンス自体はソートされません。)

curl 'https://dinosaur-facts.firebaseio.com/dinosaurs.json?orderBy="height"&startAt=4&print=pretty'

{
  "stegosaurus" : {
    "appeared" : -155000000,
    "height" : 4,
    "length" : 9,
    "order" : "ornithischia",
    "vanished" : -150000000,
    "weight" : 2500
  },
  "bruhathkayosaurus" : {
    "appeared" : -70000000,
    "height" : 25,
    "length" : 44,
    "order" : "saurischia",
    "vanished" : -70000000,
    "weight" : 135000
  }
}

名前がアルファベットのaからmで始まる恐竜さん。

curl 'https://dinosaur-facts.firebaseio.com/dinosaurs.json?orderBy="$key"&startAt="a"&endAt="m"&print=pretty'


{
  "bruhathkayosaurus" : {
    "appeared" : -70000000,
    "height" : 25,
    "length" : 44,
    "order" : "saurischia",
    "vanished" : -70000000,
    "weight" : 135000
  },
  "lambeosaurus" : {
    "appeared" : -76000000,
    "height" : 2.1,
    "length" : 12.5,
    "order" : "ornithischia",
    "vanished" : -75000000,
    "weight" : 5000
  },
  "linhenykus" : {
    "appeared" : -85000000,
    "height" : 0.6,
    "length" : 1,
    "order" : "theropoda",
    "vanished" : -75000000,
    "weight" : 3
  }
}

ただFirebaseのソートは前もってRULEの設定が必要なので少し複雑です。

Goでやって見る

本題のGoです。Justingさんのライブラリがシンプルで使いやすいです。

go get github.com/JustinTulloss/firebase

HTTPメソッドはそれぞれ以下のファンクションでラップされてます。

  • PUT -> Set()
  • PATCH -> Update()
  • POST -> Push()
  • DELETE -> Remove()
  • GET -> Value()

ざっとコードを載せます。

main.go
package main

import (
    "github.com/JustinTulloss/firebase"
    "log"
)

type Name struct {
    First string `json:",omitempty"`
    Last  string `json:",omitempty"`
}

func nameAlloc() interface{} {
    return &Name{}
}

const (
    endpoint = "https://fireblog-89e42.firebaseio.com"     // Firebaseエンドポイント
    auth     = "xoBbyJxuTryxfGBSP0EhQDKdhTLJIuBNgY4vSSs6"  // トークン
)

func main() {

    c := firebase.NewClient(endpoint + "/foo", auth, nil)

    c.Push(&Name{First: "Tim", Last: "Cook"}, nil)   // POSTします。
    c.Push(&Name{First: "Steve", Last: "Jobs"}, nil) // エラー処理は端折ってます。

    // 検索します。
    // イテレータで結果セットを受け取ります。内部でgoroutineが呼ばれ、チャネルが返されます。
    for n := range c.Iterator(nameAlloc) {
        log.Printf("FirstName-LastName: %s - %s", n.Value.(*Name).First, n.Value.(*Name).Last)
    }

    // 次は、Set() PUTでデータを登録します。構造体でなく、mapでもokay
    kids := map[string]map[string]interface{}{
        "a": map[string]interface{}{"Name": "Bob", "Age": 14},
        "b": map[string]interface{}{"Name": "Alice", "Age": 13},
    }

    _, err := c.Set("kids", kids, nil) // PUTします。
    if err != nil {
        log.Fatal(err)
    }
    // 検索します。
    for n := range c.Child("kids").Iterator(nil) {
        log.Printf("--- %s", (*n.Value.(*map[string]interface{}))["Name"])
    }
}

実行します。

$ go run main.go                                                                                     22:52:49  ☁  migrate-cloudinary ☂ ⚡
2016/11/06 22:55:46 FirstName-LastName: Tim - Cook
2016/11/06 22:55:46 FirstName-LastName: Steve - Jobs
2016/11/06 22:55:48 --- Bob
2016/11/06 22:55:48 --- Alice

コンソールで確認します。
9Firebase_Console.jpg

他にもソート機能も実装されてます。Firebaseのレスポンスデータはソートはされていないため、呼び出し側でソートしてあげないといけません。Justinさんのコードはテストケースがしっかり書かれているのでわかりやすいです。
https://github.com/JustinTulloss/firebase/blob/master/firebase_test.go


『 Go 』Article List
Category List

Eye Catch Image
Read More

Androidに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

AWSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Bitcoinに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

CentOSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

dockerに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

GitHubに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Goに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Javaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

JavaScriptに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Laravelに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Pythonに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Rubyに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Scalaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Swiftに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Unityに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Vue.jsに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Wordpressに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

機械学習に関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。