/gin_graphql

Gin and GraphQL server using Golang, gorm, gqlgen.

Primary LanguageGoApache License 2.0Apache-2.0

Gin GraphQL

A GraphQL, RESTful server with Golang, gorm, gqlgen, go-playground/validator. Implement PubSub by github.com/moby/moby/pkg/pubsub created by Docker.

Build Server

Copy .env.example to .env and .env.dev

# create tables
make migrate

# create GraphQL file
make build_graphql 

# build server
make build

# start server
.build/gin_graphql

URL


Notes

GraphQL

https://gqlgen.com/ You could initialize a new project using the recommended folder structure by running this command

Initiation

go run github.com/99designs/gqlgen init
├── 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     - DO NOT EDIT !
│   ├── model                - A package for all your graph models, generated or otherwise
│   │   └── models_gen.go    - DO NOT EDIT !
│   ├── resolver.go          - The root graph resolver type. This file wont get regenerated
│   ├── schema.graphqls      - Some schema. You can split the schema into as many graphql files as you like
│   └── schema.resolvers.go  - the resolver implementation for schema.graphql
└── server.go                - The entry point to your app. Customize it however you see fit

Finishing touches

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

//go:generate go run github.com/99designs/gqlgen

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 ./...

Implement the directive

Declare it in the schema

Path: graph/schema.graphqls.

type Mutation {
    deleteMeetUp(id: ID!): Boolean! @hasRole(role: ADMIN) @isAuthenticated
}

directive @isAuthenticated on FIELD_DEFINITION
directive @hasRole(role: Role!) on FIELD_DEFINITION
Implement

Path: graph/directives/directiveAuth.go

func IsAuthenticated(ctx context.Context, obj interface{}, next graphql.Resolver) (res interface{}, err error) {
	ctxUserID := ctx.Value(CurrentUserKey)
	if ctxUserID == nil {
		return nil, graph.ErrUnauthenticated
	}
	return next(ctx)
}
Pass it in when start server

Path: main.go

c := generated.Config{Resolvers: &graph.Resolver{}}
// Schema Directive
c.Directives.IsAuthenticated = directives.IsAuthenticated
c.Directives.HasRole = directives.HasRole

srv := handler.NewDefaultServer(generated.NewExecutableSchema(c))

return func(c *gin.Context) {
    srv.ServeHTTP(c.Writer, c.Request)
}

Modify schema

  1. modify your schema graph/schema.graphqls
  2. run gqlgen ./script/gqlgen.sh or go run -v github.com/99designs/gqlgen
  3. modify resolvers graph/resolver.go

Database (Mysql)

Migrate

make migrate mode={auto | drop | refresh} or go run database/migrate.go -m=auto


Swagger API Doc

http://localhost:5566/swagger/index.html

init

swag init

PPROF

[GIN-debug] GET    /admin/pprof/             --> github.com/gin-contrib/pprof.pprofHandler.func1 (4 handlers)
[GIN-debug] GET    /admin/pprof/cmdline      --> github.com/gin-contrib/pprof.pprofHandler.func1 (4 handlers)
[GIN-debug] GET    /admin/pprof/profile      --> github.com/gin-contrib/pprof.pprofHandler.func1 (4 handlers)
[GIN-debug] POST   /admin/pprof/symbol       --> github.com/gin-contrib/pprof.pprofHandler.func1 (4 handlers)
[GIN-debug] GET    /admin/pprof/symbol       --> github.com/gin-contrib/pprof.pprofHandler.func1 (4 handlers)
[GIN-debug] GET    /admin/pprof/trace        --> github.com/gin-contrib/pprof.pprofHandler.func1 (4 handlers)
[GIN-debug] GET    /admin/pprof/allocs       --> github.com/gin-contrib/pprof.pprofHandler.func1 (4 handlers)
[GIN-debug] GET    /admin/pprof/block        --> github.com/gin-contrib/pprof.pprofHandler.func1 (4 handlers)
[GIN-debug] GET    /admin/pprof/goroutine    --> github.com/gin-contrib/pprof.pprofHandler.func1 (4 handlers)
[GIN-debug] GET    /admin/pprof/heap         --> github.com/gin-contrib/pprof.pprofHandler.func1 (4 handlers)
[GIN-debug] GET    /admin/pprof/mutex        --> github.com/gin-contrib/pprof.pprofHandler.func1 (4 handlers)
[GIN-debug] GET    /admin/pprof/threadcreate --> github.com/gin-contrib/pprof.pprofHandler.func1 (4 handlers)

Go commands

# Initiation Go project
go mod init  
go mod tidy

# download Go package
go mod download

Fix

  1. graph/prelude.resolvers.go:19:34: cannot refer to unexported name generated.__DirectiveResolver
    • rollback the version of gqlparser from github.com/vektah/gqlparser/v2 v2.2.0 to github.com/vektah/gqlparser/v2 v2.1.0
    go mod edit -require github.com/vektah/gqlparser/v2@v2.1.0    
    go clean -i github.com/vektah/gqlparser/v2  
    go get github.com/vektah/gqlparser/v2@v2.1.0
    

Reference

  1. 99designs/gqlgen
  2. go.uber.org/ratelimit
  3. didip/tollbooth
  4. EQuimper/youtube-golang-graphql-tutorial
  5. wtlin1228/unasees
  6. schema
  7. gqlgen gin
  8. blog.laisky.com
  9. qlgen-custom-data-validation
  10. gorm
  11. go-playground/validator
  12. graphql-spec