# README
Go Graph Loader ( GGL )
go graph loader is a plugin for load the grahql by resolver and process scalar type with go struct definition instead of schema typing, and come with some simple extension like validator.
Tag & Method Signature
In this plugin we're using gql
as graphql key loader and root
as root object arguments loader. And about method signature we're following as per below, the responseType
will be ur model definition so in order to let us to generate graphql response schema as well.
type Resolver struct {
}
func (*Resolver) Product(context.Context) (responseType, error) {
}
type ProductRequest struct {
Merchant string `root:"merchant"`
ID string `gql:"id"`
}
func (*Resolver) Product(context.Context, *ProductRequest) (responseType, error) {
}
Pre Resolver Method Signature
Pre resolver function mainly is let you can do injection on the context based on the response type, usually will use for context resolution for some high level ORM.
type Resolver struct {}
type responseType struct {}
func (rt *responseType) PreResolver(ctx context.Context) context.Context {
log.Println("invoke preResolver")
return ctx
}
func (*Resolver) Product(context.Context) (responseType, error) {
}
Model Definition
For model definition by default we're not exposing all the fields only the fields with gql
tagged will be exposed. Other than that we did support for field resolver or custom resolver which mean we can add extra function on model.
Supported Primitive Types
1. bool
2. int, int8, int16, int32, int64
3. float32, float64
4. string
5. slice
6. array
7. map
Model Field Resolver
As per model field resolver, we can overriding the original field resolver which just exposing the value, with this we can customize based on the source of value. For method signature as per Tag & Method Signature mentioned it can be only context
value or with custom request arguments/
type Product struct {
ID int64 `gql:"id"`
Name string `gql:"name"`
Price float64 `gql:"price"`
}
type ProductNameArgs struct {
Extra string `gql:"name"`
}
func (product *Product) GGL_Name(ctx context.Context, args *ProductNameArgs) (string, error) {
return product.Name + "-" + args.Extra, nil
}
func (product *Product) GGL_Price(ctx context.Context) (int64, error) {
return int64(product.Price * 100), nil
}
{
product {
name(extra: "extraname")
price
}
}
Custom Field Resolver
For custom field resolver, we're not overriding the original field resolver but we create new resolver for itself with source of value. All the function will be camelCase when define in graphql query.
type Product struct {
ID int64 `gql:"id"`
Name string `gql:"name"`
Price float64 `gql:"price"`
}
func (product *Product) GGL_NameWithPrice(ctx context.Context) (string, error) {
return fmt.Sprintf("%v=%v", product.Name, product.Price), nil
}
{
product {
name,
price,
nameWithPrice
}
}
Code & Execution
package main
import (
"context"
"json"
"log"
ggl "github.com/Oskang09/go-graph-loader"
)
func main() {
resolver := // your resolver struct which contains all the root functions
manager := ggl.New()
manager.RegisterSchema(resolver)
// define your custom validator
// so with this you can validate your incoming
// parameters with your own validator
manager.RegisterValidator(nil)
// magidoc template generator
manager.WriteSchema("schema.json")
manager.WriteMagidoc("magidoc.mjs", "schema.json")
result := manager.Do().
Query("{ product { name } }"). // set your query string
Root(map[string]interface{}{"value":"some root value"}). // (optional) set your root object
Execute(context.Background()) // your current context, it can be useful for tracking & tracing purpose
if result.HasErrors() {
log.Println(result.Errors)
}
bytes, _ := json.Marshal(result.Data)
log.Println(string(bytes))
}
Error & Debugging
We did provide the error footprint while having definition error or schema error, so would help you a lot when debugging the issues.
PreResolver Siganture Error
2022/10/20 00:21:41 ————————————— Go Graph Loader —————————————
2022/10/20 00:21:41 | Package | main
2022/10/20 00:21:41 | Struct | Product
2022/10/20 00:21:41 | Type | PRE_RESOLVER
2022/10/20 00:21:41 | Signature | func(*main.Product) context.Context
2022/10/20 00:21:41 ———————————————————————————————————————————
panic: go-graph-loader: invalid method signature is using for pre resolver function
Resolver Function Signature Error
2022/10/20 00:18:03 ————————————— Go Graph Loader —————————————
2022/10/20 00:18:03 | Package | main
2022/10/20 00:18:03 | Struct | Product
2022/10/20 00:18:03 | Type | RESOLVER_METHOD
2022/10/20 00:18:03 | Signature | func(*main.Product, *main.ProductNameArgs) (string, error)
2022/10/20 00:18:03 ———————————————————————————————————————————
panic: go-graph-loader: invalid method signature is using for field resolver function
Documentation Tools
For documentating we will suggest go with magidoc since they will build documentation based on your server's introspection query result.
Development Roadmap
-
PreResolver
to allow process context on Response Type - Error Tracing Footprint
- Support int to int64, Support float32 to 64.
- Support uint to uint64, need to specify custom scalar type since graphql doesn't have it
- Allow generate schema for
Subscription
&Mutation
- Add more examples & cookbook with some famous Go framework
- Using AST Travesal to allow documentation on the Go model and reflect on Magidoc