From eaed1bde8b999237b9ace83fb280c996af977de7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Andr=C3=A9=20Santoni?= Date: Tue, 2 Jan 2018 22:16:49 +0700 Subject: [PATCH 01/11] Add a more complex example --- examples/server/main.go | 149 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 examples/server/main.go diff --git a/examples/server/main.go b/examples/server/main.go new file mode 100644 index 0000000..45c8cf4 --- /dev/null +++ b/examples/server/main.go @@ -0,0 +1,149 @@ +package main + +import ( + "net/http" + + "github.com/functionalfoundry/graphqlws" + "github.com/graphql-go/graphql" + "github.com/graphql-go/handler" + + log "github.com/sirupsen/logrus" +) + +type Document struct { + Title string + Content string +} + +var documents = []Document{ + {Title: "My diary", Content: "Today I had fun with graphqlws"}, + {Title: "Todo", Content: "Add a complete example"}, +} + +var schema graphql.Schema +var subscriptionManager graphqlws.SubscriptionManager + +func main() { + log.SetLevel(log.InfoLevel) + log.Info("Starting example server on :8085") + + var documentType = graphql.NewObject( + graphql.ObjectConfig{ + Name: "Document", + Fields: graphql.Fields{ + "title": &graphql.Field{ + Type: graphql.String, + Resolve: func(p graphql.ResolveParams) (interface{}, error) { + return documents[0].Title, nil + }, + }, + "content": &graphql.Field{ + Type: graphql.String, + Resolve: func(p graphql.ResolveParams) (interface{}, error) { + return documents[0].Content, nil + }, + }, + }, + }, + ) + + var queryType = graphql.NewObject( + graphql.ObjectConfig{ + Name: "Query", + Fields: graphql.Fields{ + "document": &graphql.Field{ + Type: documentType, + Resolve: func(p graphql.ResolveParams) (interface{}, error) { + return 1, nil + }, + }, + }, + }, + ) + + var mutationType = graphql.NewObject( + graphql.ObjectConfig{ + Name: "SomeMutation", + Fields: graphql.Fields{ + "updateDocument": &graphql.Field{ + Type: documentType, + Resolve: func(p graphql.ResolveParams) (interface{}, error) { + + for _, subscriptions := range subscriptionManager.Subscriptions() { + for _, subscription := range subscriptions { + + params := graphql.Params{ + Schema: schema, + RequestString: subscription.Query, + VariableValues: subscription.Variables, + OperationName: subscription.OperationName, + } + result := graphql.Do(params) + + data := graphqlws.DataMessagePayload{ + Data: result.Data, + Errors: graphqlws.ErrorsFromGraphQLErrors(result.Errors), + } + + subscription.SendData(subscription, &data) + } + } + + return 1, nil + }, + }, + }, + }, + ) + + var subscriptionType = graphql.NewObject( + graphql.ObjectConfig{ + Name: "Subscription", + Fields: graphql.Fields{ + "documentUpdates": &graphql.Field{ + Type: documentType, + Args: graphql.FieldConfigArgument{ + "postId": &graphql.ArgumentConfig{ + Type: graphql.String, + }, + }, + Resolve: func(p graphql.ResolveParams) (interface{}, error) { + return 1, nil + }, + }, + }, + }, + ) + + schemaConfig := graphql.SchemaConfig{ + Query: queryType, + Mutation: mutationType, + Subscription: subscriptionType, + } + + var err error + schema, err = graphql.NewSchema(schemaConfig) + if err != nil { + log.WithField("err", err).Panic("GraphQL schema is invalid") + } + + subscriptionManager = graphqlws.NewSubscriptionManager(&schema) + websocketHandler := graphqlws.NewHandler(graphqlws.HandlerConfig{ + SubscriptionManager: subscriptionManager, + Authenticate: func(token string) (interface{}, error) { + return "Default user", nil + }, + }) + + graphqlHandler := handler.New(&handler.Config{ + Schema: &schema, + Pretty: true, + GraphiQL: true, + }) + + http.Handle("/", graphqlHandler) + http.Handle("/subscriptions", websocketHandler) + if err := http.ListenAndServe(":8085", nil); err != nil { + log.WithField("err", err).Error("Failed to start server") + } +} From ecafd0700673c00bc8fee383bd7fd4057f25d15f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Andr=C3=A9=20Santoni?= Date: Tue, 2 Jan 2018 22:57:44 +0700 Subject: [PATCH 02/11] Resolve at the function level --- examples/server/main.go | 42 ++++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/examples/server/main.go b/examples/server/main.go index 45c8cf4..96b27a9 100644 --- a/examples/server/main.go +++ b/examples/server/main.go @@ -11,8 +11,8 @@ import ( ) type Document struct { - Title string - Content string + Title string `json:"title"` + Content string `json:"content"` } var documents = []Document{ @@ -33,15 +33,9 @@ func main() { Fields: graphql.Fields{ "title": &graphql.Field{ Type: graphql.String, - Resolve: func(p graphql.ResolveParams) (interface{}, error) { - return documents[0].Title, nil - }, }, "content": &graphql.Field{ Type: graphql.String, - Resolve: func(p graphql.ResolveParams) (interface{}, error) { - return documents[0].Content, nil - }, }, }, }, @@ -53,8 +47,14 @@ func main() { Fields: graphql.Fields{ "document": &graphql.Field{ Type: documentType, + Args: graphql.FieldConfigArgument{ + "docId": &graphql.ArgumentConfig{ + Type: graphql.Int, + }, + }, Resolve: func(p graphql.ResolveParams) (interface{}, error) { - return 1, nil + docID := p.Args["docId"].(int) + return documents[docID], nil }, }, }, @@ -67,8 +67,23 @@ func main() { Fields: graphql.Fields{ "updateDocument": &graphql.Field{ Type: documentType, + Args: graphql.FieldConfigArgument{ + "docId": &graphql.ArgumentConfig{ + Type: graphql.Int, + }, + "title": &graphql.ArgumentConfig{ + Type: graphql.String, + }, + "content": &graphql.ArgumentConfig{ + Type: graphql.String, + }, + }, Resolve: func(p graphql.ResolveParams) (interface{}, error) { + docID := p.Args["docId"].(int) + documents[docID].Title = p.Args["title"].(string) + documents[docID].Title = p.Args["title"].(string) + for _, subscriptions := range subscriptionManager.Subscriptions() { for _, subscription := range subscriptions { @@ -89,7 +104,7 @@ func main() { } } - return 1, nil + return documents[docID], nil }, }, }, @@ -103,12 +118,13 @@ func main() { "documentUpdates": &graphql.Field{ Type: documentType, Args: graphql.FieldConfigArgument{ - "postId": &graphql.ArgumentConfig{ - Type: graphql.String, + "docId": &graphql.ArgumentConfig{ + Type: graphql.Int, }, }, Resolve: func(p graphql.ResolveParams) (interface{}, error) { - return 1, nil + docID := p.Args["docId"].(int) + return documents[docID], nil }, }, }, From a7b92c776070a1f380726fb6165cfce3307038d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Andr=C3=A9=20Santoni?= Date: Tue, 2 Jan 2018 23:12:21 +0700 Subject: [PATCH 03/11] Add subscription filter on docId --- examples/server/main.go | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/examples/server/main.go b/examples/server/main.go index 96b27a9..ac5a63b 100644 --- a/examples/server/main.go +++ b/examples/server/main.go @@ -87,20 +87,26 @@ func main() { for _, subscriptions := range subscriptionManager.Subscriptions() { for _, subscription := range subscriptions { - params := graphql.Params{ - Schema: schema, - RequestString: subscription.Query, - VariableValues: subscription.Variables, - OperationName: subscription.OperationName, - } - result := graphql.Do(params) + // JSON interface is float64 + var subdocID int = int(subscription.Variables["docId"].(float64)) - data := graphqlws.DataMessagePayload{ - Data: result.Data, - Errors: graphqlws.ErrorsFromGraphQLErrors(result.Errors), - } + if docID == subdocID { + + params := graphql.Params{ + Schema: schema, + RequestString: subscription.Query, + VariableValues: subscription.Variables, + OperationName: subscription.OperationName, + } + result := graphql.Do(params) - subscription.SendData(subscription, &data) + data := graphqlws.DataMessagePayload{ + Data: result.Data, + Errors: graphqlws.ErrorsFromGraphQLErrors(result.Errors), + } + + subscription.SendData(subscription, &data) + } } } From 7710a46b39ac42865ebd150778dbe6d30f64fb9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Andr=C3=A9=20Santoni?= Date: Wed, 3 Jan 2018 21:51:15 +0700 Subject: [PATCH 04/11] Set graphiql subscriptions endpoint --- examples/server/main.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/examples/server/main.go b/examples/server/main.go index ac5a63b..e032f28 100644 --- a/examples/server/main.go +++ b/examples/server/main.go @@ -63,7 +63,7 @@ func main() { var mutationType = graphql.NewObject( graphql.ObjectConfig{ - Name: "SomeMutation", + Name: "Mutation", Fields: graphql.Fields{ "updateDocument": &graphql.Field{ Type: documentType, @@ -158,9 +158,11 @@ func main() { }) graphqlHandler := handler.New(&handler.Config{ - Schema: &schema, - Pretty: true, - GraphiQL: true, + Schema: &schema, + Pretty: true, + GraphiQL: true, + EndpointURL: "http://localhost:8085", + SubscriptionsEndpoint: "ws://localhost:8085/subscriptions", }) http.Handle("/", graphqlHandler) From a342c2ae16af490584a6964c83da316d9acaf3b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Andr=C3=A9=20Santoni?= Date: Fri, 5 Jan 2018 14:02:27 +0700 Subject: [PATCH 05/11] Don't export document --- examples/server/main.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/server/main.go b/examples/server/main.go index e032f28..2120c0c 100644 --- a/examples/server/main.go +++ b/examples/server/main.go @@ -10,12 +10,12 @@ import ( log "github.com/sirupsen/logrus" ) -type Document struct { +type document struct { Title string `json:"title"` Content string `json:"content"` } -var documents = []Document{ +var documents = []document{ {Title: "My diary", Content: "Today I had fun with graphqlws"}, {Title: "Todo", Content: "Add a complete example"}, } From d4bebe8352691271a917cc83b562f7df93029076 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Andr=C3=A9=20Santoni?= Date: Fri, 5 Jan 2018 14:06:31 +0700 Subject: [PATCH 06/11] Use id in place of docId --- examples/server/main.go | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/examples/server/main.go b/examples/server/main.go index 2120c0c..ae4ad04 100644 --- a/examples/server/main.go +++ b/examples/server/main.go @@ -48,13 +48,13 @@ func main() { "document": &graphql.Field{ Type: documentType, Args: graphql.FieldConfigArgument{ - "docId": &graphql.ArgumentConfig{ + "id": &graphql.ArgumentConfig{ Type: graphql.Int, }, }, Resolve: func(p graphql.ResolveParams) (interface{}, error) { - docID := p.Args["docId"].(int) - return documents[docID], nil + id := p.Args["id"].(int) + return documents[id], nil }, }, }, @@ -68,7 +68,7 @@ func main() { "updateDocument": &graphql.Field{ Type: documentType, Args: graphql.FieldConfigArgument{ - "docId": &graphql.ArgumentConfig{ + "id": &graphql.ArgumentConfig{ Type: graphql.Int, }, "title": &graphql.ArgumentConfig{ @@ -80,17 +80,17 @@ func main() { }, Resolve: func(p graphql.ResolveParams) (interface{}, error) { - docID := p.Args["docId"].(int) - documents[docID].Title = p.Args["title"].(string) - documents[docID].Title = p.Args["title"].(string) + id := p.Args["id"].(int) + documents[id].Title = p.Args["title"].(string) + documents[id].Title = p.Args["title"].(string) for _, subscriptions := range subscriptionManager.Subscriptions() { for _, subscription := range subscriptions { // JSON interface is float64 - var subdocID int = int(subscription.Variables["docId"].(float64)) + var subID int = int(subscription.Variables["id"].(float64)) - if docID == subdocID { + if id == subID { params := graphql.Params{ Schema: schema, @@ -110,7 +110,7 @@ func main() { } } - return documents[docID], nil + return documents[id], nil }, }, }, @@ -124,13 +124,13 @@ func main() { "documentUpdates": &graphql.Field{ Type: documentType, Args: graphql.FieldConfigArgument{ - "docId": &graphql.ArgumentConfig{ + "id": &graphql.ArgumentConfig{ Type: graphql.Int, }, }, Resolve: func(p graphql.ResolveParams) (interface{}, error) { - docID := p.Args["docId"].(int) - return documents[docID], nil + id := p.Args["id"].(int) + return documents[id], nil }, }, }, From a6147369b83425e53e65c4abd68c2f38dc4294fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Andr=C3=A9=20Santoni?= Date: Fri, 5 Jan 2018 14:12:51 +0700 Subject: [PATCH 07/11] wrap mutation arguments with graphql.NewNonNull --- examples/server/main.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/server/main.go b/examples/server/main.go index ae4ad04..cae4fa5 100644 --- a/examples/server/main.go +++ b/examples/server/main.go @@ -69,20 +69,20 @@ func main() { Type: documentType, Args: graphql.FieldConfigArgument{ "id": &graphql.ArgumentConfig{ - Type: graphql.Int, + Type: graphql.NewNonNull(graphql.Int), }, "title": &graphql.ArgumentConfig{ - Type: graphql.String, + Type: graphql.NewNonNull(graphql.String), }, "content": &graphql.ArgumentConfig{ - Type: graphql.String, + Type: graphql.NewNonNull(graphql.String), }, }, Resolve: func(p graphql.ResolveParams) (interface{}, error) { id := p.Args["id"].(int) documents[id].Title = p.Args["title"].(string) - documents[id].Title = p.Args["title"].(string) + documents[id].Content = p.Args["content"].(string) for _, subscriptions := range subscriptionManager.Subscriptions() { for _, subscription := range subscriptions { From cdf65d8735a823664e5882908e4a4e216c968091 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Andr=C3=A9=20Santoni?= Date: Fri, 5 Jan 2018 14:13:51 +0700 Subject: [PATCH 08/11] Remove useless new lines --- examples/server/main.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/examples/server/main.go b/examples/server/main.go index cae4fa5..f7375a2 100644 --- a/examples/server/main.go +++ b/examples/server/main.go @@ -79,19 +79,16 @@ func main() { }, }, Resolve: func(p graphql.ResolveParams) (interface{}, error) { - id := p.Args["id"].(int) documents[id].Title = p.Args["title"].(string) documents[id].Content = p.Args["content"].(string) for _, subscriptions := range subscriptionManager.Subscriptions() { for _, subscription := range subscriptions { - // JSON interface is float64 var subID int = int(subscription.Variables["id"].(float64)) if id == subID { - params := graphql.Params{ Schema: schema, RequestString: subscription.Query, From fd92641bc7912686427806b6610c41465e85669c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Andr=C3=A9=20Santoni?= Date: Fri, 5 Jan 2018 14:20:14 +0700 Subject: [PATCH 09/11] Use short variable names --- examples/server/main.go | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/examples/server/main.go b/examples/server/main.go index f7375a2..e197ef9 100644 --- a/examples/server/main.go +++ b/examples/server/main.go @@ -83,26 +83,28 @@ func main() { documents[id].Title = p.Args["title"].(string) documents[id].Content = p.Args["content"].(string) - for _, subscriptions := range subscriptionManager.Subscriptions() { - for _, subscription := range subscriptions { + for _, subs := range subscriptionManager.Subscriptions() { + for _, sub := range subs { // JSON interface is float64 - var subID int = int(subscription.Variables["id"].(float64)) + var subID int = int(sub.Variables["id"].(float64)) if id == subID { params := graphql.Params{ Schema: schema, - RequestString: subscription.Query, - VariableValues: subscription.Variables, - OperationName: subscription.OperationName, + RequestString: sub.Query, + VariableValues: sub.Variables, + OperationName: sub.OperationName, } result := graphql.Do(params) data := graphqlws.DataMessagePayload{ - Data: result.Data, - Errors: graphqlws.ErrorsFromGraphQLErrors(result.Errors), + Data: result.Data, + Errors: graphqlws.ErrorsFromGraphQLErrors( + result.Errors, + ), } - subscription.SendData(subscription, &data) + sub.SendData(sub, &data) } } } From c881694af4cc5585615d9ada108931633a1e45d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Andr=C3=A9=20Santoni?= Date: Fri, 5 Jan 2018 16:06:00 +0700 Subject: [PATCH 10/11] EndpointURL was renamed to Endpoint in graphql-go/handler --- examples/server/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/server/main.go b/examples/server/main.go index e197ef9..3669fbe 100644 --- a/examples/server/main.go +++ b/examples/server/main.go @@ -160,7 +160,7 @@ func main() { Schema: &schema, Pretty: true, GraphiQL: true, - EndpointURL: "http://localhost:8085", + Endpoint: "http://localhost:8085", SubscriptionsEndpoint: "ws://localhost:8085/subscriptions", }) From fde93d7eb3a19f59b1ce0af50315247db40a88ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Andr=C3=A9=20Santoni?= Date: Fri, 5 Jan 2018 21:05:41 +0700 Subject: [PATCH 11/11] Update SendData signature --- examples/server/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/server/main.go b/examples/server/main.go index 3669fbe..1d66264 100644 --- a/examples/server/main.go +++ b/examples/server/main.go @@ -104,7 +104,7 @@ func main() { ), } - sub.SendData(sub, &data) + sub.SendData(&data) } } }