가능한 한 통속적이고 알기 쉽게 강좌를 해설하다

개시하다


두 번째 엔지니어 인턴십으로 골랑+그래픽QL로 개발하기로 했다.
요즘은 이해가 늘었지만 지금까지 REST 이외의 세계를 몰랐던 제게 Gqlgen이 뭘 해줄지, 뭐가 편할지 전혀 두서가 없어서 같은 상황에 처한 사람들을 위해 기사를 쓰고 싶습니다.

전제 지식

  • GraphiQL의 기본 알기
  • Golang의 기본 구문 이해
  • 무엇이 gqlgen입니까?


    공식을 인용하다
    gqlgen is a Go library for building GraphQL servers without any fuss.
    ・gqlgen is based on a Schma first aproach—You get to Define your API using the GraphiQL Schema Definition Language.
    ・gqlgen prioritizes Type safety—You should never see map〔string〕interface{}here.
    ・gqlgen enables Codegen—We generate the boring bits,so you can focus on building your app quickly.
    어쨌든 GraphiQL 서버를 제작할 때'모드 우선'에서'유지형 안전성','자동 생성 코드'의 Golang의 프로그램 라이브러리를 사용할 수 있다.

    목표


    gqlgen 튜토리얼에 따라 간단한 todo 프로그램을 만듭니다.동작은 GraphiQL Playround 확인 형식으로 수행됩니다.
    이번 코드.
    https://github.com/omoterikuto/gqlgen_tutorial

    Let's start!


    일단 준비부터.작업 목록을 만들고 goo의 개발 환경을 조정합시다.이번에 사용golang 1.18.
    mkdir gqlgen_tutorial && cd gqlgen_tutorial
    
    go mod init gqlgen_tutorial
    
    에 이어 이번 주인공 gqlgen 포장과 의존 관계를 담은 내용을 다운로드한다.
    go get -u github.com/99designs/[email protected]
    
    최신 버전의 0.17.5를 사용합니다.
    그러면 다음 명령으로 모형 파일을 만듭니다.
    go run github.com/99designs/gqlgen init
    
    GraphiQL 서버를 아주 간단하게 만들었습니다!디렉토리 구성은 다음과 같이 정상적입니다.

    파일 생성에 대한 설명
  • graph/generated/generated.go
    이 파일은 GraphiQL 서버의 요청graph/resolver.go에 대해 설명하고 적절한 방법으로 부르는 역할을 했다.
  • graph/model/models_gen.go
    schema가 정의한 type과 input을 Golang으로 변환하는 구조체를 정의했습니다.
  • graph/schema.resolver.go
    요청에 따라 실제 처리resolver된 서류를 실시한다.
  • 상기 세 가지는 schema를 변경한 후go run github.com/99designs/gqlgen generate 코드를 실행한 후에 생성된 것이다.
  • graph/resolver.go
    선언은 뿌리로서의 Resolver 구조체이다.다시는 태어나지 않을 겁니다.
  • graph/schema.graphqls
    GraphiQL 모드를 정의하는 파일입니다.이 파일을 토대로 다른 파일을 다시 생성합니다.
  • gqlgen.yml
    gqlgen 설정 파일입니다.이번엔 안 하지만 shcema의 분할 등 설정도 이 파일로 할 수 있다.
  • 우리 얼른 graph/schema.graphqls봅시다.
    # GraphQL schema example
    #
    # https://gqlgen.com/getting-started/
    
    type Todo {
      id: ID!
      text: String!
      done: Boolean!
      user: User!
    }
    
    type User {
      id: ID!
      name: String!
    }
    
    type Query {
      todos: [Todo!]!
    }
    
    input NewTodo {
      text: String!
      userId: String!
    }
    
    type Mutation {
      createTodo(input: NewTodo!): Todo!
    }
    
    기억하지 못하는 scheme가 생성되었다.gqlgen에서 기본적으로 생성된 것입니다.이번에는 이 schema를 바탕으로 간단한 todo 앱을 만들고 싶습니다.
    글의 첫머리에서도 gqlgen은 모델로 우선적으로GraphiQL 서버를 생성한다고 언급했다.코드를 자동으로 생성하거나 Resolver (후술) 를 실행할 때도 이 모드에서 실현됩니다.뜻밖의 오류가 있을 때 이 schema에서 확인하는 것이 좋습니다.
    아래를 보시오graph/model/models_gen.go.
    // Code generated by github.com/99designs/gqlgen, DO NOT EDIT.
    
    package model
    
    type NewTodo struct {
    	Text   string `json:"text"`
    	UserID string `json:"userId"`
    }
    
    type Todo struct {
    	ID   string `json:"id"`
    	Text string `json:"text"`
    	Done bool   `json:"done"`
    	User *User  `json:"user"`
    }
    
    type User struct {
    	ID   string `json:"id"`
    	Name string `json:"name"`
    }
    
    방금 본 schema에서 정의한Query와 Mutation 이외의 유형은 구조체로 정의됩니다.이 파일의 구조체를 사용해서 다음에 설명한 Resolver를 실행합니다.
    마지막으로 보시죠graph/schema.resolver.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"
    	"gqlgen_tutorial/graph/generated"
    	"gqlgen_tutorial/graph/model"
    )
    
    func (r *mutationResolver) CreateTodo(ctx context.Context, input model.NewTodo) (*model.Todo, error) {
    	panic(fmt.Errorf("not implemented"))
    }
    
    func (r *queryResolver) Todos(ctx context.Context) ([]*model.Todo, error) {
    	panic(fmt.Errorf("not implemented"))
    }
    
    // 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 }
    
    이상한 방법이 생겼어요.주의해야 할 것은 CreateTodoTodos이다.이것은 graph/schema.graphqls에서 정의한 것이다
    type Query {
      todos: [Todo!]!
    }
    ...省略
    type Mutation {
      createTodo(input: NewTodo!): Todo!
    }
    
    는 각각 이쪽에 대응한다.gqlgen에서 GraphiQL 서버에 대한 요청/generated/generated.go을 자동으로 생성한 후 이 방법들이 호출되었습니다.그래서 이런 방법들이 이른바 Controller 역할을 했다.
    지금 이 단계에서는 내용이 비어 있고 아무것도 이루어지지 않았기 때문에 지금부터 내용을 실시한다.데이터는 통상적으로 데이터베이스에 영구적으로 저장되지만 동작을 확인하기 위해 먼저 메모리에 데이터를 저장한다.
    우선 변경graph/resolver.go.
    type Resolver struct {
    	todos []*model.Todo // 追加
    }
    
    schema.resolver.goo에서 정의한mutation Resolver와query Resolver는 모두 이 Resolver로 포장된 것이기 때문에 이 Resolver에서 todos를 유지하고 싶습니다.
    다음은 Resolver를 실시합니다.
    func (r *mutationResolver) CreateTodo(ctx context.Context, input model.NewTodo) (*model.Todo, error) {
    	todo := &model.Todo{
    		Text: input.Text,
    		ID:   fmt.Sprintf("T%d", rand.Int()),
    		User: &model.User{ID: input.UserID, Name: "user " + input.UserID},
    	}
    	r.todos = append(r.todos, todo)
    	return todo, nil
    }
    
    func (r *queryResolver) Todos(ctx context.Context) ([]*model.Todo, error) {
    	return r.todos, nil
    }
    
    CreateTodo 방법은 요청된 정보(input model.NewTodo)에서 Todo 모형을 제작하여 Resolver struct에 추가된 todos slice 처리일 뿐이다.Todos 방법은 기존 Resolver struct 내의 todos slice만 반환합니다.
    실제 앱이라면 좀 더 복잡한 논리와 DB 조작이 있을 수 있지만, 이번에는 최대한 최소화하고 싶어서 사랑을 끊었다.
    resolver 설치가 끝났으니까, 야 동작 확인!GraphiQL 서버를 시작합니다.
    방문
    go run server.go
    
    http://localhost:8080/하세요.

    이런 페이지를 보여주면 성공!GraphiQL playground를 사용하면 curl 명령을 특별히 두드리지 않고 앞부분의 동작을 확인할 수 있습니다.
    당장 무테이션 요청해서 토도 만들어봐!다음 요청을 복사하면 화면 왼쪽 상단에 있는 재생 표시가 있습니까?부탁 좀 들어주세요.
    mutation {
      createTodo(input: { text: "todo", userId: "1" }) {
        user {
          id
        }
        text
        done
      }
    }
    
    아래의 답장을 답장하면 정상적으로 제작이 가능합니다!
    {
      "data": {
        "createTodo": {
          "user": {
            "id": "1"
          },
          "text": "todo",
          "done": false
        }
      }
    }
    
    아래에서 제작한 토도를 구해 보세요.
    query {
      todos {
        text
        done
        user {
          name
        }
      }
    }
    
    대박!
    resolver만 설치하면 GraphiQL 서버를 간단하게 만들 수 있습니다.
    그러나 이 점만으로도 GraphiQL의 장점 중 하나는 얻은 데이터를 선택할 수 없다는 것이다.
    예를 들어 현재 이 단계에서 todos를 얻었을 때user를 가져야 한다.당연하다
    이러한 요청을 보내면user 데이터는 응답으로 되돌아오지 않지만 내부에서user 데이터를 얻었습니다.RDB를 자주 사용하는 웹 응용 프로그램에서 todo 모델은 UserID만 있고 링크된user는 대부분 todo와 달리 DB에서 얻는다.이 경우 사용자 데이터가 필요하지 않아도 sql가 필요하지 않습니다.
    이러다가는 그래피큐어의 은혜를 온전히 받아들였다고 할 수는 없다.이것은 실시todoResolver를 통해 해결할 수 있다.여기서부터 수정해.
    우선 새로운 모델 제작Todo struct이 필요하다.현재 상태에서는 schema.graphqls 기반으로 자동 생성된 Todo 모델이 사용됩니다.그러나 이렇게 되면 mutaaionmodels/models_gen.go의 보답치인 Todo모델은 반드시 User를 포함해야 하기 때문에 Todo모델을 새로 정의했다.
    다음 내용을 다시 제작CreateTodo하십시오.
    {
      "data": {
        "todos": [
          {
            "text": "todo",
            "done": false,
            "user": {
              "name": "user 1"
            }
          }
        ]
      }
    }
    
    그 다음은 gqlgen.yml 파일에 다음 내용을 추가합니다.
    query {
      todos {
        text
        done
      }
    }
    
    이로써'todo 모델 사용graph/models/todo.go의 Todo struct'를 지정할 수 있다.
    준비되면 파일을 생성하세요.
    type Todo struct {
        ID     string
        Text   string
        Done   bool
        UserID string
    }
    
    gqlgen_tutorial/graph/model.go를 보십시오.Todo struct가 사라졌네요.이제 방금 정의한 Todo 모델이 사용됩니다.
    그럼 Resolver를 실현하세요.graph/model/models_gen.go를 여십시오.
    Todo struct는 아까 변경된 내용에 따라 schema.resolvers.go 유지User 하기 때문에
    우선 수정UserID.
    models:
      Todo:
        model: gqlgen_tutorial/graph/model.Todo
    
    이전에는 없었던 User 방법
    go run github.com/99designs/gqlgen generate
    
    상기 변경 사항을 추가합니다.
    이게 제가 처음에 이해하기 어려웠던 점이에요.
    todo struct가mutationCreateTodo과queryCreateTodo에 반환되었을 때 schema의 Todos에서 지정한 User 필드에 todo struct가 없기 때문에 todo Resolver에 대한 User 방법을 호출했습니다.
    이렇게 하면 완성된다.마지막 한 번 더
    func (r *mutationResolver) CreateTodo(ctx context.Context, input model.NewTodo) (*model.Todo, error) {
    	todo := &model.Todo{
    		Text:   input.Text,
    		ID:     fmt.Sprintf("T%d", rand.Int()),
    		UserID: input.UserID, // 修正
    	}
    	r.todos = append(r.todos, todo)
    	return todo, nil
    }
    
    를 실행하고 GraphiQL Playground를 통해 동작을 확인하십시오.아까랑 똑같은 행동을 하면 완벽해.

    최후


    어때?이해하기 어려운 점이 많다고 생각해요. 도움이 된다면 영광이에요.
    나는 마음속으로부터 줄곧 불평과 불평을 하고 있다.

    좋은 웹페이지 즐겨찾기