github.com/maeglindeveloper/gqlgen@v0.13.1-0.20210413081235-57808b12a0a0/graphql/executor/extensions.go (about)

     1  package executor
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  
     7  	"github.com/99designs/gqlgen/graphql"
     8  )
     9  
    10  // Use adds the given extension to this Executor.
    11  func (e *Executor) Use(extension graphql.HandlerExtension) {
    12  	if err := extension.Validate(e.es); err != nil {
    13  		panic(err)
    14  	}
    15  
    16  	switch extension.(type) {
    17  	case graphql.OperationParameterMutator,
    18  		graphql.OperationContextMutator,
    19  		graphql.OperationInterceptor,
    20  		graphql.FieldInterceptor,
    21  		graphql.ResponseInterceptor:
    22  		e.extensions = append(e.extensions, extension)
    23  		e.ext = processExtensions(e.extensions)
    24  
    25  	default:
    26  		panic(fmt.Errorf("cannot Use %T as a gqlgen handler extension because it does not implement any extension hooks", extension))
    27  	}
    28  }
    29  
    30  // AroundFields is a convenience method for creating an extension that only implements field middleware
    31  func (e *Executor) AroundFields(f graphql.FieldMiddleware) {
    32  	e.Use(aroundFieldFunc(f))
    33  }
    34  
    35  // AroundOperations is a convenience method for creating an extension that only implements operation middleware
    36  func (e *Executor) AroundOperations(f graphql.OperationMiddleware) {
    37  	e.Use(aroundOpFunc(f))
    38  }
    39  
    40  // AroundResponses is a convenience method for creating an extension that only implements response middleware
    41  func (e *Executor) AroundResponses(f graphql.ResponseMiddleware) {
    42  	e.Use(aroundRespFunc(f))
    43  }
    44  
    45  type extensions struct {
    46  	operationMiddleware        graphql.OperationMiddleware
    47  	responseMiddleware         graphql.ResponseMiddleware
    48  	fieldMiddleware            graphql.FieldMiddleware
    49  	operationParameterMutators []graphql.OperationParameterMutator
    50  	operationContextMutators   []graphql.OperationContextMutator
    51  }
    52  
    53  func processExtensions(exts []graphql.HandlerExtension) extensions {
    54  	e := extensions{
    55  		operationMiddleware: func(ctx context.Context, next graphql.OperationHandler) graphql.ResponseHandler {
    56  			return next(ctx)
    57  		},
    58  		responseMiddleware: func(ctx context.Context, next graphql.ResponseHandler) *graphql.Response {
    59  			return next(ctx)
    60  		},
    61  		fieldMiddleware: func(ctx context.Context, next graphql.Resolver) (res interface{}, err error) {
    62  			return next(ctx)
    63  		},
    64  	}
    65  
    66  	// this loop goes backwards so the first extension is the outer most middleware and runs first.
    67  	for i := len(exts) - 1; i >= 0; i-- {
    68  		p := exts[i]
    69  		if p, ok := p.(graphql.OperationInterceptor); ok {
    70  			previous := e.operationMiddleware
    71  			e.operationMiddleware = func(ctx context.Context, next graphql.OperationHandler) graphql.ResponseHandler {
    72  				return p.InterceptOperation(ctx, func(ctx context.Context) graphql.ResponseHandler {
    73  					return previous(ctx, next)
    74  				})
    75  			}
    76  		}
    77  
    78  		if p, ok := p.(graphql.ResponseInterceptor); ok {
    79  			previous := e.responseMiddleware
    80  			e.responseMiddleware = func(ctx context.Context, next graphql.ResponseHandler) *graphql.Response {
    81  				return p.InterceptResponse(ctx, func(ctx context.Context) *graphql.Response {
    82  					return previous(ctx, next)
    83  				})
    84  			}
    85  		}
    86  
    87  		if p, ok := p.(graphql.FieldInterceptor); ok {
    88  			previous := e.fieldMiddleware
    89  			e.fieldMiddleware = func(ctx context.Context, next graphql.Resolver) (res interface{}, err error) {
    90  				return p.InterceptField(ctx, func(ctx context.Context) (res interface{}, err error) {
    91  					return previous(ctx, next)
    92  				})
    93  			}
    94  		}
    95  	}
    96  
    97  	for _, p := range exts {
    98  		if p, ok := p.(graphql.OperationParameterMutator); ok {
    99  			e.operationParameterMutators = append(e.operationParameterMutators, p)
   100  		}
   101  
   102  		if p, ok := p.(graphql.OperationContextMutator); ok {
   103  			e.operationContextMutators = append(e.operationContextMutators, p)
   104  		}
   105  	}
   106  
   107  	return e
   108  }
   109  
   110  type aroundOpFunc func(ctx context.Context, next graphql.OperationHandler) graphql.ResponseHandler
   111  
   112  func (r aroundOpFunc) ExtensionName() string {
   113  	return "InlineOperationFunc"
   114  }
   115  
   116  func (r aroundOpFunc) Validate(schema graphql.ExecutableSchema) error {
   117  	if r == nil {
   118  		return fmt.Errorf("OperationFunc can not be nil")
   119  	}
   120  	return nil
   121  }
   122  
   123  func (r aroundOpFunc) InterceptOperation(ctx context.Context, next graphql.OperationHandler) graphql.ResponseHandler {
   124  	return r(ctx, next)
   125  }
   126  
   127  type aroundRespFunc func(ctx context.Context, next graphql.ResponseHandler) *graphql.Response
   128  
   129  func (r aroundRespFunc) ExtensionName() string {
   130  	return "InlineResponseFunc"
   131  }
   132  
   133  func (r aroundRespFunc) Validate(schema graphql.ExecutableSchema) error {
   134  	if r == nil {
   135  		return fmt.Errorf("ResponseFunc can not be nil")
   136  	}
   137  	return nil
   138  }
   139  
   140  func (r aroundRespFunc) InterceptResponse(ctx context.Context, next graphql.ResponseHandler) *graphql.Response {
   141  	return r(ctx, next)
   142  }
   143  
   144  type aroundFieldFunc func(ctx context.Context, next graphql.Resolver) (res interface{}, err error)
   145  
   146  func (f aroundFieldFunc) ExtensionName() string {
   147  	return "InlineFieldFunc"
   148  }
   149  
   150  func (f aroundFieldFunc) Validate(schema graphql.ExecutableSchema) error {
   151  	if f == nil {
   152  		return fmt.Errorf("FieldFunc can not be nil")
   153  	}
   154  	return nil
   155  }
   156  
   157  func (f aroundFieldFunc) InterceptField(ctx context.Context, next graphql.Resolver) (res interface{}, err error) {
   158  	return f(ctx, next)
   159  }