20200529のGoに関する記事は2件です。

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

PostgreSQLに、データの雛形をマイグレートする

今回、どのようなデータモデルをマイグレートするのかを確認しておきましょう。
gqlkit-server/prisma/schema.prismaを開くと下記のようになっています。
このファイルを編集してprisma migrateしてやる事で
データベースにデータモデルを作ることができます。

gqlkit-server/prisma/schema.prisma
datasource 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.graphql
type 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.go
package 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め!実に罪深い!(褒め言葉)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【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)で変換する

}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む