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 }