gqlgen 튜토리얼을 시도했습니다.

소개



만나서 반갑습니다, k. s. 로저스 의 니시타니입니다.

최근에는 iOS, Android용 REST API를 개발하고 있습니다.
이 때 화면 묘화용 데이터 취득 API가 350kb 정도의 응답을 반환할 수 있어 결과적으로 앱의 묘화 속도에 영향을 주었습니다.
원인은 응답의 중첩된 Entity 사이즈로, 운용 당초는 데이터량이 적기 때문에 문제는 없었습니다만,
운영하는 동안 데이터가 증가함에 따라 Entity 크기가 늘어났습니다.

이 때의 대응으로서는, 응답으로부터 불필요한 내용을 삭제해, 350kb로부터 20kb까지 줄임으로써 정상화할 수 있었습니다.
그러나, 이번은 우연히 불필요한 데이터였지만 본래는 돌려야 할 내용이므로, 방침으로서 특례를 많이 만들고 싶지 않은 기분이 있었습니다.



응답 크기
응답 속도
앱의 화면 표시까지의 시간


모든 데이터를 반환
350kb
9.5초
15~20초

필요한 데이터만 반환
20kb
2.5초
5초


그래서 각 화면·기능에 필요한 데이터만을 유연하게 취득할 수 있는 GraphQL에 대해 조사했습니다.
본래 GraphQL로 처리 속도가 빨라지는 것은 아니지만, 상기의 경우는 불필요 Entity를 취득하지 않기 때문에, 서버측의 처리 속도 개선을 기대할 수 있다고 생각하고 있습니다.

실수, 조언 등이 있으면 코멘트에서 알려 주시면 좋겠습니다.

왜 gqlgen인가?



첫째, Golang에서 개발하려는 이유가 있습니다.
당사에서는 Golang의 보일러 템플릿(REST, gRPC)을 개발하고 있으며, GraphQL을 채용하게 된 경우는 Golang에서 구현할 가능성이 높습니다.

golang에서 구현 가능한 프레임워크는 여기 을 참고로 했습니다.
당사는 iOS 및 Android 팀과 연계하여 개발을 진행하는 경우가 많기 때문에 스키마 구동 및 문서가 풍부한 gqlgen을 선택했습니다.

환경 구축



공식 튜토리얼에 따라 진행합니다.

우선 프로젝트를 작성합니다.
mkdir gqlgen-todos
cd gqlgen-todos
go mod init github.com/[username]/gqlgen-todos

스키마 파일을 작성합니다.

schema.graphql
# Todoのデータ保持
type Todo {
  id: ID!
  text: String!
  done: Boolean!
  user: User!
}

# Userのデータ保持
type User {
  id: ID!
  name: String!
}

# リクエストの定義(Todo作成)
input NewTodo {
  text: String!
  userId: String!
}

# データ取得APIの定義
type Query {
  todos: [Todo!]!
}

# データ変更APIの定義
type Mutation {
  createTodo(input: NewTodo!): Todo!
}

데이터 취득 관련 API는 Query에, 신규 작성, 갱신, 삭제는 Mutation에 정의하게 됩니다.

프로젝트의 병아리 만들기



스키마 파일을 만든 후에 go run github.com/99designs/gqlgen init에서 병아리를 생성할 수 있습니다.
.
├── generated.go # gqlgenの生成ファイル(基本的に触らない)
├── go.mod 
├── go.sum
├── gqlgen.yml # 設定ファイル
├── models_gen.go # スキーマから生成されたモデル
├── resolver.go # 処理の実装をここに書く
├── schema.graphql
└── server
    └── server.go

서버측 구현



Todo 모델 정의



Todo의 모델을 새로 정의합니다.models_gen.go 에서 자동으로 생성된 모델에는 User도 포함되어 있습니다.
그러나 요청에서 사용자 데이터를 지정할 때만 데이터를 검색하고 싶기 때문에 tot를 재정의합니다.

todo.go
package gqlgen_todos

type Todo struct {
    ID     string
    Text   string
    Done   bool
    UserID string
}

gqlgen.yml에 새로 작성한 tot의 내용을 추가합니다.

gqlgen.yml
schema:
- schema.graphql
exec:
  filename: generated.go
model:
  filename: models_gen.go
resolver:
  filename: resolver.go
  type: Resolver
# 追加
models:
  Todo:
    model: github.com/[username]/gqlgen-todos.Todo

다시 빌드합니다.
go run github.com/99designs/gqlgen

resolvers 구현



현재 사양에서 gqlgen을 실행해도 이미 존재하는 resolver.go를 변경할 수없는 것 같습니다. (대응 예정)
그러므로, 한번 resolver.go 삭제해 재생성합니다.
rm resolver.go
go run github.com/99designs/gqlgen

이것으로 resolver.go 가 최신이 되어 not implemented 의 메소드를 구현해 완료입니다!

resolver.go
package gqlgen_todos

import (
    context "context"
    "fmt"
    "math/rand"
)
// 追加
type Resolver struct {
    todos []*Todo
}

func (r *Resolver) Mutation() MutationResolver {
    return &mutationResolver{r}
}
func (r *Resolver) Query() QueryResolver {
    return &queryResolver{r}
}
func (r *Resolver) Todo() TodoResolver {
    return &todoResolver{r}
}

type mutationResolver struct{ *Resolver }

func (r *mutationResolver) CreateTodo(ctx context.Context, input NewTodo) (*Todo, error) {
    // 追加
    todo := &Todo{
        Text:   input.Text,
        ID:     fmt.Sprintf("T%d", rand.Int()),
        UserID: input.UserID,
    }
    r.todos = append(r.todos, todo)
    return todo, nil
}

type queryResolver struct{ *Resolver }

func (r *queryResolver) Todos(ctx context.Context) ([]Todo, error) {
    // 追加
    return r.todos, nil
}

type todoResolver struct{ *Resolver }

func (r *todoResolver) User(ctx context.Context, obj *Todo) (*User, error) {
    // 追加
    return &User{ID: obj.UserID, Name: "user " + obj.UserID}, nil
}

실행


go run server/server.go 에서 모의 ​​서버가 시작되고 http://localhost:8080/ 에서 테스트할 수 있습니다.

후에는 다음과 같이 Todo 추가와 목록 취득을 할 수 있습니다.





결론



이번에는 gqlgen 공식 튜토리얼을 시도해 보았습니다.
현재는 심플합니다만, 실용에 있어서는 대응해야 할 과제가 많이 있다고 생각합니다.
앞으로도 시간을 찾아 조사를 진행하고 싶습니다.

Wantedly에서도 블로그 게시



Tech 블로그에 더해 회사 블로그 등도 하고 있으므로, 신경이 쓰이는 분은 꼭 들여다 봐 주세요.
htps //w w. 와서 dly. 코 m / 코 m 파니에 s / ks 로즈 rs

좋은 웹페이지 즐겨찾기