LoginSignup
1
1

More than 3 years have passed since last update.

Go言語とMongoDBでスキーマレスなデータを管理するAPIをつくってみた。

Last updated at Posted at 2019-08-24

はじめに

こんにちは

必要に迫られてドキュメント型DBの1つであるMongoDBを触らなければならない機会があったのでその共有(今頃?w)

Go言語を例にMongoDBで簡単なAPIをつくってみたいと思います。

MongoDBとのコネクション

ドライバーの導入

MongoDBは独自プロトコルを採用しているため、ドライバーを使う必要があります。

※今回はスター数からこちらのドライバーを使わせて頂くことにしました。
https://github.com/mongodb/mongo-go-driver

※導入方法のざっくりとした説明は前回の記事でまとめております。
https://qiita.com/leica19/items/ccdd2b452477b1ad7aed

Go言語からの接続

必要なパッケージはこちら

db/main.go
import (
    "context"
    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/mongo/options"
)

実コードはこの2行で完結します。

db/main.go
    clientOptions := options.Client().ApplyURI("mongodb://db")
    client, _ := mongo.Connect(context.TODO(), clientOptions)

ApplyURI()の引数にある「db」がhostとなりますが、今回はdocker-composeを利用しているため「db」という名前でアクセスすることができます。

見栄えよく関数化すると

db/main.go
func ConnectMongoDB() *mongo.Client {
    clientOptions := options.Client().ApplyURI("mongodb://db")
    client, err := mongo.Connect(context.TODO(), clientOptions)
    if err != nil {
        log.Fatal(err)
    }
    return client
}

こんな感じでしょうか。

コレクションの作成

次にコレクションを作成する必要があります。
※コレクションとはドキュメントの集合単位です。

コレクションの作成にはmongo.ClientのCollectionメソッドが使えます。
戻り値としてmongo.Collectionのハンドラーが返ってきます。
※今後は主にこのハンドラーを使ってコレクションを操作していくことになります。

db/main.go
    collection := client.Database("test").Collection("users")

今回は"users"という名前のコレクションを作成しています。

ドキュメントの新規作成

POSTのエンドポイントを経由してusersコレクションに新規ドキュメントを登録してみます。
JSONをPOSTできるようにします。

以下、ルーティングとハンドラー

main.go
    e.POST("/user", func(c echo.Context) error {
        jsonBody := echo.Map{}
        if err := c.Bind(&jsonBody); err != nil {
            errorResponse := ErrorResponse{Message: "Bad Request"}
            return c.JSON(http.StatusBadRequest, errorResponse)
        }
        result, _ := collection.InsertOne(context.TODO(), jsonBody)
        response := Response{ID: result.InsertedID}
        return c.JSON(http.StatusOK, response)
    })

リクエストのBodyパラメーターをc.Bind()でGo言語のmapにマッピングしております。
※Web frameworkとしてEchoを使っています。https://echo.labstack.com/guide
レコードの新規作成には、InsertOneメソッドを利用しています。

さっそく登録してみます。

Screenshot from 2019-08-24 18-17-57.png

レスポンスにはドキュメントのIDであるObjectIdを返しています。

ドキュメントの参照

続いて、先ほど登録したドキュメントがきちんと登録されているかGETリクエストで確認してみます。

ハンドラーから

main.go
    e.GET("/user/:_id", func(c echo.Context) error {
        raw_id := c.Param("_id")
        _id, _ := primitive.ObjectIDFromHex(raw_id)
        result := echo.Map{}
        if err := collection.FindOne(context.TODO(), bson.M{"_id": _id}).Decode(&result); err != nil {
            errorResponse := ErrorResponse{Message: "Not Found"}
            return c.JSON(http.StatusNotFound, errorResponse)
        }
        return c.JSON(http.StatusOK, result)
    })

ポイントは、primitiveパッケージのObjectIDFromHex関数を使って、
16進数の文字列できたObjectIdを正しいObjectIdに変換する処理を挟むところです。
※内部的なことはよくわかってません。すみません。

ObjectIdをリクエストパスに入れてGETすると

Screenshot from 2019-08-24 18-18-11.png

先ほどPOSTしたJSONが正しく返ってきています。

ドキュメントの削除

最後に削除です。

特に目立ったところはありませんが、ハンドラーは

main.go
    e.DELETE("/user/:_id", func(c echo.Context) error {
        raw_id := c.Param("_id")
        _id, _ := primitive.ObjectIDFromHex(raw_id)
        result, _ := collection.DeleteOne(context.TODO(), bson.M{"_id": _id})
        return c.JSON(http.StatusOK, result)
    })

仮実装なので、DeleteOneメソッドの戻り値をそのままレスポンスしています。。
リクエストパスにObjectIdを入れて、DELETEメソッドでリクエストすればドキュメントが削除されます。

Screenshot from 2019-08-24 18-18-22.png

一応GETでも確認

Screenshot from 2019-08-24 18-18-29.png

きちんとドキュメントが削除されています。

最後に

今回は非常にあっさりしたものですが、今後はmongoのクエリにも詳しくなりたいな。というかならなくちゃ。

読んで頂き、ありがとうございました。

今回のソースコードはこちらで公開しております。
https://github.com/leica19/go-mongo-sample-api

参考

1
1
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
1
1