Skip to content

Setup FastGQL

This tutorial will take you through the process of building a GraphQL server with fastgql that can: automatically query, filter, order and pagination users, posts & categories from a postgres database.

You can find the finished code for this tutorial here.

If you are familiar with gqlgen, the setup is nearly identical, with a little work in your Schema you won’t need to define any resolvers!

Setup Project

Create a directory for your project, and initialise it as a Go Module:

Terminal window
$ mkdir fastgql-example
$ cd fastgql-example
$ go mod init github.com/[username]/fastgql-example
$ go get github.com/roneli/fastgql

Add github.com/roneli/fastgql to your project’s tools.go

Terminal window
printf '// +build tools\npackage tools\nimport _ "github.com/roneli/fastgql"' | gofmt > tools.go
go mod tidy

Building the server

Create the project skeleton

Terminal window
$ go run github.com/roneli/fastgql init
$ go mod tidy

This will create our suggested package layout. You can modify these paths in gqlgen.yml if you need to.

├── go.mod
├── go.sum
├── gqlgen.yml - The gqlgen config file, knobs for controlling the generated code.
├── graph
│ ├── generated - A package that only contains the generated runtime
│ │ └── generated.go
│ ├── model - A package for all your graph models, generated or otherwise
│ │ └── models_gen.go
│ ├── resolver.go - The root graph resolver type. This file wont get regenerated
| ├── fastgql.graphql - fastgql schema fragemnt, adding all directives, inputs etc' required for schema augment
│ ├── schema.graphql - Some schema. You can split the schema into as many graphql files as you like
│ └── schema.fastgql.go - the resolver implementation for schema.graphql
└── server.go - The entry point to your app. Customize it however you see fit

Define your schema

gqlgen is a schema-first library — before writing code, you describe your API using the GraphQL Schema Definition Language. By default this goes into a file called schema.graphql but you can break it up into as many different files as you want.

The schema that was generated for us was:

{% code overflow=“wrap” %}

type User @generateFilterInput @table(name: "user"){
id: Int!
name: String!
posts: [Post] @relation(type: ONE_TO_MANY, fields: ["id"], references: ["user_id"])
}
type Post @generateFilterInput @table(name: "posts") {
id: Int!
name: String
categories: [Category] @relation(type: MANY_TO_MANY, fields: ["id"], references: ["id"]
manyToManyTable: "posts_to_categories", manyToManyFields: ["post_id"], manyToManyReferences: ["category_id"])
user: User @relation(type: ONE_TO_ONE, fields: ["user_id"], references: ["id"])
}
type Category @generateFilterInput @table(name: "categories") {
id: Int!
name: String
}
type Query {
posts: [Post] @generate
users: [User] @generate
categories: [Category] @generate
}

{% endcode %}

Implement the resolvers

fastgql generate compares the schema file (schema.graphql) with the models graph/model/* and wherever it can it will bind directly to the model. It generates resolvers just like gqlgen, but also implements some resolvers to directly work with the database.

If we take a look in graph/schema.fastgql.go you will see all the resolvers that fastgql autogenerated for example:

{% code overflow=“wrap” %}

func (r *queryResolver) Posts(ctx context.Context, limit *int, offset *int, orderBy *model.PostOrdering, filter *model.PostFilterInput) ([]*model.Post, error) {
var data []*model.Post
if err := r.Executor.Scan(ctx, "postgres", &data); err != nil {
return nil, err
}
return data, nil
}

{% endcode %}

We just need to start a postgres server and insert a schema, you can try the example’s compose file and execute the schema.sql:

Finally, we just need to define our postgres connection str that defined in server.go. We can override with PG_CONN_STR env variable.

If we used the example’s docker compose we can use this DSN: PG_CONN_STR=postgresql://localhost/postgres?user=postgres&password=password

We now have a working server, to start it:

Terminal window
go run server.go

then open http://localhost:8080 in a browser. here are some queries to try:

query {
posts(limit: 2) {
name
categories {
name
}
}
}
query filterPostsByUser {
posts(limit: 10, filter: {user:{name: {eq: "fastgql"}}}, orderBy: {name: ASC}) {
name
categories {
name
}
user {
name
}
}
}

Finishing touches

At the top of our server.go, between package and import, add the following line:

//go:generate go run github.com/roneli/fastgql generate -c gqlgen.yml

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:

go generate ./...