チュートリアル
https://zenn.dev/hsaki/books/golang-graphql/viewer/tutorial
既存環境削除
% brew remove go # GOROOT設定されているか確認 $ echo $GOROOT # 設定されていたらディレクトリ削除、GOROOT設定されていない場合は不要 $ rm -rf $GOROOT # GOPATH設定されているか確認 $ echo $GOPATH # 設定されていたらディレクトリ削除、GOPATH設定されていない場合は不要 $ rm -rf $GOPATH 環境変数削除 # GOROOT,GOPATHの設定箇所削除 $ vi ~/.zshrc % brew uninstall goenv
$ brew install --HEAD goenv % goenv -v goenv 2.0.6
$ brew update && brew upgrade goenv $ cd $GOENV_ROOT $ git pull origin master インストールできるバージョン確認 $ goenv install -l バージョンを指定してインストール $ goenv install 1.18
$ goenv global 1.18.10 goenv2系の場合 $ vi ~/.zshrc 以下を追記 export GOENV_ROOT="$HOME/.goenv" export PATH="$GOENV_ROOT/bin:$PATH" eval "$(goenv init -)" export PATH="$GOROOT/bin:$PATH" export PATH="$PATH:$GOPATH/bin" $ source ~/.zshrc
% cd /Users/kanehiroyuu/Documents/develop.nosync/study-graphql % go install github.com/99designs/gqlgen@latest % gqlgen version v0.17.30 % go mod init my_gql_server go: /Users/kanehiroyuu/Documents/develop.nosync/study-graphql/go.mod already exists % go get -u github.com/99designs/gqlgen サンプルアプリ作成 % gqlgen init % go mod tidy
Query query { todos { id text done user { name } } } Response { "data": { "todos": [ { "id": "TODO-1", "text": "My Todo 1", "done": true, "user": { "name": "hsaki" } }, { "id": "TODO-2", "text": "My Todo 2", "done": false, "user": { "name": "hsaki" } } ] } }
もくじ
参考になった
・Interfaceはメソッドの塊です。
・Interfaceが期待するメソッド(例ではFuncA,FuncB)をすべて満たした変数には、自動的にInterfaceが実装されます。
・Interfaceを満たした変数はInterfaceへ代入することができます。https://cloudsmith.co.jp/blog/backend/go/2021/08/1847845.html
type Hoge interface { FuncA() FuncB() } type Foo struct {} func (f *Foo) FuncA() {} func (f *Foo) FuncB() {} func main() { var hoge Hoge hoge = Foo{..} // HogeインターフェースにFoo構造体を代入できる }
https://github.com/saki-engineering/graphql-sample/blob/main/graph/services/users.go
package services import ( "context" "github.com/saki-engineering/graphql-sample/graph/db" "github.com/saki-engineering/graphql-sample/graph/model" "github.com/volatiletech/sqlboiler/v4/boil" "github.com/volatiletech/sqlboiler/v4/queries/qm" ) type userService struct { exec boil.ContextExecutor } func convertUser(user *db.User) *model.User { return &model.User{ ID: user.ID, Name: user.Name, } } func convertUserSlice(users db.UserSlice) []*model.User { result := make([]*model.User, 0, len(users)) for _, user := range users { result = append(result, convertUser(user)) } return result } func (u *userService) GetUserByID(ctx context.Context, id string) (*model.User, error) { user, err := db.FindUser(ctx, u.exec, id, db.UserTableColumns.ID, db.UserTableColumns.Name, ) if err != nil { return nil, err } return convertUser(user), nil } func (u *userService) GetUserByName(ctx context.Context, name string) (*model.User, error) { user, err := db.Users( qm.Select(db.UserTableColumns.ID, db.UserTableColumns.Name), db.UserWhere.Name.EQ(name), // qm.Where("name = ?", name), ).One(ctx, u.exec) if err != nil { return nil, err } return convertUser(user), nil } func (u *userService) ListUsersByID(ctx context.Context, IDs []string) ([]*model.User, error) { users, err := db.Users( qm.Select(db.UserTableColumns.ID, db.UserTableColumns.Name), db.UserWhere.ID.IN(IDs), ).All(ctx, u.exec) if err != nil { return nil, err } return convertUserSlice(users), nil }
https://github.com/saki-engineering/graphql-sample/blob/main/graph/services/service.go
package services import ( "context" "github.com/saki-engineering/graphql-sample/graph/model" "github.com/volatiletech/sqlboiler/v4/boil" ) //go:generate mockgen -source=$GOFILE -package=$GOPACKAGE -destination=../../mock/$GOPACKAGE/service_mock.go type Services interface { UserService RepoService IssueService PullRequestService ProjectService ProjectItemService } type UserService interface { GetUserByID(ctx context.Context, id string) (*model.User, error) GetUserByName(ctx context.Context, name string) (*model.User, error) ListUsersByID(ctx context.Context, IDs []string) ([]*model.User, error) } type RepoService interface { GetRepoByID(ctx context.Context, id string) (*model.Repository, error) GetRepoByFullName(ctx context.Context, owner, name string) (*model.Repository, error) } type IssueService interface { GetIssueByID(ctx context.Context, id string) (*model.Issue, error) GetIssueByRepoAndNumber(ctx context.Context, repoID string, number int) (*model.Issue, error) ListIssueInRepository(ctx context.Context, repoID string, after *string, before *string, first *int, last *int) (*model.IssueConnection, error) } type PullRequestService interface { GetPullRequestByID(ctx context.Context, id string) (*model.PullRequest, error) GetPullRequestByRepoAndNumber(ctx context.Context, repoID string, number int) (*model.PullRequest, error) ListPullRequestInRepository(ctx context.Context, repoID string, after *string, before *string, first *int, last *int) (*model.PullRequestConnection, error) } type ProjectService interface { GetProjectByID(ctx context.Context, id string) (*model.ProjectV2, error) GetProjectByOwnerAndNumber(ctx context.Context, ownerID string, number int) (*model.ProjectV2, error) ListProjectByOwner(ctx context.Context, ownerID string, after *string, before *string, first *int, last *int) (*model.ProjectV2Connection, error) } type ProjectItemService interface { GetProjectItemByID(ctx context.Context, id string) (*model.ProjectV2Item, error) ListProjectItemOwnedByProject(ctx context.Context, projectID string, after *string, before *string, first *int, last *int) (*model.ProjectV2ItemConnection, error) ListProjectItemOwnedByIssue(ctx context.Context, issueID string, after *string, before *string, first *int, last *int) (*model.ProjectV2ItemConnection, error) ListProjectItemOwnedByPullRequest(ctx context.Context, pullRequestID string, after *string, before *string, first *int, last *int) (*model.ProjectV2ItemConnection, error) AddIssueInProjectV2(ctx context.Context, projectID, issueID string) (*model.ProjectV2Item, error) AddPullRequestInProjectV2(ctx context.Context, projectID, pullRequestID string) (*model.ProjectV2Item, error) } type services struct { *userService *repoService *issueService *pullRequestService *projectService *projectItemService } func New(exec boil.ContextExecutor) Services { return &services{ userService: &userService{exec: exec}, repoService: &repoService{exec: exec}, issueService: &issueService{exec: exec}, pullRequestService: &pullRequestService{exec: exec}, projectService: &projectService{exec: exec}, projectItemService: &projectItemService{exec: exec}, } }