This post includes an example of GraphQL usage in Go. The actual GraphQL implementation is using the graphql-go library.
Some insights I got from this:
- Implementing code in GraphQL is much more complicated than using REST. We need to re-write the specifications for each usage, and repeat the fields names. It is not build in to the language like GO and simple JSON marshaling.
- To use mutation drop the root parenthesis in the query. OMG I've spent an hour trying to understand why it is not working.
- I believe the advantage of GraphQL over REST is dynamic fields selection. Don't know many applications where this matters.
- Authorization is not full built into GraphQL. I guess this is why we have so many security issues in applications using GraphQL.
package main
import (
"encoding/json"
"fmt"
"github.com/graphql-go/graphql"
)
type dbActor struct {
Name string
BirthYear int
}
var dbActors = []*dbActor{
{
Name: "John Travolta",
BirthYear: 1954,
},
{
Name: "Robert Redford",
BirthYear: 1936,
},
}
func main() {
schema := createSchema()
var query string
query = `
{
list{
name
birthYear
}
}
`
runQuery(schema, query)
query = `
{
actor(name: "Robert Redford"){
birthYear
}
}
`
runQuery(schema, query)
query = `
mutation {
create(name:"Meryl Streep",birthYear:1949){
name
}
}
`
runQuery(schema, query)
query = `
{
list{
name
birthYear
}
}
`
runQuery(schema, query)
}
func runQuery(schema graphql.Schema, query string) {
params := graphql.Params{
Schema: schema,
RequestString: query,
}
result := graphql.Do(params)
if len(result.Errors) > 0 {
panic(fmt.Errorf("failed to execute graphql operation, errors: %+v", result.Errors))
}
jsonData, err := json.MarshalIndent(result, "", " ")
if err != nil {
panic(err)
}
fmt.Printf("\n%s\n", jsonData)
}
func createSchema() graphql.Schema {
schemaActor := graphql.NewObject(graphql.ObjectConfig{
Name: "actor",
Fields: graphql.Fields{
"name": &graphql.Field{
Type: graphql.String,
},
"birthYear": &graphql.Field{
Type: graphql.Int,
},
},
})
schemaQuery := graphql.NewObject(graphql.ObjectConfig{
Name: "QueryRoot",
Fields: graphql.Fields{
"list": &graphql.Field{
Type: graphql.NewList(schemaActor),
Resolve: func(params graphql.ResolveParams) (interface{}, error) {
return dbActors, nil
},
},
"actor": &graphql.Field{
Type: schemaActor,
Args: graphql.FieldConfigArgument{
"name": &graphql.ArgumentConfig{
Type: graphql.String,
},
},
Resolve: func(params graphql.ResolveParams) (interface{}, error) {
name, ok := params.Args["name"].(string)
if !ok {
panic("name argument invalid")
}
for _, actor := range dbActors {
if actor.Name == name {
return actor, nil
}
}
return nil, nil
},
},
},
})
schemaMutation := graphql.NewObject(graphql.ObjectConfig{
Name: "Mutation",
Fields: graphql.Fields{
"create": &graphql.Field{
Type: schemaActor,
Args: graphql.FieldConfigArgument{
"name": &graphql.ArgumentConfig{
Type: graphql.NewNonNull(graphql.String),
},
"birthYear": &graphql.ArgumentConfig{
Type: graphql.NewNonNull(graphql.Int),
},
},
Resolve: func(params graphql.ResolveParams) (interface{}, error) {
name, ok := params.Args["name"].(string)
if !ok {
panic("name argument invalid")
}
birthYear, ok := params.Args["birthYear"].(int)
if !ok {
panic("birthYear argument invalid")
}
actor := dbActor{
Name: name,
BirthYear: birthYear,
}
dbActors = append(dbActors, &actor)
return actor, nil
},
},
},
})
schemaConfig := graphql.SchemaConfig{
Query: schemaQuery,
Mutation: schemaMutation,
}
schema, err := graphql.NewSchema(schemaConfig)
if err != nil {
panic(err)
}
return schema
}
No comments:
Post a Comment