Table of Contents
Create graphQL server using gqlgen following gqlgen tutorial
mkdir gqlgen-users cd gqlgen-users go mod init github.com/[username]/gqlgen-users
Create tools.go with gqlgen library imported.
tools.go
//go:build tools // +build tools package tools import ( _ "github.com/99designs/gqlgen" )
Install packages
go mod tidy
Create the project skeleton
go run github.com/99designs/gqlgen init
Create database connector
databaseConnector/databaseConnector.go
package databaseConnector import ( "fmt" "github.com/jackc/pgtype" "gorm.io/driver/postgres" "gorm.io/gorm" ) type User struct { ID uint `gorm:"primaryKey"` Username string `gorm:"unique"` Email string Age int MetaData pgtype.JSONB `gorm:"type:jsonb" json:"fieldnameofjsonb"` } func autoMigrateDB(db *gorm.DB) { // Perform database migration err := db.AutoMigrate(&User{}) if err != nil { fmt.Println(err) } } func connectToPostgreSQL() (*gorm.DB, error) { // dsn := "user=mynews password=test123 dbname=tests host=localhost port=5432 sslmode=disable" dsn := "user=toninichev dbname=tests host=localhost port=5432 sslmode=disable" db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{}) if err != nil { return nil, err } return db, nil } func createuserWithMetaData(db *gorm.DB, username string, email string, age int, metaData string) (*User, error) { jsonData := pgtype.JSONB{} err := jsonData.Set([]byte(metaData)) if err != nil { return nil, err } // Create a user newUser := User{Username: username, Email: email, Age: age, MetaData: jsonData} err = createUser(db, &newUser) if err != nil { return nil, err } return &newUser, nil } func createUser(db *gorm.DB, user *User) error { result := db.Create(user) if result.Error != nil { return result.Error } return nil } func CreateDB(tableName string) error { db, err := connectToPostgreSQL() if err != nil { return err } autoMigrateDB(db) return nil } func CreateUser(username string, email string, age int, metaData string) (*User, error) { db, err := connectToPostgreSQL() if err != nil { return nil, err } user, err := createuserWithMetaData(db, username, email, age, metaData) return user, err } func GetUserByID(userID uint) (*User, error) { db, err := connectToPostgreSQL() if err != nil { return nil, err } var user User result := db.First(&user, userID) if result.Error != nil { return nil, result.Error } return &user, nil } func GetUserByMetaData(metaDataFilter string) (*User, error) { db, err := connectToPostgreSQL() if err != nil { return nil, err } var user User // result := db.First(&user, userID) result := db.Where(metaDataFilter).First(&user) if result.Error != nil { return nil, result.Error } return &user, nil }
Edit schema adding the new Customer type, queries and mutations to retrieve and create new users.
graph/schema.graphqls
# GraphQL schema example # # https://gqlgen.com/getting-started/ type Customer { customerId: String! username: String! email: String!, age: Int! metaData: String! } input NewCustomer { customerId: String! username: String! email: String!, age: Int! metaData: String! } type Query { getCustomer(customerId: String!): Customer! getCustomerByMetaData(metaData: String!): Customer! } type Mutation { saveCustomer(input: NewCustomer!):Boolean! createDB(tableName: String!):Boolean! }
Re-generate resolvers with the new schema
go run github.com/99designs/gqlgen generate
Implement the resolvers
graph/schema.resolvers.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. // Code generated by github.com/99designs/gqlgen version v0.17.44 import ( "context" "strconv" "tutorials/gqlgen-users/databaseConnector" "tutorials/gqlgen-users/graph/model" ) // SaveCustomer is the resolver for the saveCustomer field. func (r *mutationResolver) SaveCustomer(ctx context.Context, input model.NewCustomer) (bool, error) { databaseConnector.CreateUser(input.Username, input.Email, input.Age, input.MetaData) return true, nil } // CreateDb is the resolver for the createDB field. func (r *mutationResolver) CreateDb(ctx context.Context, tableName string) (bool, error) { err := databaseConnector.CreateDB(tableName) if err != nil { // handle error return false, err } return true, nil } // GetCustomer is the resolver for the getCustomer field. func (r *queryResolver) GetCustomer(ctx context.Context, customerID string) (*model.Customer, error) { cid, _ := strconv.Atoi(customerID) var customer *databaseConnector.User var err error customer, err = databaseConnector.GetUserByID(uint(cid)) if err != nil { // handle error return nil, err } // get the underlying byte slice. jsonbText, _ := customer.MetaData.Value() // Convert byte slice to string jsonString := string(jsonbText.([]byte)) // map returned customer structure from the DB into the model c := model.Customer{ CustomerID: strconv.FormatUint(uint64(customer.ID), 10), Username: customer.Username, Email: customer.Email, Age: customer.Age, MetaData: jsonString, } return &c, nil } // GetCustomerByMetaData is the resolver for the getCustomerByMetaData field. func (r *queryResolver) GetCustomerByMetaData(ctx context.Context, metaData string) (*model.Customer, error) { customer, err := databaseConnector.GetUserByMetaData(metaData) if err != nil { // handle error return nil, err } // get the underlying byte slice. jsonbText, _ := customer.MetaData.Value() // Convert byte slice to string jsonString := string(jsonbText.([]byte)) // map returned customer structure from the DB into the model c := model.Customer{ CustomerID: strconv.FormatUint(uint64(customer.ID), 10), Username: customer.Username, Email: customer.Email, Age: customer.Age, MetaData: jsonString, } return &c, nil } // Mutation returns MutationResolver implementation. func (r *Resolver) Mutation() MutationResolver { return &mutationResolver{r} } // Query returns QueryResolver implementation. func (r *Resolver) Query() QueryResolver { return &queryResolver{r} } type mutationResolver struct{ *Resolver } type queryResolver struct{ *Resolver }