func Marshal(resp http.ResponseWriter, req *http.Request, value interface{}) error { contentType := ContentTypeForResponse(req) if t, err := encoding.ContentTypeFromString(contentType); err == nil { buff := new(bytes.Buffer) err := encoding.Marshal(t, buff, value) if err != nil { DefaultErrorRenderer(resp, req, err.Error(), http.StatusInternalServerError) return err } resp.Header().Add("Content-Type", t.String()) resp.Write(buff.Bytes()) } else { DefaultErrorRenderer(resp, req, ErrBadContentType.Error(), http.StatusBadRequest) return err } return nil }
// Run the configuration specified in conf against the target. This will run a series // of template fetching, applying templates, unmarshaling of the final applied template // onto the given target object. After unmarshaling is done, the target's fields are // examined one by one, by tag, and fields that have template as values are then applied. func Configure(ctx context.Context, conf Conf, target interface{}, optionalFuncs ...template.FuncMap) error { conf.lock.Lock() defer conf.lock.Unlock() initialData := ContextGetInitialData(ctx) if initialData != nil { gtemplate.ContextPutTemplateData(ctx, initialData) } contentType := ContextGetConfigDataType(ctx) // Generate a list of functions that will escape the template strings // Ex. "secret" : "{{var "zk://host/path/to/secret"}}" // This string will be escaped so that the evaluation happens after the unmarshal step by field tag funcs := template.FuncMap{} for _, fns := range optionalFuncs { funcs = gtemplate.MergeFuncMaps(funcs, fns) } // Note here we generate escaped versions of function to override what's provided. // The actual funcs are used in the struct field-by-field step, for those that are marked by tags. stubs := gtemplate.MergeFuncMaps(funcs, generateEscapeFuncsFromFieldTag(target)) conf.model = map[string]interface{}{} for _, url := range conf.Urls { // Fetch the config data and execute as if it were template applied, err := gtemplate.Execute(ctx, url, stubs) if conf.OnDoneExecuteLayer != nil { conf.OnDoneExecuteLayer(&conf, url, applied, err) } if err != nil { return err } // Unmarshal to an intermediate representation buff := bytes.NewBuffer(applied) err = encoding.Unmarshal(contentType, buff, conf.model) if conf.OnDoneUnmarshalLayer != nil { conf.OnDoneUnmarshalLayer(&conf, url, err) } if err != nil { return err } } if conf.OnDoneFetching != nil { conf.OnDoneFetching(&conf) } // Now marshal the aggregated model to a buffer and then unmarshal it back to the typed struct serialized := new(bytes.Buffer) err := encoding.Marshal(contentType, serialized, conf.model) if err != nil { return err } conf.serialized = serialized.Bytes() err = encoding.Unmarshal(contentType, bytes.NewBuffer(conf.serialized), target) if conf.OnDoneSerialize != nil { conf.OnDoneSerialize(&conf, err) } if err != nil { return err } if conf.OnDoneUnmarshal != nil { conf.OnDoneUnmarshal(&conf, target) } // Now look for fields with struct tags and apply the actual templates return evalStructFieldTemplates(target, funcs) }