I've successfully set up a GraphQL server in go using the graphql-go library. However, I seem to be getting an error when I pass query parameters when making a query. So I have a query named emails
that takes address
as an argument and queries a database to return results regarding all the emails associated with the given address
. When I pass the address
parameter directly, everything seems to work perfectly, as you can see from this image:
However, it doesn't seem to work when I pass it query parameters, like this:
I was off the idea that these two statements should give the same results. However, this doesn't seem to be the case. Could somebody help me understand why I'm getting these errors? This is my go code
package main
import (
"log"
"net/http"
"github.com/graphql-go/graphql"
"github.com/graphql-go/handler"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/dynamodb"
"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"
)
var sess, _ = session.NewSession()
// Email - Used to represent a single email object stored in
// dynamodb. Fields 'attachments', 'body-html', 'stripped-html' and
// 'stripped-text' may be empty.
type Email struct {
To string `json:"to"`
Recipients []string `json:"recipients"`
Token string `json:"token"`
Sender string `json:"sender"`
Subject string `json:"subject"`
Timestamp string `json:"timestamp"`
Attachments []string `json:"attachments"`
Mime string `json:"mime"`
BodyPlain string `json:"body_plain"`
BodyHTML string `json:"body_html"`
StrippedText string `json:"stripped_text"`
StrippedHTML string `json:"stripped_html"`
}
// emailType - a new graphql object representing a single email
var emailType = graphql.NewObject(graphql.ObjectConfig{
Name: "Email",
Fields: graphql.Fields{
"to": &graphql.Field{
Type: graphql.String,
},
"recipients": &graphql.Field{
Type: graphql.NewList(graphql.String),
},
"token": &graphql.Field{
Type: graphql.String,
},
"sender": &graphql.Field{
Type: graphql.String,
},
"subject": &graphql.Field{
Type: graphql.String,
},
"attachments": &graphql.Field{
Type: graphql.NewList(graphql.String),
},
"timestamp": &graphql.Field{
Type: graphql.String,
},
"mime": &graphql.Field{
Type: graphql.String,
},
"body_plain": &graphql.Field{
Type: graphql.String,
},
"body_html": &graphql.Field{
Type: graphql.String,
},
"stripped_text": &graphql.Field{
Type: graphql.String,
},
"stripped_html": &graphql.Field{
Type: graphql.String,
},
},
})
// emailType - a new graphql object representing a deleted email.
var deleteEmailType = graphql.NewObject(graphql.ObjectConfig{
Name: "Email",
Fields: graphql.Fields{
"to": &graphql.Field{
Type: graphql.String,
},
"token": &graphql.Field{
Type: graphql.String,
},
},
})
func disableCors(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
w.Header().Set("Access-Control-Allow-Headers", "Accept, Authorization, Content-Type, Content-Length, Accept-Encoding")
// I added this for another handler of mine,
// but I do not think this is necessary for GraphQL's handler
if r.Method == "OPTIONS" {
w.Header().Set("Access-Control-Max-Age", "86400")
w.WriteHeader(http.StatusOK)
return
}
h.ServeHTTP(w, r)
})
}
func main() {
// configures the rootQuery for the graphQL API
rootQuery := graphql.NewObject(graphql.ObjectConfig{
Name: "Query",
Fields: graphql.Fields{
"emails": &graphql.Field{
Type: graphql.NewList(emailType),
Args: graphql.FieldConfigArgument{
"address": &graphql.ArgumentConfig{
Type: graphql.String,
},
},
Resolve: func(params graphql.ResolveParams) (interface{}, error) {
address := params.Args["address"].(string)
svc := dynamodb.New(sess)
result, err := svc.Query(&dynamodb.QueryInput{
TableName: aws.String("emails_db"),
KeyConditions: map[string]*dynamodb.Condition{
"to": {
ComparisonOperator: aws.String("EQ"),
AttributeValueList: []*dynamodb.AttributeValue{
{
S: aws.String(address),
},
},
},
},
})
if err != nil {
return nil, nil
}
// unmarshalls all the emails to recs
recs := []Email{}
err = dynamodbattribute.UnmarshalListOfMaps(result.Items, &recs)
if err != nil {
return nil, nil
}
return recs, nil
},
},
},
})
// configures the rootMutation for the graphQL API
rootMutation := graphql.NewObject(graphql.ObjectConfig{
Name: "Mutation",
Fields: graphql.Fields{
"email": &graphql.Field{
Type: deleteEmailType,
Args: graphql.FieldConfigArgument{
"address": &graphql.ArgumentConfig{
Type: graphql.NewNonNull(graphql.String),
},
"token": &graphql.ArgumentConfig{
Type: graphql.NewNonNull(graphql.String),
},
},
Resolve: func(params graphql.ResolveParams) (interface{}, error) {
address := params.Args["address"].(string)
token := params.Args["token"].(string)
svc := dynamodb.New(sess)
_, err := svc.DeleteItem(&dynamodb.DeleteItemInput{
TableName: aws.String("emails_db"),
Key: map[string]*dynamodb.AttributeValue{
"to": {
S: aws.String(address),
},
"token": {
S: aws.String(token),
},
},
})
if err != nil {
return nil, err
}
// unmarshalls all the emails to recs
rec := Email{To: address, Token: token}
return rec, nil
},
},
},
})
// configures routes
schema, _ := graphql.NewSchema(graphql.SchemaConfig{
Mutation: rootMutation,
Query: rootQuery,
})
h := handler.New(&handler.Config{
Schema: &schema,
Pretty: true,
GraphiQL: true,
})
http.Handle("/graphql", disableCors(h))
log.Fatal(http.ListenAndServe(":80", nil))
}