srv := handler.NewDefaultServer(generated.NewExecutableSchema(generated.Config{Resolvers: &graph.Resolver{}}))
http.Handle("/", playground.Handler("GraphQL playground", "/query"))
http.Handle("/query", srv)
开头的看点 在这里 http.Handle("/query", srv)
graphql 对http请求的接管 使用handler interface
我们就去找他的ServerHTTP方法看
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
defer func() { # 这边部分主要是 防止 死掉 并返回当前panic抛出的错误
if err := recover(); err != nil {
err := s.exec.PresentRecoveredError(r.Context(), err)
resp := &graphql.Response{Errors: []*gqlerror.Error{err}}
b, _ := json.Marshal(resp)
w.WriteHeader(http.StatusUnprocessableEntity)
w.Write(b)
}
}()
r = r.WithContext(graphql.StartOperationTrace(r.Context())) # 获取context 生命周期
transport := s.getTransport(r) # 进去看源码 里面就是 上面图片说的 协议list 去range 看是属于哪一个协议的
if transport == nil { # 如果都不是
sendErrorf(w, http.StatusBadRequest, "transport not supported")
return
}
transport.Do(w, r, s.exec) # 在那个协议执行 ,s.exec 为 我们通过gqlgen生成的graphql对象
}
func (h POST) Do(w http.ResponseWriter, r *http.Request, exec graphql.GraphExecutor) {
w.Header().Set("Content-Type", "application/json") #设置返回json
var params *graphql.RawParams
start := graphql.Now() # 获取进入时间
if err := jsonDecode(r.Body, ¶ms); err != nil { #因为graphql 根结构体是有规范的所有可以通过 [map]interface解析
w.WriteHeader(http.StatusBadRequest)
writeJsonErrorf(w, "json body could not be decoded: "+err.Error())
return
}
params.ReadTime = graphql.TraceTiming{
Start: start,
End: graphql.Now(), # 统计解析耗时
}
// 此处GOTO C1
rc, err := exec.CreateOperationContext(r.Context(), params) # 此处 说到上面的exec了 编译的时候生成的中间代码 实现了GraphExecutor interface
if err != nil {
w.WriteHeader(statusFor(err))
resp := exec.DispatchError(graphql.WithOperationContext(r.Context(), rc), err)
writeJson(w, resp)
return
}
responses, ctx := exec.DispatchOperation(r.Context(), rc)
writeJson(w, responses(ctx))
}
### RawParams
RawParams struct {
Query string `json:"query"`
OperationName string `json:"operationName"`
Variables map[string]interface{} `json:"variables"`
Extensions map[string]interface{} `json:"extensions"`
ReadTime TraceTiming `json:"-"`
}
C1:
func (e *Executor) CreateOperationContext(ctx context.Context, params *graphql.RawParams) (*graphql.OperationContext, gqlerror.List) {
rc := &graphql.OperationContext{
DisableIntrospection: true,
Recover: e.recoverFunc,
ResolverMiddleware: e.ext.fieldMiddleware,
Stats: graphql.Stats{
Read: params.ReadTime,
OperationStart: graphql.GetStartTime(ctx),
},
}
ctx = graphql.WithOperationContext(ctx, rc)
for _, p := range e.ext.operationParameterMutators {
if err := p.MutateOperationParameters(ctx, params); err != nil {
return rc, gqlerror.List{err}
}
}
rc.RawQuery = params.Query
rc.OperationName = params.OperationName
var listErr gqlerror.List
rc.Doc, listErr = e.parseQuery(ctx, &rc.Stats, params.Query)
if len(listErr) != 0 {
return rc, listErr
}
rc.Operation = rc.Doc.Operations.ForName(params.OperationName)
if rc.Operation == nil {
return rc, gqlerror.List{gqlerror.Errorf("operation %s not found", params.OperationName)}
}
var err *gqlerror.Error
rc.Variables, err = validator.VariableValues(e.es.Schema(), rc.Operation, params.Variables)
if err != nil {
errcode.Set(err, errcode.ValidationFailed)
return rc, gqlerror.List{err}
}
rc.Stats.Validation.End = graphql.Now()
for _, p := range e.ext.operationContextMutators {
if err := p.MutateOperationContext(ctx, rc); err != nil {
return rc, gqlerror.List{err}
}
}
return rc, nil
}