...

Source file src/github.com/99designs/gqlgen/graphql/handler.go

Documentation: github.com/99designs/gqlgen/graphql

     1  package graphql
     2  
     3  import (
     4  	"context"
     5  	"net/http"
     6  	"strconv"
     7  	"strings"
     8  
     9  	"github.com/vektah/gqlparser/v2/gqlerror"
    10  )
    11  
    12  type (
    13  	OperationMiddleware func(ctx context.Context, next OperationHandler) ResponseHandler
    14  	OperationHandler    func(ctx context.Context) ResponseHandler
    15  
    16  	ResponseHandler    func(ctx context.Context) *Response
    17  	ResponseMiddleware func(ctx context.Context, next ResponseHandler) *Response
    18  
    19  	Resolver        func(ctx context.Context) (res interface{}, err error)
    20  	FieldMiddleware func(ctx context.Context, next Resolver) (res interface{}, err error)
    21  
    22  	RootResolver        func(ctx context.Context) Marshaler
    23  	RootFieldMiddleware func(ctx context.Context, next RootResolver) Marshaler
    24  
    25  	RawParams struct {
    26  		Query         string                 `json:"query"`
    27  		OperationName string                 `json:"operationName"`
    28  		Variables     map[string]interface{} `json:"variables"`
    29  		Extensions    map[string]interface{} `json:"extensions"`
    30  		Headers       http.Header            `json:"headers"`
    31  
    32  		ReadTime TraceTiming `json:"-"`
    33  	}
    34  
    35  	GraphExecutor interface {
    36  		CreateOperationContext(ctx context.Context, params *RawParams) (*OperationContext, gqlerror.List)
    37  		DispatchOperation(ctx context.Context, rc *OperationContext) (ResponseHandler, context.Context)
    38  		DispatchError(ctx context.Context, list gqlerror.List) *Response
    39  	}
    40  
    41  	// HandlerExtension adds functionality to the http handler. See the list of possible hook points below
    42  	// Its important to understand the lifecycle of a graphql request and the terminology we use in gqlgen
    43  	// before working with these
    44  	//
    45  	//  +--- REQUEST   POST /graphql --------------------------------------------+
    46  	//  | +- OPERATION query OpName { viewer { name } } -----------------------+ |
    47  	//  | |  RESPONSE  { "data": { "viewer": { "name": "bob" } } }             | |
    48  	//  | +- OPERATION subscription OpName2 { chat { message } } --------------+ |
    49  	//  | |  RESPONSE  { "data": { "chat": { "message": "hello" } } }          | |
    50  	//  | |  RESPONSE  { "data": { "chat": { "message": "byee" } } }           | |
    51  	//  | +--------------------------------------------------------------------+ |
    52  	//  +------------------------------------------------------------------------+
    53  	HandlerExtension interface {
    54  		// ExtensionName should be a CamelCase string version of the extension which may be shown in stats and logging.
    55  		ExtensionName() string
    56  		// Validate is called when adding an extension to the server, it allows validation against the servers schema.
    57  		Validate(schema ExecutableSchema) error
    58  	}
    59  
    60  	// OperationParameterMutator is called before creating a request context. allows manipulating the raw query
    61  	// on the way in.
    62  	OperationParameterMutator interface {
    63  		MutateOperationParameters(ctx context.Context, request *RawParams) *gqlerror.Error
    64  	}
    65  
    66  	// OperationContextMutator is called after creating the request context, but before executing the root resolver.
    67  	OperationContextMutator interface {
    68  		MutateOperationContext(ctx context.Context, rc *OperationContext) *gqlerror.Error
    69  	}
    70  
    71  	// OperationInterceptor is called for each incoming query, for basic requests the writer will be invoked once,
    72  	// for subscriptions it will be invoked multiple times.
    73  	OperationInterceptor interface {
    74  		InterceptOperation(ctx context.Context, next OperationHandler) ResponseHandler
    75  	}
    76  
    77  	// ResponseInterceptor is called around each graphql operation response. This can be called many times for a single
    78  	// operation the case of subscriptions.
    79  	ResponseInterceptor interface {
    80  		InterceptResponse(ctx context.Context, next ResponseHandler) *Response
    81  	}
    82  
    83  	RootFieldInterceptor interface {
    84  		InterceptRootField(ctx context.Context, next RootResolver) Marshaler
    85  	}
    86  
    87  	// FieldInterceptor called around each field
    88  	FieldInterceptor interface {
    89  		InterceptField(ctx context.Context, next Resolver) (res interface{}, err error)
    90  	}
    91  
    92  	// Transport provides support for different wire level encodings of graphql requests, eg Form, Get, Post, Websocket
    93  	Transport interface {
    94  		Supports(r *http.Request) bool
    95  		Do(w http.ResponseWriter, r *http.Request, exec GraphExecutor)
    96  	}
    97  )
    98  
    99  type Status int
   100  
   101  func (p *RawParams) AddUpload(upload Upload, key, path string) *gqlerror.Error {
   102  	if !strings.HasPrefix(path, "variables.") {
   103  		return gqlerror.Errorf("invalid operations paths for key %s", key)
   104  	}
   105  
   106  	var ptr interface{} = p.Variables
   107  	parts := strings.Split(path, ".")
   108  
   109  	// skip the first part (variables) because we started there
   110  	for i, p := range parts[1:] {
   111  		last := i == len(parts)-2
   112  		if ptr == nil {
   113  			return gqlerror.Errorf("path is missing \"variables.\" prefix, key: %s, path: %s", key, path)
   114  		}
   115  		if index, parseNbrErr := strconv.Atoi(p); parseNbrErr == nil {
   116  			if last {
   117  				ptr.([]interface{})[index] = upload
   118  			} else {
   119  				ptr = ptr.([]interface{})[index]
   120  			}
   121  		} else {
   122  			if last {
   123  				ptr.(map[string]interface{})[p] = upload
   124  			} else {
   125  				ptr = ptr.(map[string]interface{})[p]
   126  			}
   127  		}
   128  	}
   129  
   130  	return nil
   131  }
   132  

View as plain text