func Process()

in lib/handlerfactory/request_handler.go [82:169]


func Process(s storage.Store, opts *Options, r *http.Request) (_ proto.Message, ferr error) {
	defer func() {
		if c := recover(); c != nil {
			glog.Errorf("CRASH %s %s: %v\n%s", r.Method, r.URL.Path, c, string(debug.Stack()))
			if ferr == nil {
				ferr = status.Errorf(codes.Internal, "internal error")
			}
		}
	}()

	hi := opts.Service()
	var op func(*http.Request, string) (proto.Message, error)
	switch r.Method {
	case http.MethodGet:
		op = hi.Get
	case http.MethodPost:
		op = hi.Post
	case http.MethodPut:
		op = hi.Put
	case http.MethodPatch:
		op = hi.Patch
	case http.MethodDelete:
		op = hi.Remove
	default:
		return nil, status.Errorf(codes.InvalidArgument, "request method not supported: %q", r.Method)
	}

	// TODO: move inside each service and don't pass NameChecker here.
	name, vars, err := ValidateResourceName(r, opts.NameField, opts.NameChecker)
	if err != nil {
		return nil, status.Errorf(codes.InvalidArgument, "%v", err)
	}
	typ := opts.TypeName
	desc := r.Method + " " + typ

	tx, err := s.Tx(r.Method != http.MethodGet)
	if err != nil {
		return nil, status.Errorf(codes.Unavailable, "service dependencies not available; try again later")
	}
	defer func() {
		err := tx.Finish()
		if ferr == nil {
			ferr = err
		}
	}()

	// Get rid of Setup and move creation of transaction inside service methods.
	//
	if _, err = hi.Setup(r, tx); err != nil {
		return nil, err
	}

	// TODO: Replace NormalizeInput with a ParseReq that returns a request proto message.
	// TODO: Explicitly pass the message to the service methods.
	if err := hi.NormalizeInput(r, name, vars); err != nil {
		return nil, toStatusErr(codes.InvalidArgument, err, r)
	}

	// TODO: get rid of LookupItem and move this inside the service methods.
	exists := hi.LookupItem(r, name, vars)
	switch r.Method {
	case http.MethodPost:
		if exists {
			return nil, status.Errorf(codes.AlreadyExists, "%s already exists: %q", typ, name)
		}
	case http.MethodGet, http.MethodPatch, http.MethodPut, http.MethodDelete:
		if !exists {
			if opts.HasNamedIdentifiers {
				return nil, status.Errorf(codes.NotFound, "%s not found: %q", typ, name)
			}
			return nil, status.Errorf(codes.NotFound, "%s not found", typ)
		}
	}

	if r.Method == http.MethodGet {
		resp, err := op(r, name)
		if err != nil {
			return nil, toStatusErr(codes.InvalidArgument, err, r)
		}
		return resp, nil
	}

	resp, err := RunRMWTx(r, tx, op, hi.CheckIntegrity, hi.Save, name, vars, typ, desc)
	if err != nil {
		return nil, err
	}
	return resp, nil
}