super-graph/serv/http.go

130 lines
2.8 KiB
Go
Raw Permalink Normal View History

2019-03-24 09:57:29 -04:00
package serv
import (
"encoding/json"
"errors"
"io"
"io/ioutil"
"net/http"
"strings"
2019-04-01 08:55:46 -04:00
"time"
2020-03-06 09:47:51 +05:30
"github.com/rs/cors"
2019-03-24 09:57:29 -04:00
)
const (
2019-04-19 01:55:03 -04:00
maxReadBytes = 100000 // 100Kb
2019-03-24 09:57:29 -04:00
introspectionQuery = "IntrospectionQuery"
openVar = "{{"
closeVar = "}}"
)
var (
2019-04-19 01:55:03 -04:00
errUnauthorized = errors.New("not authorized")
2019-03-24 09:57:29 -04:00
)
type gqlReq struct {
2019-09-05 00:09:56 -04:00
OpName string `json:"operationName"`
Query string `json:"query"`
Vars json.RawMessage `json:"variables"`
2019-07-29 01:13:33 -04:00
ref string
role string
2019-09-20 00:19:11 -04:00
hdr http.Header
2019-03-24 09:57:29 -04:00
}
type gqlResp struct {
Error string `json:"message,omitempty"`
Data json.RawMessage `json:"data,omitempty"`
2019-04-04 00:53:24 -04:00
Extensions *extensions `json:"extensions,omitempty"`
2019-04-01 08:55:46 -04:00
}
type extensions struct {
2019-04-04 00:53:24 -04:00
Tracing *trace `json:"tracing,omitempty"`
2019-04-01 08:55:46 -04:00
}
type trace struct {
Version int `json:"version"`
StartTime time.Time `json:"startTime"`
EndTime time.Time `json:"endTime"`
Duration time.Duration `json:"duration"`
Execution execution `json:"execution"`
}
type execution struct {
Resolvers []resolver `json:"resolvers"`
}
type resolver struct {
Path []string `json:"path"`
ParentType string `json:"parentType"`
FieldName string `json:"fieldName"`
ReturnType string `json:"returnType"`
StartOffset int `json:"startOffset"`
Duration time.Duration `json:"duration"`
2019-03-24 09:57:29 -04:00
}
2020-03-06 09:47:51 +05:30
func apiV1Handler() http.Handler {
h := withAuth(http.HandlerFunc(apiV1), conf.Auth)
if len(conf.AllowedOrigins) != 0 {
c := cors.New(cors.Options{
AllowedOrigins: conf.AllowedOrigins,
AllowCredentials: true,
Debug: conf.DebugCORS,
})
h = c.Handler(h)
}
return h
}
2019-12-31 01:30:20 -05:00
func apiV1(w http.ResponseWriter, r *http.Request) {
2019-05-12 19:27:26 -04:00
ctx := &coreContext{Context: r.Context()}
2019-03-24 09:57:29 -04:00
//nolint: errcheck
if conf.AuthFailBlock && !authCheck(ctx) {
w.WriteHeader(http.StatusUnauthorized)
json.NewEncoder(w).Encode(gqlResp{Error: errUnauthorized.Error()})
2019-03-24 09:57:29 -04:00
return
}
2019-04-19 01:55:03 -04:00
b, err := ioutil.ReadAll(io.LimitReader(r.Body, maxReadBytes))
2019-03-24 09:57:29 -04:00
if err != nil {
2019-11-25 02:22:33 -05:00
errlog.Error().Err(err).Msg("failed to read request body")
2019-03-24 09:57:29 -04:00
errorResp(w, err)
return
}
2019-11-15 01:35:19 -05:00
defer r.Body.Close()
2019-03-24 09:57:29 -04:00
2019-06-17 01:58:00 -04:00
err = json.Unmarshal(b, &ctx.req)
if err != nil {
2019-11-25 02:22:33 -05:00
errlog.Error().Err(err).Msg("failed to decode json request body")
2019-03-24 09:57:29 -04:00
errorResp(w, err)
return
}
2019-05-12 19:27:26 -04:00
if strings.EqualFold(ctx.req.OpName, introspectionQuery) {
2019-10-15 02:30:19 -04:00
introspect(w)
2019-03-24 09:57:29 -04:00
return
}
2019-05-12 19:27:26 -04:00
err = ctx.handleReq(w, r)
2019-03-24 09:57:29 -04:00
//nolint: errcheck
2019-04-19 01:55:03 -04:00
if err == errUnauthorized {
w.WriteHeader(http.StatusUnauthorized)
json.NewEncoder(w).Encode(gqlResp{Error: err.Error()})
return
2019-03-24 09:57:29 -04:00
}
if err != nil {
2019-11-25 02:22:33 -05:00
errlog.Error().Err(err).Msg("failed to handle request")
2019-03-24 09:57:29 -04:00
errorResp(w, err)
2019-11-15 01:35:19 -05:00
return
2019-03-24 09:57:29 -04:00
}
2019-04-01 08:55:46 -04:00
}
2019-05-12 19:27:26 -04:00
//nolint: errcheck
2019-05-12 19:27:26 -04:00
func errorResp(w http.ResponseWriter, err error) {
json.NewEncoder(w).Encode(gqlResp{Error: err.Error()})
}