func Unmarshal(resp http.ResponseWriter, req *http.Request, value interface{}) error { defer req.Body.Close() contentType := ContentTypeForRequest(req) if t, err := encoding.ContentTypeFromString(contentType); err == nil { err := encoding.Unmarshal(t, req.Body, value) if err != nil { DefaultErrorRenderer(resp, req, err.Error(), http.StatusInternalServerError) return err } } else { DefaultErrorRenderer(resp, req, ErrBadContentType.Error(), http.StatusBadRequest) return err } return nil }
// This test here shows how to implement two stages of configuring an object. // First a field in the struct gets the source of the config url from the command line flags. // Second, the config is fetched and unmarshalled to the object. // Finally, we parse again so that additional flag values are overlaid onto the struct. func (suite *TestSuiteCommand) TestCommandReparseFlag(c *C) { Register("person", func() (Module, ErrorHandling) { return new(person), PanicOnError }) // Generate the auth token required by the server. token := auth.NewToken(1*time.Hour).Add("secure", 1) header := http.Header{} token.SetHeader(header, testutil.PrivateKeyFunc) ctx := resource.ContextPutHttpHeader(context.Background(), header) suite.template = ` name: joe age: 21 employee: false not-a-field: hello ` p := &person{ Age: 18, Employee: true, } RunModule("person", p, strings.Split("--config_url=http://localhost:7986/secure --age=35", " "), nil) c.Assert(p.ConfigUrl, Equals, "http://localhost:7986/secure") c.Assert(p.Employee, Equals, true) data, err := resource.Fetch(ctx, p.ConfigUrl) c.Assert(err, IsNil) c.Log(string(data)) err = encoding.Unmarshal(encoding.ContentTypeYAML, bytes.NewBuffer(data), p) c.Assert(err, IsNil) c.Assert(p.Age, Equals, 21) c.Assert(p.Name, Equals, "joe") c.Assert(p.Employee, Equals, true) // we don't expect the yaml to change the field. ReparseFlags(p) c.Assert(p.Age, Equals, 35) // This is overwritten by the flag value c.Assert(p.Name, Equals, "joe") c.Assert(p.Employee, Equals, true) }
// 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) }