- 投稿日:2020-05-29T11:15:00+09:00
Goの30秒で始められるGraphQLサーバー構築
前提
- dockerとdocker-composeインストール済み
- prisma cli インストール済み
どのような物を作るか?
単純に
Hello World!
などのメッセージ一覧を返したり
メッセージを新規作成したり更新、削除したりといった
GraphQLのCRUD APIサーバーを構築します。gqlkitをgit cloneし、コンテナを起動する
まずは、gqlkitというdockerアプリケーションフレームワークをgit cloneし、コンテナを起動しましょう。
これで、半分は作業が完了しました!git clone git@github.com:gqlkit-lab/gqlkit.git cd gqlkit cp .env.example .env docker-compose up -dPostgreSQLに、データの雛形をマイグレートする
今回、どのようなデータモデルをマイグレートするのかを確認しておきましょう。
gqlkit-server/prisma/schema.prismaを開くと下記のようになっています。
このファイルを編集してprisma migrate
してやる事で
データベースにデータモデルを作ることができます。gqlkit-server/prisma/schema.prismadatasource db { provider = "postgresql" url = "postgresql://postgres:postgres@localhost:5432/postgres?schema=public" } model messages { id String @default(cuid()) @id text String created_at String updated_at String }今回は、このままの内容をマイグレートするのでファイルの内容は編集せず下記を実行します。
これでPostgreSQLにmessages
テーブルが作成されました。prisma migrate save --experimental prisma migrate up --experimentalちなみに
schema.prisma
に書くモデル名の注意点ですが
gqlkitはgormを採用しているので「messages」のように複数形で「s」が最後に来るように気をつけましょう。
2単語以上の場合はsnake_caseで書いてやります。GraphQLサーバーを起動する
次の流れとしては、gqlkit-server/graph/schema.graphqlを編集し
gqlkit-server/graph/schema.resolvers.goにリゾルバを書いていくのですが
gqlkitはデフォルトのサンプルとして
messagesのCRUDサンプルはgqlgenでジェネレート済みとなっています。
なので、ここではさらっと
schema.graphqlの中身とschema.resolvers.goの中身を確認だけしておきます。gqlkit-server/graph/schema.graphqltype Query { readMessages: [Message!]! } type Mutation { createMessage(text: String!): Message! updateMessage(id: ID!, text: String!): Message! deleteMessage(id: ID!): Message! } type Message { id: ID! text: String! created_at: String updated_at: String! }gqlkit-server/graph/schema.resolvers.gopackage graph // This file will be automatically regenerated based on the schema, any resolver implementations // will be copied through when generating and any unknown code will be moved to the end. import ( "context" "fmt" "gqlkit/env" "gqlkit/graph/generated" "gqlkit/graph/model" "time" "github.com/jinzhu/gorm" _ "github.com/lib/pq" uuid "github.com/satori/go.uuid" ) func (r *mutationResolver) CreateMessage(ctx context.Context, text string) (*model.Message, error) { db, err := gorm.Open("postgres", env.DB_CONNECT) defer db.Close() if err != nil { return nil, fmt.Errorf(err.Error()) } id := uuid.Must(uuid.NewV4(), nil) loc, _ := time.LoadLocation("Asia/Tokyo") now := time.Now().In(loc).Format("2006-01-02T15:04:05+09:00") r.message = &model.Message{ ID: id.String(), Text: text, CreatedAt: &now, UpdatedAt: now, } db.Create(&r.message) return r.message, nil } func (r *mutationResolver) UpdateMessage(ctx context.Context, id string, text string) (*model.Message, error) { db, err := gorm.Open("postgres", env.DB_CONNECT) defer db.Close() if err != nil { return nil, fmt.Errorf(err.Error()) } loc, _ := time.LoadLocation("Asia/Tokyo") now := time.Now().In(loc).Format("2006-01-02T15:04:05+09:00") db.Where("id = ?", id).First(&r.messages) r.message = r.messages[0] db.Model(&r.message).Where("id = ?", id).Update("text", text) db.Model(&r.message).Where("id = ?", id).Update("updated_at", now) return r.message, nil } func (r *mutationResolver) DeleteMessage(ctx context.Context, id string) (*model.Message, error) { db, err := gorm.Open("postgres", env.DB_CONNECT) defer db.Close() if err != nil { return nil, fmt.Errorf(err.Error()) } db.Where("id = ?", id).First(&r.messages) r.message = r.messages[0] db.Where("id = ?", id).Delete(&r.messages) return r.message, nil } func (r *queryResolver) ReadMessages(ctx context.Context) ([]*model.Message, error) { db, err := gorm.Open("postgres", env.DB_CONNECT) defer db.Close() if err != nil { return nil, fmt.Errorf(err.Error()) } db.Order("created_at").Find(&r.messages) return r.messages, nil } // Mutation returns generated.MutationResolver implementation. func (r *Resolver) Mutation() generated.MutationResolver { return &mutationResolver{r} } // Query returns generated.QueryResolver implementation. func (r *Resolver) Query() generated.QueryResolver { return &queryResolver{r} } type mutationResolver struct{ *Resolver } type queryResolver struct{ *Resolver }実際に、任意のアプリを開発する際は、
schema.graphql
を編集する
↓
go run github.com/99designs/gqlgen
でリゾルバをジェネレートする
↓
schema.resolvers.go
を編集する
という感じの流れで開発していきます。という事で最後に、下記を実行してGraphQLプレイグラウンドを立ち上げましょう!
http://localhost:8080/ でGraphQLプレイグラウンドが立ち上がっています。cd gqlkit-server go run server.go
まとめ
現在、マークアップエンジニアからwebエンジニアへと
ステップアップ転職を目指しているのですが何を思ったか求人の多いRubyに手を出さず
先にGoに手を出してしまいました。すると、Goのなんと楽にバックエンド開発が終了してしまう事か
これは、下手をするとfirebase + nuxtでアプリ作ってた時以上に楽です。Goに触れたのは幸なのか不幸なのか
その後、Railsの学習に手をつけてみようと何度かトライするのですが
Goの圧倒的すぎるシンプルさ、簡単さ、スッキリさ、に引きずられてしまい
どうしても、わざわざ学ぼうという意欲が出ないでいます。
Laravelも同じく...
求人は多いのに...(泣)
Goめ!実に罪深い!(褒め言葉)
- 投稿日:2020-05-29T02:05:14+09:00
【Golang】interface②タイプアサーション
【Golang】interface②タイプアサーション
Golangの基礎学習〜Webアプリケーション作成までの学習を終えたので、復習を兼ねてまとめていく。 基礎〜応用まで。
package main import ( "fmt" ) //interface2の使い方 func do(i interface{}){ //1 /* //int型に直す。正しければ復元する //タイプアサーション ii := i.(int) // i = ii * 2 ii *= 2 fmt.Println(ii) //str型に直す ss := i.(string) fmt.Println(ss + "!") */ //2 //interfaceをtype毎に条件分岐 vを変換 //スイッチタイプ文 //switch v := i.(type) はセットで覚える(型アサーション) switch v := i.(type) { case int: fmt.Println(v * 2) case string: fmt.Println(v + "!") default: fmt.Printf("%T\n", v) } } func main() { //1 //まだint型でない interface型 var i interface{} = 10 var s interface{} = "Mike" //2 //いろんな型で実行 do(i) //>>20 do(s) //>>Mike! do(true) //>>bool //3 //タイプアサーション、コンバージョン var i2 int = 10 //タイプコンバージョンは書き換える ii := float64(10) fmt.Println(i2, ii) //>>10 10 //タイプアサーション //interfaceの場合の変換 //var i interface{} = 10 //i.(int)で変換する }