github.com/mstephano/gqlgen-schemagen@v0.0.0-20230113041936-dd2cd4ea46aa/graphql/handler/transport/http_post.go (about)

     1  package transport
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"log"
     7  	"mime"
     8  	"net/http"
     9  	"strings"
    10  
    11  	"github.com/vektah/gqlparser/v2/gqlerror"
    12  
    13  	"github.com/mstephano/gqlgen-schemagen/graphql"
    14  )
    15  
    16  // POST implements the POST side of the default HTTP transport
    17  // defined in https://github.com/APIs-guru/graphql-over-http#post
    18  type POST struct{}
    19  
    20  var _ graphql.Transport = POST{}
    21  
    22  func (h POST) Supports(r *http.Request) bool {
    23  	if r.Header.Get("Upgrade") != "" {
    24  		return false
    25  	}
    26  
    27  	mediaType, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
    28  	if err != nil {
    29  		return false
    30  	}
    31  
    32  	return r.Method == "POST" && mediaType == "application/json"
    33  }
    34  
    35  func getRequestBody(r *http.Request) (string, error) {
    36  	if r == nil || r.Body == nil {
    37  		return "", nil
    38  	}
    39  	body, err := io.ReadAll(r.Body)
    40  	if err != nil {
    41  		return "", fmt.Errorf("unable to get Request Body %w", err)
    42  	}
    43  	return string(body), nil
    44  }
    45  
    46  func (h POST) Do(w http.ResponseWriter, r *http.Request, exec graphql.GraphExecutor) {
    47  	ctx := r.Context()
    48  	w.Header().Set("Content-Type", "application/json")
    49  	params := &graphql.RawParams{}
    50  	start := graphql.Now()
    51  	params.Headers = r.Header
    52  	params.ReadTime = graphql.TraceTiming{
    53  		Start: start,
    54  		End:   graphql.Now(),
    55  	}
    56  
    57  	bodyString, err := getRequestBody(r)
    58  	if err != nil {
    59  		gqlErr := gqlerror.Errorf("could not get json request body: %+v", err)
    60  		resp := exec.DispatchError(ctx, gqlerror.List{gqlErr})
    61  		log.Printf("could not get json request body: %+v", err.Error())
    62  		writeJson(w, resp)
    63  	}
    64  
    65  	bodyReader := io.NopCloser(strings.NewReader(bodyString))
    66  	if err = jsonDecode(bodyReader, &params); err != nil {
    67  		w.WriteHeader(http.StatusBadRequest)
    68  		gqlErr := gqlerror.Errorf(
    69  			"json request body could not be decoded: %+v body:%s",
    70  			err,
    71  			bodyString,
    72  		)
    73  		resp := exec.DispatchError(ctx, gqlerror.List{gqlErr})
    74  		log.Printf("decoding error: %+v body:%s", err.Error(), bodyString)
    75  		writeJson(w, resp)
    76  		return
    77  	}
    78  
    79  	rc, OpErr := exec.CreateOperationContext(ctx, params)
    80  	if OpErr != nil {
    81  		w.WriteHeader(statusFor(OpErr))
    82  		resp := exec.DispatchError(graphql.WithOperationContext(ctx, rc), OpErr)
    83  		writeJson(w, resp)
    84  		return
    85  	}
    86  
    87  	var responses graphql.ResponseHandler
    88  	responses, ctx = exec.DispatchOperation(ctx, rc)
    89  	writeJson(w, responses(ctx))
    90  }