LoginSignup
37
32

More than 5 years have passed since last update.

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

Last updated at Posted at 2016-11-06

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

37
32
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
37
32