github.com/animeshon/gqlgen@v0.13.1-0.20210304133704-3a770431bb6d/docs/content/getting-started.md (about)

     1  ---
     2  linkTitle: Getting Started
     3  title: Building GraphQL servers in golang
     4  description: Get started building type-safe GraphQL servers in Golang using gqlgen
     5  menu: main
     6  weight: -7
     7  ---
     8  
     9  This tutorial will take you through the process of building a GraphQL server with gqlgen that can:
    10  
    11   - Return a list of todos
    12   - Create new todos
    13   - Mark off todos as they are completed
    14  
    15  You can find the finished code for this tutorial [here](https://github.com/vektah/gqlgen-tutorials/tree/master/gettingstarted)
    16  
    17  ## Setup Project
    18  
    19  Create a directory for your project, and initialise it as a Go Module:
    20  
    21  ```sh
    22  $ mkdir gqlgen-todos
    23  $ cd gqlgen-todos
    24  $ go mod init github.com/[username]/gqlgen-todos
    25  $ go get github.com/99designs/gqlgen
    26  ```
    27  
    28  ## Building the server
    29  
    30  ### Create the project skeleton
    31  
    32  ```bash
    33  $ go run github.com/99designs/gqlgen init
    34  ```
    35  
    36  This will create our suggested package layout. You can modify these paths in gqlgen.yml if you need to.
    37  ```
    38  ├── go.mod
    39  ├── go.sum
    40  ├── gqlgen.yml               - The gqlgen config file, knobs for controlling the generated code.
    41  ├── graph
    42  │   ├── generated            - A package that only contains the generated runtime
    43  │   │   └── generated.go
    44  │   ├── model                - A package for all your graph models, generated or otherwise
    45  │   │   └── models_gen.go
    46  │   ├── resolver.go          - The root graph resolver type. This file wont get regenerated
    47  │   ├── schema.graphqls      - Some schema. You can split the schema into as many graphql files as you like
    48  │   └── schema.resolvers.go  - the resolver implementation for schema.graphql
    49  └── server.go                - The entry point to your app. Customize it however you see fit
    50  ```
    51  
    52  ### Define your schema
    53  
    54  gqlgen is a schema-first library — before writing code, you describe your API using the GraphQL
    55  [Schema Definition Language](http://graphql.org/learn/schema/). By default this goes into a file called
    56  `schema.graphql` but you can break it up into as many different files as you want.
    57  
    58  The schema that was generated for us was:
    59  ```graphql
    60  type Todo {
    61    id: ID!
    62    text: String!
    63    done: Boolean!
    64    user: User!
    65  }
    66  
    67  type User {
    68    id: ID!
    69    name: String!
    70  }
    71  
    72  type Query {
    73    todos: [Todo!]!
    74  }
    75  
    76  input NewTodo {
    77    text: String!
    78    userId: String!
    79  }
    80  
    81  type Mutation {
    82    createTodo(input: NewTodo!): Todo!
    83  }
    84  ```
    85  
    86  ### Implement the resolvers
    87  
    88  `gqlgen generate` compares the schema file (`graph/schema.graphqls`) with the models `graph/model/*` and wherever it
    89  can it will bind directly to the model.
    90  
    91  If we take a look in `graph/schema.resolvers.go` we will see all the times that gqlgen couldn't match them up. For us
    92  it was twice:
    93  
    94  ```go
    95  func (r *mutationResolver) CreateTodo(ctx context.Context, input model.NewTodo) (*model.Todo, error) {
    96  	panic(fmt.Errorf("not implemented"))
    97  }
    98  
    99  func (r *queryResolver) Todos(ctx context.Context) ([]*model.Todo, error) {
   100  	panic(fmt.Errorf("not implemented"))
   101  }
   102  ```
   103  
   104  We just need to implement these two methods to get our server working:
   105  
   106  First we need somewhere to track our state, lets put it in `graph/resolver.go`:
   107  ```go
   108  type Resolver struct{
   109  	todos []*model.Todo
   110  }
   111  ```
   112  This is where we declare any dependencies for our app like our database, it gets initialized once in `server.go` when
   113  we create the graph.
   114  
   115  ```go
   116  func (r *mutationResolver) CreateTodo(ctx context.Context, input model.NewTodo) (*model.Todo, error) {
   117  	todo := &model.Todo{
   118  		Text:   input.Text,
   119  		ID:     fmt.Sprintf("T%d", rand.Int()),
   120  		User: &model.User{ID: input.UserID, Name: "user " + input.UserID},
   121  	}
   122  	r.todos = append(r.todos, todo)
   123  	return todo, nil
   124  }
   125  
   126  func (r *queryResolver) Todos(ctx context.Context) ([]*model.Todo, error) {
   127  	return r.todos, nil
   128  }
   129  ```
   130  
   131  We now have a working server, to start it:
   132  ```bash
   133  go run server.go
   134  ```
   135  
   136  then open http://localhost:8080 in a browser. here are some queries to try:
   137  ```graphql
   138  mutation createTodo {
   139    createTodo(input:{text:"todo", userId:"1"}) {
   140      user {
   141        id
   142      }
   143      text
   144      done
   145    }
   146  }
   147  
   148  query findTodos {
   149      todos {
   150        text
   151        done
   152        user {
   153          name
   154        }
   155      }
   156  }
   157  ```
   158  
   159  ### Don't eagerly fetch the user
   160  
   161  This example is great, but in the real world fetching most objects is expensive. We dont want to load the User on the
   162  todo unless the user actually asked for it. So lets replace the generated `Todo` model with something slightly more
   163  realistic.
   164  
   165  Create a new file called `graph/model/todo.go`
   166  ```go
   167  package model
   168  
   169  type Todo struct {
   170  	ID     string `json:"id"`
   171  	Text   string `json:"text"`
   172  	Done   bool   `json:"done"`
   173  	UserID string `json:"user"`
   174  }
   175  ```
   176  
   177  > Note
   178  >
   179  > By default gqlgen will use any models in the model directory that match on name, this can be configured in `gqlgen.yml`.
   180  
   181  And run `go run github.com/99designs/gqlgen generate`.
   182  
   183  Now if we look in `graph/schema.resolvers.go` we can see a new resolver, lets implement it and fix `CreateTodo`.
   184  ```go
   185  func (r *mutationResolver) CreateTodo(ctx context.Context, input model.NewTodo) (*model.Todo, error) {
   186  	todo := &model.Todo{
   187  		Text:   input.Text,
   188  		ID:     fmt.Sprintf("T%d", rand.Int()),
   189  		UserID: input.UserID, // fix this line
   190  	}
   191  	r.todos = append(r.todos, todo)
   192  	return todo, nil
   193  }
   194  
   195  func (r *todoResolver) User(ctx context.Context, obj *model.Todo) (*model.User, error) {
   196  	return &model.User{ID: obj.UserID, Name: "user " + obj.UserID}, nil
   197  }
   198  ```
   199  
   200  ## Finishing touches
   201  
   202  At the top of our `resolver.go`, between `package` and `import`, add the following line:
   203  
   204  ```go
   205  //go:generate go run github.com/99designs/gqlgen
   206  ```
   207  
   208  This magic comment tells `go generate` what command to run when we want to regenerate our code.  To run go generate recursively over your entire project, use this command:
   209  
   210  ```go
   211  go generate ./...
   212  ```