Skip to content

Commit

Permalink
Added minimal subscriptions support
Browse files Browse the repository at this point in the history
  • Loading branch information
lpalmes committed Nov 30, 2017
1 parent beff084 commit 6e1ef80
Show file tree
Hide file tree
Showing 28 changed files with 475 additions and 77 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
/internal/tests/testdata/graphql-js
.DS_Store
6 changes: 3 additions & 3 deletions example/starwars/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import (
"log"
"net/http"

"github.com/neelance/graphql-go"
"github.com/neelance/graphql-go/example/starwars"
"github.com/neelance/graphql-go/relay"
"github.com/lpalmes/graphql-go"
"github.com/lpalmes/graphql-go/example/starwars"
"github.com/lpalmes/graphql-go/relay"
)

var schema *graphql.Schema
Expand Down
2 changes: 1 addition & 1 deletion example/starwars/starwars.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
"strconv"
"strings"

graphql "github.com/neelance/graphql-go"
graphql "github.com/lpalmes/graphql-go"
)

var Schema = `
Expand Down
125 changes: 125 additions & 0 deletions example/subscription/server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package main

import (
"log"
"net/http"
"time"

graphql "github.com/lpalmes/graphql-go"
"github.com/lpalmes/graphql-go/relay"
"github.com/lpalmes/graphql-go/subscriptions"
"github.com/rs/cors"
)

var channel = make(subscriptions.SubscriptionChannel)

var schema *graphql.Schema

var Schema = `
schema {
query: Query
subscription: Subscription
}
# The query type, represents all of the entry points into our object graph
type Query {
greet: Greeter
bye: String!
}
type Greeter {
hello(name: String!): String!
}
type Subscription {
ping: String!
greet: Greeter
}
`

type Resolver struct{}

type greeterResolver struct{}

func (r *Resolver) Greet() *greeterResolver {
return &greeterResolver{}
}

func (r *greeterResolver) Hello(args *struct {
Name string
}) string {
return "hello " + args.Name
}

func (r *Resolver) Bye() string {
return "friend"
}

func (r *Resolver) Ping() string {
return "Pong"
}

func init() {
schema = graphql.MustParseSchema(Schema, &Resolver{})
}

func main() {
mux := http.NewServeMux()
mux.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write(page)
}))

go func() {
for {
channel <- subscriptions.SubscriptionPayload{
Name: "ping",
Payload: "Blue",
}
time.Sleep(time.Second * 2)
}
}()

mux.Handle("/graphql", &relay.Handler{Schema: schema})
go subscriptions.Listen(schema, &channel)
mux.Handle("/subscriptions", &subscriptions.Handler{Schema: schema})

handler := cors.Default().Handler(mux)
log.Fatal(http.ListenAndServe(":8080", handler))
}

var page = []byte(`
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/graphiql/0.10.2/graphiql.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/fetch/1.1.0/fetch.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.5.4/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.5.4/react-dom.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/graphiql/0.10.2/graphiql.js"></script>
</head>
<body style="width: 100%; height: 100%; margin: 0; overflow: hidden;">
<div id="graphiql" style="height: 100vh;">Loading...</div>
<script>
function graphQLFetcher(graphQLParams) {
return fetch("/query", {
method: "post",
body: JSON.stringify(graphQLParams),
credentials: "include",
}).then(function (response) {
return response.text();
}).then(function (responseBody) {
try {
return JSON.parse(responseBody);
} catch (error) {
return responseBody;
}
});
}
ReactDOM.render(
React.createElement(GraphiQL, {fetcher: graphQLFetcher}),
document.getElementById("graphiql")
);
</script>
</body>
</html>
`)
75 changes: 75 additions & 0 deletions example/subscription/test.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script>
window.addEventListener("load", function(evt) {

var output = document.getElementById("output");
var input = document.getElementById("input");
var ws;

var print = function(message) {
var d = document.createElement("div");
d.innerHTML = message;
output.appendChild(d);
};

document.getElementById("open").onclick = function(evt) {
if (ws) {
return false;
}
ws = new WebSocket("ws://localhost:8080/subscriptions");
ws.onopen = function(evt) {
print("OPEN");
}
ws.onclose = function(evt) {
print("CLOSE");
ws = null;
}
ws.onmessage = function(evt) {
print("RESPONSE: " + evt.data);
}
ws.onerror = function(evt) {
print("ERROR: " + evt.data);
}
return false;
};

document.getElementById("send").onclick = function(evt) {
if (!ws) {
return false;
}
print("SEND: " + input.value);
ws.send(input.value);
return false;
};

document.getElementById("close").onclick = function(evt) {
if (!ws) {
return false;
}
ws.close();
return false;
};

});
</script>
</head>
<body>
<table>
<tr><td valign="top" width="50%">
<p>Click "Open" to create a connection to the server,
"Send" to send a message to the server and "Close" to close the connection.
You can change the message and send multiple times.
<p>
<form>
<button id="open">Open</button>
<button id="close">Close</button>
<p><input id="input" type="text" value="Hello world!">
<button id="send">Send</button>
</form>
</td><td valign="top" width="50%">
<div id="output"></div>
</td></tr></table>
</body>
</html>
2 changes: 1 addition & 1 deletion gqltesting/testing.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"strconv"
"testing"

graphql "github.com/neelance/graphql-go"
graphql "github.com/lpalmes/graphql-go"
)

// Test is a GraphQL test case to be used with RunTest(s).
Expand Down
29 changes: 18 additions & 11 deletions graphql.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,17 @@ import (

"encoding/json"

"github.com/neelance/graphql-go/errors"
"github.com/neelance/graphql-go/internal/common"
"github.com/neelance/graphql-go/internal/exec"
"github.com/neelance/graphql-go/internal/exec/resolvable"
"github.com/neelance/graphql-go/internal/exec/selected"
"github.com/neelance/graphql-go/internal/query"
"github.com/neelance/graphql-go/internal/schema"
"github.com/neelance/graphql-go/internal/validation"
"github.com/neelance/graphql-go/introspection"
"github.com/neelance/graphql-go/log"
"github.com/neelance/graphql-go/trace"
"github.com/lpalmes/graphql-go/errors"
"github.com/lpalmes/graphql-go/internal/common"
"github.com/lpalmes/graphql-go/internal/exec"
"github.com/lpalmes/graphql-go/internal/exec/resolvable"
"github.com/lpalmes/graphql-go/internal/exec/selected"
"github.com/lpalmes/graphql-go/internal/query"
"github.com/lpalmes/graphql-go/internal/schema"
"github.com/lpalmes/graphql-go/internal/validation"
"github.com/lpalmes/graphql-go/introspection"
"github.com/lpalmes/graphql-go/log"
"github.com/lpalmes/graphql-go/trace"
)

// ParseSchema parses a GraphQL schema and attaches the given root resolver. It returns an error if
Expand Down Expand Up @@ -109,6 +109,13 @@ func (s *Schema) Validate(queryString string) []*errors.QueryError {
return validation.Validate(s.schema, doc)
}

func (s *Schema) ExecSubscription(ctx context.Context, queryString string, operationName string, variables map[string]interface{}, payload interface{}) *Response {
if s.res == nil {
panic("schema created without resolver, can not exec")
}
return s.exec(ctx, queryString, operationName, variables, s.res)
}

// Exec executes the given query with the schema's resolver. It panics if the schema was created
// without a resolver. If the context get cancelled, no further resolvers will be called and a
// the context error will be returned as soon as possible (not immediately).
Expand Down
6 changes: 3 additions & 3 deletions graphql_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import (
"testing"
"time"

"github.com/neelance/graphql-go"
"github.com/neelance/graphql-go/example/starwars"
"github.com/neelance/graphql-go/gqltesting"
"github.com/lpalmes/graphql-go"
"github.com/lpalmes/graphql-go/example/starwars"
"github.com/lpalmes/graphql-go/gqltesting"
)

type helloWorldResolver1 struct{}
Expand Down
2 changes: 1 addition & 1 deletion internal/common/lexer.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"fmt"
"text/scanner"

"github.com/neelance/graphql-go/errors"
"github.com/lpalmes/graphql-go/errors"
)

type syntaxError string
Expand Down
2 changes: 1 addition & 1 deletion internal/common/literals.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"strings"
"text/scanner"

"github.com/neelance/graphql-go/errors"
"github.com/lpalmes/graphql-go/errors"
)

type Literal interface {
Expand Down
2 changes: 1 addition & 1 deletion internal/common/types.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package common

import (
"github.com/neelance/graphql-go/errors"
"github.com/lpalmes/graphql-go/errors"
)

type Type interface {
Expand Down
2 changes: 1 addition & 1 deletion internal/common/values.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package common

import (
"github.com/neelance/graphql-go/errors"
"github.com/lpalmes/graphql-go/errors"
)

type InputValue struct {
Expand Down
17 changes: 9 additions & 8 deletions internal/exec/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ import (
"reflect"
"sync"

"github.com/neelance/graphql-go/errors"
"github.com/neelance/graphql-go/internal/common"
"github.com/neelance/graphql-go/internal/exec/resolvable"
"github.com/neelance/graphql-go/internal/exec/selected"
"github.com/neelance/graphql-go/internal/query"
"github.com/neelance/graphql-go/internal/schema"
"github.com/neelance/graphql-go/log"
"github.com/neelance/graphql-go/trace"
"github.com/lpalmes/graphql-go/errors"
"github.com/lpalmes/graphql-go/internal/common"
"github.com/lpalmes/graphql-go/internal/exec/resolvable"
"github.com/lpalmes/graphql-go/internal/exec/selected"
"github.com/lpalmes/graphql-go/internal/query"
"github.com/lpalmes/graphql-go/internal/schema"
"github.com/lpalmes/graphql-go/log"
"github.com/lpalmes/graphql-go/trace"
)

type Request struct {
Expand Down Expand Up @@ -185,6 +185,7 @@ func execFieldSelection(ctx context.Context, r *Request, f *fieldToExec, path *p
if f.field.ArgsPacker != nil {
in = append(in, f.field.PackedArgs)
}

callOut := f.resolver.Method(f.field.MethodIndex).Call(in)
result = callOut[0]
if f.field.HasError && !callOut[1].IsNil() {
Expand Down
6 changes: 3 additions & 3 deletions internal/exec/packer/packer.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import (
"reflect"
"strings"

"github.com/neelance/graphql-go/errors"
"github.com/neelance/graphql-go/internal/common"
"github.com/neelance/graphql-go/internal/schema"
"github.com/lpalmes/graphql-go/errors"
"github.com/lpalmes/graphql-go/internal/common"
"github.com/lpalmes/graphql-go/internal/schema"
)

type packer interface {
Expand Down
6 changes: 3 additions & 3 deletions internal/exec/resolvable/meta.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import (
"fmt"
"reflect"

"github.com/neelance/graphql-go/internal/common"
"github.com/neelance/graphql-go/internal/schema"
"github.com/neelance/graphql-go/introspection"
"github.com/lpalmes/graphql-go/internal/common"
"github.com/lpalmes/graphql-go/internal/schema"
"github.com/lpalmes/graphql-go/introspection"
)

var MetaSchema *Object
Expand Down
Loading

0 comments on commit 6e1ef80

Please sign in to comment.