Skip to content

Instantly share code, notes, and snippets.

@dollarkillerx
Last active April 13, 2020 15:49
Show Gist options
  • Save dollarkillerx/eed825727fe7a54a7083f7534a12098d to your computer and use it in GitHub Desktop.
Save dollarkillerx/eed825727fe7a54a7083f7534a12098d to your computer and use it in GitHub Desktop.
gqlgen源码分析.md
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, &params); 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
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment