Add support for client that uses GET as transport mechanism (#186)
Current implementation always uses POST as the transport mechanism. Adding GET support enables usage of GET queries for caching simply via URL. Some notes: - I left the existing API for creating a new client as is, but the implementation could be much cleaner by introducing some sort of configuration struct when creating a new client - The construction of the query parameters follows the logic from Apollo's client implementation, which can be found here https://github.com/apollographql/apollo-client/blob/8beb4820edc6352996e08f7f73bde3573f1eb666/src/link/http/rewriteURIForGET.ts - Updated integration tests to use both sets of clients. Updating the tests to use a test suite would be cleaner
This commit is contained in:
@@ -35,6 +35,7 @@ type Config struct {
|
||||
}
|
||||
|
||||
type ResolverRoot interface {
|
||||
Mutation() MutationResolver
|
||||
Query() QueryResolver
|
||||
}
|
||||
|
||||
@@ -58,6 +59,10 @@ type ComplexityRoot struct {
|
||||
Color func(childComplexity int) int
|
||||
}
|
||||
|
||||
Mutation struct {
|
||||
CreateUser func(childComplexity int, input NewUser) int
|
||||
}
|
||||
|
||||
Query struct {
|
||||
Being func(childComplexity int, id string) int
|
||||
Beings func(childComplexity int, ids []string) int
|
||||
@@ -80,6 +85,9 @@ type ComplexityRoot struct {
|
||||
}
|
||||
}
|
||||
|
||||
type MutationResolver interface {
|
||||
CreateUser(ctx context.Context, input NewUser) (*User, error)
|
||||
}
|
||||
type QueryResolver interface {
|
||||
Me(ctx context.Context) (*User, error)
|
||||
User(ctx context.Context, id *string) (*User, error)
|
||||
@@ -156,6 +164,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
||||
|
||||
return e.complexity.Hair.Color(childComplexity), true
|
||||
|
||||
case "Mutation.createUser":
|
||||
if e.complexity.Mutation.CreateUser == nil {
|
||||
break
|
||||
}
|
||||
|
||||
args, err := ec.field_Mutation_createUser_args(context.TODO(), rawArgs)
|
||||
if err != nil {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
return e.complexity.Mutation.CreateUser(childComplexity, args["input"].(NewUser)), true
|
||||
|
||||
case "Query.being":
|
||||
if e.complexity.Query.Being == nil {
|
||||
break
|
||||
@@ -316,6 +336,20 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler {
|
||||
var buf bytes.Buffer
|
||||
data.MarshalGQL(&buf)
|
||||
|
||||
return &graphql.Response{
|
||||
Data: buf.Bytes(),
|
||||
}
|
||||
}
|
||||
case ast.Mutation:
|
||||
return func(ctx context.Context) *graphql.Response {
|
||||
if !first {
|
||||
return nil
|
||||
}
|
||||
first = false
|
||||
data := ec._Mutation(ctx, rc.Operation.SelectionSet)
|
||||
var buf bytes.Buffer
|
||||
data.MarshalGQL(&buf)
|
||||
|
||||
return &graphql.Response{
|
||||
Data: buf.Bytes(),
|
||||
}
|
||||
@@ -360,6 +394,10 @@ type Query {
|
||||
fail: Boolean
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
createUser(input: NewUser!): User!
|
||||
}
|
||||
|
||||
type User implements Being & Lucky {
|
||||
id: ID!
|
||||
name: String!
|
||||
@@ -369,6 +407,10 @@ type User implements Being & Lucky {
|
||||
friends: [User!]!
|
||||
}
|
||||
|
||||
input NewUser {
|
||||
name: String!
|
||||
}
|
||||
|
||||
type Hair { color: String } # silly name to confuse the name-generator
|
||||
|
||||
type Animal implements Being {
|
||||
@@ -402,6 +444,21 @@ var parsedSchema = gqlparser.MustLoadSchema(sources...)
|
||||
|
||||
// region ***************************** args.gotpl *****************************
|
||||
|
||||
func (ec *executionContext) field_Mutation_createUser_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
||||
var err error
|
||||
args := map[string]interface{}{}
|
||||
var arg0 NewUser
|
||||
if tmp, ok := rawArgs["input"]; ok {
|
||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("input"))
|
||||
arg0, err = ec.unmarshalNNewUser2githubᚗcomᚋKhanᚋgenqlientᚋinternalᚋintegrationᚋserverᚐNewUser(ctx, tmp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
args["input"] = arg0
|
||||
return args, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) field_Query___type_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
||||
var err error
|
||||
args := map[string]interface{}{}
|
||||
@@ -805,6 +862,48 @@ func (ec *executionContext) _Hair_color(ctx context.Context, field graphql.Colle
|
||||
return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Mutation_createUser(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ec.Error(ctx, ec.Recover(ctx, r))
|
||||
ret = graphql.Null
|
||||
}
|
||||
}()
|
||||
fc := &graphql.FieldContext{
|
||||
Object: "Mutation",
|
||||
Field: field,
|
||||
Args: nil,
|
||||
IsMethod: true,
|
||||
IsResolver: true,
|
||||
}
|
||||
|
||||
ctx = graphql.WithFieldContext(ctx, fc)
|
||||
rawArgs := field.ArgumentMap(ec.Variables)
|
||||
args, err := ec.field_Mutation_createUser_args(ctx, rawArgs)
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return graphql.Null
|
||||
}
|
||||
fc.Args = args
|
||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||
ctx = rctx // use context from middleware stack in children
|
||||
return ec.resolvers.Mutation().CreateUser(rctx, args["input"].(NewUser))
|
||||
})
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return graphql.Null
|
||||
}
|
||||
if resTmp == nil {
|
||||
if !graphql.HasFieldError(ctx, fc) {
|
||||
ec.Errorf(ctx, "must not be null")
|
||||
}
|
||||
return graphql.Null
|
||||
}
|
||||
res := resTmp.(*User)
|
||||
fc.Result = res
|
||||
return ec.marshalNUser2ᚖgithubᚗcomᚋKhanᚋgenqlientᚋinternalᚋintegrationᚋserverᚐUser(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Query_me(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
@@ -2609,6 +2708,29 @@ func (ec *executionContext) ___Type_specifiedByURL(ctx context.Context, field gr
|
||||
|
||||
// region **************************** input.gotpl *****************************
|
||||
|
||||
func (ec *executionContext) unmarshalInputNewUser(ctx context.Context, obj interface{}) (NewUser, error) {
|
||||
var it NewUser
|
||||
asMap := map[string]interface{}{}
|
||||
for k, v := range obj.(map[string]interface{}) {
|
||||
asMap[k] = v
|
||||
}
|
||||
|
||||
for k, v := range asMap {
|
||||
switch k {
|
||||
case "name":
|
||||
var err error
|
||||
|
||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name"))
|
||||
it.Name, err = ec.unmarshalNString2string(ctx, v)
|
||||
if err != nil {
|
||||
return it, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return it, nil
|
||||
}
|
||||
|
||||
// endregion **************************** input.gotpl *****************************
|
||||
|
||||
// region ************************** interface.gotpl ***************************
|
||||
@@ -2780,6 +2902,46 @@ func (ec *executionContext) _Hair(ctx context.Context, sel ast.SelectionSet, obj
|
||||
return out
|
||||
}
|
||||
|
||||
var mutationImplementors = []string{"Mutation"}
|
||||
|
||||
func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet) graphql.Marshaler {
|
||||
fields := graphql.CollectFields(ec.OperationContext, sel, mutationImplementors)
|
||||
ctx = graphql.WithFieldContext(ctx, &graphql.FieldContext{
|
||||
Object: "Mutation",
|
||||
})
|
||||
|
||||
out := graphql.NewFieldSet(fields)
|
||||
var invalids uint32
|
||||
for i, field := range fields {
|
||||
innerCtx := graphql.WithRootFieldContext(ctx, &graphql.RootFieldContext{
|
||||
Object: field.Name,
|
||||
Field: field,
|
||||
})
|
||||
|
||||
switch field.Name {
|
||||
case "__typename":
|
||||
out.Values[i] = graphql.MarshalString("Mutation")
|
||||
case "createUser":
|
||||
innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
|
||||
return ec._Mutation_createUser(ctx, field)
|
||||
}
|
||||
|
||||
out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, innerFunc)
|
||||
|
||||
if out.Values[i] == graphql.Null {
|
||||
invalids++
|
||||
}
|
||||
default:
|
||||
panic("unknown field " + strconv.Quote(field.Name))
|
||||
}
|
||||
}
|
||||
out.Dispatch()
|
||||
if invalids > 0 {
|
||||
return graphql.Null
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
var queryImplementors = []string{"Query"}
|
||||
|
||||
func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) graphql.Marshaler {
|
||||
@@ -3670,6 +3832,11 @@ func (ec *executionContext) marshalNInt2int(ctx context.Context, sel ast.Selecti
|
||||
return res
|
||||
}
|
||||
|
||||
func (ec *executionContext) unmarshalNNewUser2githubᚗcomᚋKhanᚋgenqlientᚋinternalᚋintegrationᚋserverᚐNewUser(ctx context.Context, v interface{}) (NewUser, error) {
|
||||
res, err := ec.unmarshalInputNewUser(ctx, v)
|
||||
return res, graphql.ErrorOnPath(ctx, err)
|
||||
}
|
||||
|
||||
func (ec *executionContext) unmarshalNSpecies2githubᚗcomᚋKhanᚋgenqlientᚋinternalᚋintegrationᚋserverᚐSpecies(ctx context.Context, v interface{}) (Species, error) {
|
||||
var res Species
|
||||
err := res.UnmarshalGQL(v)
|
||||
@@ -3695,6 +3862,10 @@ func (ec *executionContext) marshalNString2string(ctx context.Context, sel ast.S
|
||||
return res
|
||||
}
|
||||
|
||||
func (ec *executionContext) marshalNUser2githubᚗcomᚋKhanᚋgenqlientᚋinternalᚋintegrationᚋserverᚐUser(ctx context.Context, sel ast.SelectionSet, v User) graphql.Marshaler {
|
||||
return ec._User(ctx, sel, &v)
|
||||
}
|
||||
|
||||
func (ec *executionContext) marshalNUser2ᚕᚖgithubᚗcomᚋKhanᚋgenqlientᚋinternalᚋintegrationᚋserverᚐUserᚄ(ctx context.Context, sel ast.SelectionSet, v []*User) graphql.Marshaler {
|
||||
ret := make(graphql.Array, len(v))
|
||||
var wg sync.WaitGroup
|
||||
|
||||
@@ -34,6 +34,10 @@ type Hair struct {
|
||||
Color *string `json:"color"`
|
||||
}
|
||||
|
||||
type NewUser struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type User struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http/httptest"
|
||||
"strconv"
|
||||
|
||||
"github.com/99designs/gqlgen/graphql"
|
||||
"github.com/99designs/gqlgen/graphql/handler"
|
||||
@@ -73,6 +74,24 @@ func beingByID(id string) Being {
|
||||
return nil
|
||||
}
|
||||
|
||||
func getNewID() string {
|
||||
maxID := 0
|
||||
for _, user := range users {
|
||||
intID, _ := strconv.Atoi(user.ID)
|
||||
if intID > maxID {
|
||||
maxID = intID
|
||||
}
|
||||
}
|
||||
for _, animal := range animals {
|
||||
intID, _ := strconv.Atoi(animal.ID)
|
||||
if intID > maxID {
|
||||
maxID = intID
|
||||
}
|
||||
}
|
||||
newID := maxID + 1
|
||||
return strconv.Itoa(newID)
|
||||
}
|
||||
|
||||
func (r *queryResolver) Me(ctx context.Context) (*User, error) {
|
||||
return userByID("1"), nil
|
||||
}
|
||||
@@ -129,9 +148,16 @@ func (r *queryResolver) Fail(ctx context.Context) (*bool, error) {
|
||||
return &f, fmt.Errorf("oh no")
|
||||
}
|
||||
|
||||
func (m mutationResolver) CreateUser(ctx context.Context, input NewUser) (*User, error) {
|
||||
newUser := User{ID: getNewID(), Name: input.Name, Friends: []*User{}}
|
||||
users = append(users, &newUser)
|
||||
return &newUser, nil
|
||||
}
|
||||
|
||||
func RunServer() *httptest.Server {
|
||||
gqlgenServer := handler.New(NewExecutableSchema(Config{Resolvers: &resolver{}}))
|
||||
gqlgenServer.AddTransport(transport.POST{})
|
||||
gqlgenServer.AddTransport(transport.GET{})
|
||||
gqlgenServer.AroundResponses(func(ctx context.Context, next graphql.ResponseHandler) *graphql.Response {
|
||||
graphql.RegisterExtension(ctx, "foobar", "test")
|
||||
return next(ctx)
|
||||
@@ -140,10 +166,15 @@ func RunServer() *httptest.Server {
|
||||
}
|
||||
|
||||
type (
|
||||
resolver struct{}
|
||||
queryResolver struct{}
|
||||
resolver struct{}
|
||||
queryResolver struct{}
|
||||
mutationResolver struct{}
|
||||
)
|
||||
|
||||
func (r *resolver) Mutation() MutationResolver {
|
||||
return &mutationResolver{}
|
||||
}
|
||||
|
||||
func (r *resolver) Query() QueryResolver { return &queryResolver{} }
|
||||
|
||||
//go:generate go run github.com/99designs/gqlgen
|
||||
|
||||
Reference in New Issue
Block a user