Git Product home page Git Product logo

schema's People

Contributors

cam72cam avatar coreydaley avatar divoxx avatar elimisteve avatar elithrar avatar emil2k avatar frozzare avatar h2570su avatar hjr265 avatar ilgooz avatar ken39arg avatar kisielk avatar kladd avatar kucherenkovova avatar lexszero avatar moraes avatar mssola avatar nvartolomei avatar rafaeljusto avatar rwl avatar rzajac avatar shkw avatar spirozh avatar sqs avatar teburd avatar tkhametov avatar tschaub avatar yuyaabo avatar yyoshiki41 avatar zak905 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

schema's Issues

Proposal: Add Type to ConversionError

I'd like to response graceful error messages to user for given type of invalid field. See new version of ConversionError below. I'd like to implement this. Refer to link for more information: ajg/form#5

e.g.

type ConversionError struct {
    Key   string
    Type reflect.Type
    Index int    
    Err   error  
}

[Feature Request] Ability to set validator

Hi, first thank for your great toolkit!
I'm using gorilla/schema in my app and I hope it can help me with some simple validate.
For example, with s struct:

type Foo struct {
  X string `schema:",url"`
  Y string `schema:",email"`
}

And then given a map of Validator

var validators = map[string]func([]string) error {
  "email":func(ss []string) error {/*...*/},
}

We can decode and check validate error easily.
Thanks

P/s: If you don't have time or maybe this request not suit to the pkg, I hope you can show me some tip to start it myself.

Decode to typed fields fails

Decoder (actually parsePath) doesn't recognise the field names if they are "typed" or if they and/or if they are embedded. See the tests below.

internal/testdata

package testdata
type Aa bool

decoder_test.go

import "./internal/testdata"
s1 := &struct{
     testdata.Aa
}{}
v1 := map[string][]string{
    "Aa": {"true"},
}
decoder := NewDecoder()
_ = decoder.Decode(s1, v1)
if s1.Aa != testdata.Aa(true) {
    t.Errorf("s1: expected %v, got %v", true, s1.Aa)
}

v2 := map[string][]string{
    "F01": {"true"},
}
s2 := &struct{
    F01 testdata.Aa
}{}
_ = decoder.Decode(s2, v2)
if s2.F01 != testdata.Aa(true) {
    t.Errorf("s2: expected %v, got %v", true, s2.F01)
}

Decode to maps

If you know your fields (and their types) only at runtime, there is no way to decode values to them. Structs have to be defined at compile time.

A possible solution would be to support maps as target values. For example:

values := map[string][]string{
    "Name":  {"John"},
    "Age": {"55"},
}
person := make(map[string]interface{})
person["Name"] = new(string)
person["Age"] = new(int)
decoder := schema.NewDecoder()
decoder.Decode(person, values)

There could also be support for nested maps, but I guess it would be ok to just support flat maps with fields like "nested.key".

Other ideas?

Register converter for map type support

Registering a converter for a map field, e.g. decoder.RegisterConverter(map[string]string{}, func (input string) reflect.Value {}), currently fails with a schema: invalid path error.

The issue seems to be that the decoder does not check for registered converters when building structInfo.

schema/cache.go

Line 181 in 64644a2

if conv := c.conv[ft.Kind()]; conv == nil {

Nested slices seem non functional

I'm pretty sure I'm not doing anything obviously silly here and it's possibly that this just isn't supported as it's not explicitly called out in the overview.

At a high level I'm trying to read parameters into a struct that contains a slice of structs. Within that inner most struct I have a slice of strings (think filter parameters, tags, etc). The innermost slice simply doesn't respond as a slice type an attempts to address it as such cause errors to be thrown when parsing the field path.

Repro case follows:

package main

import (
    "encoding/json"
    "fmt"

    "github.com/gorilla/schema"
)

type Outer struct {
    Level1 []Inner
}

type Inner struct {
    Field string
    Slice []string
}

var bad = map[string][]string{
    "Level1.0.Field":   {"field"},
    "Level1.0.Slice.0": {"entry0"},
}

var good = map[string][]string{
    "Level1.0.Field": {"field0"},
    "Level1.1.Field": {"field1"},
    "Level1.2.Field": {"field2"},
    "Level1.2.Slice": {"Field2 - slice entry"},
}

func main() {
    fd := schema.NewDecoder()
    vs := good
    fs := Outer{}

    e := fd.Decode(&fs, vs)
    fmt.Println(e)
    b, e := json.MarshalIndent(fs, "", "  ")
    if e != nil {
        fmt.Println(e)
        return
    }
    fmt.Println(string(b))
    fmt.Printf("\n\n\n\n\n\n")

    vs = bad
    fs = Outer{}
    e = fd.Decode(&fs, vs)
    if e != nil {
        switch t := e.(type) {
        case schema.MultiError:
            for k, v := range t {
                fmt.Println(k)
                fmt.Printf("  %#v\n", v)
            }
            return
        default:
            fmt.Printf("%#v\n", e)
            return
        }
    }
}

And output, when run, is:

$ go install test && ./test
<nil>
{
  "Level1": [
    {
      "Field": "field0",
      "Slice": null
    },
    {
      "Field": "field1",
      "Slice": null
    },
    {
      "Field": "field2",
      "Slice": [
        "Field2 - slice entry"
      ]
    }
  ]
}






Level1.0.Slice.0
  &errors.errorString{s:"schema: invalid path \"Level1.0.Slice.0\""}

Is this behavior expected? If so what kind of overhead would be involved in updating schema to support nested slices / is that even something that would be considered being added to the library?

Thanks!

What is a "StructLoader"?

The schema documentation states:

"Note: it is a good idea to set a StructLoader instance as a package global, because it caches meta-data about structs, and a instance can be shared safely:"

I cannot find the term StructLoader in the rest of the document. Is StructLoader an old term or perhaps alternate name or misnomer for a schema.NewDecoder() object?

Sanitization

Hi All - I have a use case where I have little control over the incoming JSON. I'd like to do some sanitization on the object keys (all keys, on all nested objects) before I map it to a struct. Specifically, I'd like ensure that all keys have the same case (In my case, camelCase) Is there some way to scrub the JSON object before decoding it?

UnmarshalText issue

Great library, thank you!

I'm having a problem making UnmarshalText be nice and cooperate. Here's simplest possible code recreating the issue:

package main

import (
	"fmt"
	"github.com/gorilla/schema"
)

type Email struct {
	Address string
}

func (e *Email) UnmarshalText(text []byte) (err error) {
	e.Address, err = string(text), nil
	return
}

type Person struct {
	Name   string
	Emails []Email
}

func main() {
	v := map[string][]string{
		"name":   {"John"},
		"emails": {"foo", "bar"},
	}
	var p Person

	err := schema.NewDecoder().Decode(&p, v)
	if err != nil {
		fmt.Println(err)
	}

	fmt.Println(p)
}

Output:

schema: invalid path "emails"
{John []}

Is there anything broken or (as is more likely!) am I doing sth wrong?

UnmarshalText precedence for type aliases

Seems like UnmarshalText should take precedence for converting values. This would be useful for defining enums and returning an error if the value isn't one of the valid values

package main

import (
    "errors"
    "fmt"

    "github.com/gorilla/schema"
)

type Foo string

func (f *Foo) UnmarshalText(text []byte) error {
    if string(text) != "foo" {
        return errors.New("not foo")
    }
    *f = Foo(text)
    return nil
}

type Stuff struct {
    Value Foo
}

func main() {
    stuff := new(Stuff)
    values := map[string][]string{
        "Value": {"abc"},
    }
    decoder := schema.NewDecoder()
    err := decoder.Decode(stuff, values)

    fmt.Println(err) // <nil>
    fmt.Println(stuff) // &{abc}
}

Setting up params for slice of structs

I am curious if support is included for something like:

var invoices []domain.Invoice
decoder := schema.NewDecoder()
decoder.Decode(invoices, r.PostForm)

The params would come in like Value.0 + Value.1, each value would represent a different domain.Invoice. The goal of this is to easily create a slice of structs. I saw that there is support for a slice of structs if it is a nested value, but I am needing a slice of structs directly. Is this possible?

schema: invalid path in structure

Hi, I'm using gorilla/schema in my project, however I have an error that am not really sure how to deal with. I will minimize my case as:
I have a structure like:

type Session struct {
	gorm.Model
	Email string
	Password []byte `schema:"-"`
}

I don't want to assign directly the password as I need to hash it using BCrypt, so that's the why I set that tag. So, from Postman I am sending:

pass: 12345
Email: [email protected]

And I get this error:
schema: invalid path "pass"

I already tried sending as 'Password' but nothing, I want to assign all the others fields but not the password. If I don't sent the password the error is gone (but I need to receive the pass)... So, what can be happening here?

gopkg versioned packages

We vendor in our dependencies currently, but personally my gospace is still shared across different packages (as a project is just a package anyways). Because of that i think it would be a good idea to use gopkg.in and tag the packages.

What do you think about that?

Should gorilla/schema care about DoS attacks?

I'll leave this IRC conversation as a quick request for feedback:

<pepee> honestly, this is still making me nervous:  http://www.gorillatoolkit.org/pkg/schema
<moraes> pepee, why?
<pepee> moraes, what if you pass a very long slice? or a long field in a form, etc.
<moraes> peppee, that's an interesting issue. probably not out of scope for the package.
<moraes> or for those kinds of attacks you shouldn't even touch request data
<moraes> pepee, so: 1. server check (413 status); 2. gorilla/schema could apply a limit tag
<pepee> moraes, yeah, there should be ways of limiting input, at least for the slices
<moraes> i will open an issue
<pepee> they should at least indicate that in the docs
<pepee> "make sure you sanitize your inputs, your user could be sending long strings, blah blah"
<moraes> yup.

The question is: Should gorilla/schema care about DoS attacks, at all? Or this is out of scope and should be handled in the server level or at most before submitting data to the package?

Document UnmarshalText precedence

Until #58 or #64 is resolved, can the documentation be updated to convey UnmarshalText does not yet work for type aliases?

http://www.gorillatoolkit.org/pkg/schema
There's also the possibility to create a custom type that implements the TextUnmarshaler interface, and in this case there's no need to registry a converter, like:

type Person struct {
  Emails []Email
}

type Email struct {
  *mail.Address
}

func (e *Email) UnmarshalText(text []byte) (err error) {
    e.Address, err = mail.ParseAddress(string(text))
    return
}

http://www.gorillatoolkit.org/pkg/schema

Export convertors

Is there any reason not to export convertors? I need to decode a payload which is composed either by structs or /and non-struct types (e.g. map[string]float64). Currently the decoder errors out if the destination is not a struct so I've forked the repo and just exported convertors.

Encode simple slice type results in error

Huge fan of your product. I seem unable to figure out, how to encode a simple slice type type People []Person. Using

package main

import (
        "fmt"

        "github.com/gorilla/schema"
)

type Person struct {
        Name string `schema:"name"`
        Age  int
}

type People []Person

func main() {
        jay := Person{"Jay", 34}
        may := Person{"May", 43}
        peeps := People{jay, may}

        values := make(map[string][]string)
        encoder := schema.NewEncoder()
        err := encoder.Encode(peeps, values)
        if err != nil {
                panic(err)
        }
        fmt.Printf("Encoded people: %v\n", values)
}

I get the error panic: schema: interface must be a struct.
Wrapping People into a struct now called Group also does not work:

package main

import (
        "fmt"

        "github.com/gorilla/schema"
)

type Person struct {
        Name string `schema:"name"`
        Age  int
}

type Group struct {
        People []Person
}

func main() {
        jay := Person{"Jay", 34}
        may := Person{"May", 43}
        peeps := Group{[]Person{jay, may}}

        values := make(map[string][]string)
        encoder := schema.NewEncoder()
        err := encoder.Encode(peeps, values)
        if err != nil {
                panic(err)
        }
        fmt.Printf("Encoded group %v\n", values)
}

Exits with error:
panic: schema: encoder not found for [{Jay 34} {May 43}]

What am I doing wrong here? Ideally I would like to work with the first version of type People []Person.

Add support on omitempty for all types

Hello,

I expected this behaviour which match encoding/json package.

Example: https://play.golang.org/p/o6IiMmNMK9

I wrote below the test to match the behaviour above but it fails.

The unit test:

type E5 struct {
	F01 int     `schema:"f01,omitempty"`
	F02 string  `schema:"f02,omitempty"`
	F03 *string `schema:"f03,omitempty"`
	F04 *int8   `schema:"f04,omitempty"`
	F05 float64 `schema:"f05,omitempty"`
}

func TestEncoderWithOmitempty(t *testing.T) {
	vals := map[string][]string{}

	s := E5{}

	encoder := NewEncoder()
	encoder.Encode(&s, vals)

	valNotExists(t, "f01", vals)
	valNotExists(t, "f02", vals)
	valNotExists(t, "f03", vals)
	valNotExists(t, "f04", vals)
	valNotExists(t, "f05", vals)
}

Here is the trace:

Running tool: /usr/local/bin/go test -timeout 30s -tags  -run ^TestEncoderWithOmitempty$

--- FAIL: TestEncoderWithOmitempty (0.00s)
	/Users/aetcheverry/Projects/Go/src/github.com/gorilla/schema/encoder_test.go:273: Key not ommited. Expected: empty; got: 0.
	/Users/aetcheverry/Projects/Go/src/github.com/gorilla/schema/encoder_test.go:273: Key not ommited. Expected: empty; got: null.
	/Users/aetcheverry/Projects/Go/src/github.com/gorilla/schema/encoder_test.go:273: Key not ommited. Expected: empty; got: null.
	/Users/aetcheverry/Projects/Go/src/github.com/gorilla/schema/encoder_test.go:273: Key not ommited. Expected: empty; got: 0.000000.
FAIL
exit status 1
FAIL	github.com/gorilla/schema	0.005s
Error: Tests failed.

Thanks for your help. 😃

UnmarshalText isn't called when Fields on struct are set

If you have a query of b.0.Foo=1&b.0.Bar=2 and b implements TextUnmarshaller then UnmarshalText won't be called. However, if the query is b.0=Foo%3D1%26Bar%3D2 then it works as expected, but I can't expect the caller to know which structs are custom and which aren't.

Test/example case:

package main

import (
	"net/url"
	"github.com/gorilla/schema"
)

type B struct {
	C string
	d interface{}
}

func (b *B) UnmarshalText(text []byte) error {
	q, err := url.ParseQuery(string(text))
	if err != nil {
		return err
	}
	b.C = q.Get("C")
	if b.C == "foo" {
		// you would probably do something different here, but example
		b.d = struct {
			E string
		}{q.Get("E")}
	}
	return nil
}

type A struct {
	B []B
}

func main() {
	d := schema.NewDecoder()

	q := url.Values{}
	q.Set("B.0.C", "foo")
	q.Set("B.0.E", "bar")
	a := &A{}
	d.Decode(a, q)
	// UnmarshalText is never called
	// a is &{B:[{C:foo d:<nil>}]}

	q = url.Values{}
	q.Set("B.0", "C=foo&E=bar")
	a = &A{}
	d.Decode(a, q)
	// UnmarshalText is called
	// a is &{B:[{C:foo d:{E:bar}}]}
}

encoding.TextUnmarshaler for slice type

Hi,
thanks for creating such great package. It did save my time.

For my understanding, if a type implemented encoding.TextUnmarshal interface, it should be
decode according to how we implement UnmarshalText function, right?
But slice type is a different story, because you miss test the interface in L137 https://github.com/gorilla/schema/blob/master/decoder.go#L137

and the following changes works for me

+        _, ok := v.Interface().(encoding.TextUnmarshaler)
-       if conv == nil && t.Kind() == reflect.Slice {
+       if conv == nil && t.Kind() == reflect.Slice && !ok {
                var items []reflect.Value
                elemT := t.Elem()
                isPtrElem := elemT.Kind() == reflect.Ptr
                if isPtrElem {
                        elemT = elemT.Elem()
                }

let me know my understand is wrong, thanks

"required" tag option should be supported

As example given on home page, when dealing with http request parameters, we have fields that must be nonempty value:

type Person struct {
    Name  string `schema:"name, required"`  // custom name
    Phone string `schema:"phone"` // custom name
    Admin bool   `schema:"-"`     // this field is never set
}

func MyHandler(w http.ResponseWriter, r *http.Request) {
    err := r.ParseForm()

    if err != nil {
        // Handle error
    }

    person := &Person{}
    decoder := schema.NewDecoder()

    // r.PostForm is a map of our POST form values
    err := decoder.Decode(person, r.PostForm)

    if err != nil {
        // error show up when required field empty
    }
    // Do something with person.Name or person.Phone
}

error show up when calling Decode if any required field empty. I got strong desire on this function.

Decode to embedded fields

I want to decode to a struct, which embeds fields of another struct. If I do this, I get an "invalid path" error, because schema can't find the field. That's because the cache's create function iterates over the fields using the Field method reflect.Type, which doesn't include embedded fields (but the embedded struct name). A solution would be to use FieldByName (which finds embedded fields) or iterate over the embedded fields.

Any chance to support file upload ?

Hi,

I d like to know if there s any chance the lib could handle file uploads too.

I d like very much to be able to write something like this,

type UserForm struct {
	fw.Form
	Username string `schema:"Username" conform:"trim" validate:"required,gt=4"`
	Email string `schema:"Email" conform:"trim" validate:"required,email,gt=4"`
        UserImage FileUpload `schema:"UserImage"`
}

So later i can add validations on it,

type UserForm struct {
	fw.Form
	Username string `schema:"Username" conform:"trim" validate:"required,gt=4"`
	Email string `schema:"Email" conform:"trim" validate:"required,email,gt=4"`
        UserImage FileUpload `schema:"UserImage" validate:"type=jpeg|gif,sizelt=1200,maxHeight=xxx,maxWidth=yyy"`
}

What do you think ? Can this be done ?

Getting a "undefined : cache error "

Hi
This is the error that I get

go get github.com/gorilla/schema
# github.com/gorilla/schema
schema\decoder.go:22: undefined: cache

I am running on Windows 10 with go version go1.8.1 windows/amd64

[feature request] let configuration methods return a pointer to the instance

package something

import (
    "github.com/gorilla/schema"
)

var decoder = schema.NewDecoder().IgnoreUnknownKeys(true) // valid syntax

The syntax above is valid go, and is how the docs suggest you use gorilla (keeping a global instance)

however, doing this won't be valid

package something

import (
    "github.com/gorilla/schema"
)

var decoder = schema.NewDecoder()
decoder.IgnoreUnknownKeys(true)  // syntax-error: non-declaration statement outside function body

Sounds like a simple enough change. I'd be happy to send a PR.
What do you guys think?

Have to consult a Form value before decode into object

Hi, I'm using gorilla/schema to populate my structure, righ now I'm getting a strange behaviour when I Decode the form into my struct. I am developing a CRUD for the table users and right now I am making the Update part.. So, briefly I get an ID, search in db for that register and finally I decode the form into the existent user in order to override the new fields to update, but now, I am testing with the field name and it's not assigned unless I retrieve that value before using req.FormValue . I have something like:


type User struct {
	gorm.Model
	Name string
       Active bool
}

Then in the code to set the values:

user := models.User{}
decoder := schema.NewDecoder()
err := decoder.Decode(&user, req.PostForm)

But that doesn't work, intead of that I have to retrieve some value from the form and then the decode is made successfully, something like:

user := models.User{}
fmt.Println(req.FormValue("Name"))
decoder := schema.NewDecoder()
err := decoder.Decode(&user, req.PostForm)

And here that works pretty well, I have to consult the value I don't know why.

Panic on invalid data provided by the client

Decode() method panics if source data contain invalid fields having path parts with names of other fields.

Its better to illustrate this with example. This code will panic on execution:

package main

import "fmt"
import "github.com/gorilla/schema"

func main() {
        type Person struct {
                Person string `schema:"person"`
                Phone  string `schema:"phone"`
        }

        values := map[string][]string{
                "person.phone":  {"John"},
                "phone":  {"999-999-999"},
        }
        person := new(Person)
        decoder := schema.NewDecoder()
        decoder.Decode(person, values)
        fmt.Println(person)
}

The panic occurs only if source data have names of other variables. For example changing values to:

        values := map[string][]string{
                "person.phones":  {"John"},
                "phone":  {"999-999-999"},
        }

is handled correctly (phone part of the path is changed to phones which does not collide with other attribute name).

Values is usually in control of the client of the application. This bug allows client to cause panic on the server by manipulating GET or POST arguments.

Error is returned when passing a pointer to an interface variable to decode

When calling decode, if you pass a pointer to an interface variable, you get an error:

schema: interface must be a pointer to struct

Here is code to reproduce:

import (
    "testing"
    "github.com/gorilla/schema"
)

type Cat struct {
    name string
}

type SomethingGeneric struct {
    getSomething func() interface{}
}

func getSomeCat() interface{} {
    return Cat{}
}

var somethingForCats = SomethingGeneric{getSomething: getSomeCat}

var decoder = schema.NewDecoder()

func TestCanDecodeInterfacePointer(t *testing.T) {
    dst := somethingForCats.getSomething()

    values := map[string][]string{
        "name": {"Tommy"},
    }

    err := decoder.Decode(&dst, values)

    if err != nil {
        t.Errorf("Could not decode.  Got error %v", err.Error())
    }

}

To avoid some boilerplate code, I need to be able to have some reusable code that can pass an interface variable pointer to decode.

Issue Decoding Blank Values

Situation

Have a user struct, populated via a database query that includes a LastName field already populated
We have a user update HTML form which posts the updates.

Issue

When LastName, or other fields, are set to blank in the HTML input the form posts the following:

map[IsActive:[true] FirstName:[Joey] LastName:[] PreferredFirstName:[Joey] Username:[joeybloggs]]

this is correct as you can see LastName has no value; however after running schema decoder like so:

// user originally grabbed from DB in middleware and set on context ( using gorilla contaxt )
user := context.Get(r, "user").(*User)

if err = schemaDecoder.Decode(user, r.MultipartForm.Value); err != nil {
  log.Println(err.Error())
  http.Error(w, "Invalid Request", http.StatusBadRequest)
  return
}

fmt.Println(user.LastName) // outputs Bloggs, the fields original value

LastName was not set to blank and still retains it's original value.

My specific problem

the user struct is validated after schema decoder runs and in this situation validation should report an error, however it all passes, user gets saved to the database and user is notified that the user saved successfully.

Notes

This is not the same issue as #17 as I don't want to zero out fields not posted.

Specifying multiple parameters for a string type silently coerces data

For instance, if I GET /path?key=banana&key=pear, then use schema to parse the url into a type fruit struct { key string }, I'll get either 'banana' or 'pear' (undefined behavior).

I would prefer to get a type error, as I was expecting a string but got an array of string.

Thoughts?

Preferred way for multiple checkboxes

Question about best practice when dealing with form that:

  • Has multiple checkboxes as an answers to one question, eg. Shop Type: [] electronics, [] groceries, [] wines, [] something
  • Answer options (checkbox values and ids) are fetched from DB

I thought that the best option would be to go with nested struct:

type shopType struct {
    Id int
    Type string
    Selected bool
}

type shopForm struct {
    Name string
    Types []shopType
}

Then populating shopForm.Types from DB and using it as a context in template. Then in template:

{{ range $idx, $type := .Types }}
    <label class="checkbox-inline"><input type="checkbox" name="Types.{{ $idx }}.Selected" {{ if $type.Selected }}checked{{ end }}> {{ $type.Type }}</label>
{{ end }}

But the problem with this approach is that I can only decode Selected field and I'm missing Id and Type. I could add hidden input fields like this:

<input type="hidden" name="Types.{{ $idx }}.Id" value="{{ $type.Id }}">
<input type="hidden" name="Types.{{ $idx }}.Type" value="{{ $type.Type }}">

and then it works OK, but it's ugly and it can't be done when dealing with select option form.

I'm probably missing something obvious :)

Need a way to "omitempty"

Right now gorilla/schema does not have a way to omit non present values to empty.
For example :

type params struct {
   Username string `schema:"name"`
   Password string `scehma:"password,setempty"`
}

If the input map does not contain the key "password" it should set it to an empty value if the tag is provided.

We are running into an issue with this right now.

Encode method is returning inaccurate errors

I have this snippet here, the problem is that the error returned by the Encode method gives (0 errors), this is what err displays when I print in int stdout. I'm not sure if an error occurred or should I treat this as a no error and move on with the code...

func (t *Ticket) Create() {
	encoder := schema.NewEncoder()

	// setup form values
	form := url.Values{}
	err := encoder.Encode(t, form)
	if err != nil {
		panic(err)
	}
}

Struct to values "encoder"

I've been using schema for a while, but I'd also like the ability to encode url values with the fields of a struct. I've created a basic encoder here, do you have any interest in adding something like this to schema?

Can't unmarshal type []string correctly with error schema.MultiError

Hi,

I've been trying to do this in really many ways, and I took the time to provide a test case with the scenario, does anyone have any ideas how I could work-around this problem ?

I have a object Tags []string and its part of a bigger collection, but the problematic point is this []string.

When I created a update view for this collection, the View is sending the form encoded as:

tags%5B%5D=Conservationists&tags%5B%5D=Zimbabwe

However schema returns me back schema: invalid path "tags[]"

It works if I change the struct schema to schema:"tags[]", but this is awful.

This is the full test with the reported problem:

package test

import (
    "testing"
    "net/http"
    "log"
    "net/http/httptest"
    "fmt"
    "io/ioutil"
    "github.com/stretchr/testify/assert"
    "github.com/gorilla/schema"
    "encoding/json"
    "strings"
)

type Tag struct {
    Tags []string                    `schema:"tags" json:"tags,omitempty"`
}

func TestHTTPMarshalProblem(t *testing.T) {

    ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        err := r.ParseForm()
        assert.Equal(t, err, nil)
        assert.NotEqual(t, r.Form, nil)
        assert.NotEqual(t, r.PostForm, nil)

        log.Println("PostForm ",r.PostForm)
        decoder := schema.NewDecoder()
        targetObject := new(Tag)

        // r.PostForm is a map of our POST form values
        err = decoder.Decode(targetObject, r.PostForm)
        if err != nil {
            log.Println(err)
            assert.Equal(t, err, nil)
            log.Println("targetObject ", targetObject)
        }
        assert.NotNil(t, targetObject,"err should be something")

        ret, err := json.Marshal(&targetObject)
        if err != nil {
            http.Error(w, err.Error(), http.StatusInternalServerError)
            return
        }

        if len(ret) == 0 {
            log.Println("404 not found")
            w.WriteHeader(http.StatusNotFound)
            return
        }

        w.Write(ret)

    }))
    defer ts.Close()

    var str = "tags%5B%5D=Conservationists&tags%5B%5D=Zimbabwe&tags%5B%5D=have&tags%5B%5D=accused&tags%5B%5D=American&tags%5B%5D=being&tags%5B%5D=alleged&tags%5B%5D=Cecil&tags%5B%5D=Africa%E2%80%99s&tags%5B%5D=lions"

    res, err := http.Post(ts.URL, "application/x-www-form-urlencoded; charset=UTF-8", strings.NewReader(str))

    if err != nil {
        log.Fatal(err)
    }
    obj, err := ioutil.ReadAll(res.Body)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("result %s", obj)
}

output:

2016/05/18 13:30:32 PostForm  map[tags[]:[Conservationists Zimbabwe have accused American being alleged Cecil Africa’s lions]]
2016/05/18 13:30:32 schema: invalid path "tags[]" 
2016/05/18 13:30:32 targetObject  &{[]}

Need to document `[]` requirement in struct annotations for array fields

With this struct annotation, Decode() silently fails to decode the array:

type MyStruct struct {
   MyArray []uint32 `schema:"myArray"`
}

With this struct annotation, Decode() succeeds:

type MyStruct struct {
   MyArray []uint32 `schema:"myArray[]"`
}

Any objections to adding this to the documentation?

Allow 'json' tag to be used as a field alias

Right now this package requires the 'schema' tag to be set on each structure. In my particular workflow it's possible for the web client to submit a structure via JSON or via the forms collection. Ideally schema would be able to use the 'schema' tag or the 'json' tag (preferring the first if they both exist) to decode an incoming request.

Decode HTML form to struct with string slice.

I expected the following code to decode the HTML form after reading the []Email example in the docs. Is this a bug or am I misunderstanding?

package main

import (
    "io"
    "log"
    "net/http"

    "github.com/gorilla/schema"
)

type Foo struct {
    Bars []string
}

func main() {
    http.HandleFunc("/", handler)
    log.Fatal(http.ListenAndServe(":3000", nil))
}

func handler(w http.ResponseWriter, req *http.Request) {
    if req.Method == http.MethodPost {
        err := req.ParseForm()
        if err != nil {
            http.Error(w, err.Error(), http.StatusInternalServerError)
            return
        }
        var foo Foo
        decoder := schema.NewDecoder()
        //decoder.IgnoreUnknownKeys(true)
        err = decoder.Decode(&foo, req.PostForm)
        if err != nil {
            // schema: invalid path "Bars.0" (and 2 other errors)
            http.Error(w, err.Error(), http.StatusInternalServerError)
            return
        }
        log.Println(foo) // prints {[]} with IgnoreUnknownKeys(true)
        http.Redirect(w, req, "/", http.StatusSeeOther)
        return
    }
    io.WriteString(w, `<html>
<body>
<form method="post" action="/">
  <input type="hidden" name="Bars.0" value="a">
  <input type="hidden" name="Bars.1" value="b">
  <input type="hidden" name="Bars.2" value="c">
  <button type="submit">Submit</button>
</form>
</body>
</html>`)
}

Converting comman seperated strings into slice of string.

Currently if I add a custom converter like decoder.RegisterConverter([]string{}, func (input string) reflect.Value {}) it wont call the custom converter but instead ignore it.

package schema_test

import (
    "fmt"
    "reflect"
    "testing"

    "github.com/gorilla/schema"
)

func TestStrings(t *testing.T) {
    decoder := schema.NewDecoder()
    decoder.RegisterConverter([]string{}, func(input string) reflect.Value {
        fmt.Printf("%+v", input)

        return reflect.ValueOf(input)
    })

    i := struct {
        Multiple []string `schema:"multiple"`
    }{}

    decoder.Decode(&i, map[string][]string{
        "multiple": []string{"one,two,three"},
    })
}

Would have suspected i.Multiple to contain a []string{"one", "two", "three"}

Deliberately set empty field

I need a way to explicitly set a field value to empty and not have it be ignored by gorilla/schema when processed. It is important to not simply wipe out all missing fields, but only make empty the fields that were provided and somehow marked as intentionally empty.

Use case: struct that is pre-populated from a database entry that is then passed into schema.Decoder to apply matched fields from a web form.

Possibly if the fields exist in the incoming web form and are empty, they can be wiped out while leaving alone the fields in the struct that weren't referenced in the web form. Such a thing would need testing that I haven't myself done.

I've created a very hacky patch[1] to allow deliberately unsetting a field value when empty, instead of just ignoring it. In an application I'm building, I pull in a record from the database and then use schema to merge changes. When the data coming in from a web form is empty, I intend for the value to be wiped out, not just ignored. But because of how structs work, it's really not easy to tell the difference between absent field versus a deliberately empty value. In this very hacky patch, if it hits a string value of "[[[ERASE]]]" it will set the field value to "". It's not good enough and is bound to have loads of gotchas. Maybe there an alternative way to do this that I've missed; if so, sorry for the wishlist request.

[1] scjalliance@fdf73b8 (don't actually use this commit)

Handle empty values appropriately

In the decoder, lines 110-112 cause a panic in the handling of slices, due to the items array having already been created according to the length of values. Skipping the handling of a value causes the corresponding index in items to contain invalid/zero Value objects.

Adding insult to injury, this even occurs when parsing a slice of strings (e.g. { "0", "1", "" } => []string => panic!).

Encode() will panic if struct contains field of struct pointer

Seems like this package doesn't allow struct to contain *struct field. Is there any plan to support this?

Here the code that triggers panic:

image

Here is the panic message:

--- FAIL: TestSlices (0.00s)
exit status 2
FAIL	example.com/x/vendor/github.com/gorilla/schema	0.010s
panic: runtime error: invalid memory address or nil pointer dereference [recovered]
	panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation, code=0x1 addr=0x0 pc=0x111e298]

goroutine 6 [running]:
testing.tRunner.func1(0xc420074750)
	/usr/local/Cellar/go/1.8.1/libexec/src/testing/testing.go:622 +0x29d
panic(,0x1145d40, 0x1216840)
	/usr/local/Cellar/go/1.8.1/libexec/src/runtime/panic.go:,489 +0x2cf
example.com/x/vendor/github.com/gorilla/schema.typeEncoder.func1(0x1131640, 0xc42001ea70, 0x1b6, 0x5, 0x1131640)
	/Users/kurt/gopath/src/example.com/x/vendor/github.com/gorilla/schema/encoder.go:117 +0xb8
example.com/x/vendor/github.com/gorilla/schema.(*Encoder).encode(0xc4200132b0, 0x1135740, 0xc42001ea00, 0x16, 0xc42000eb40, 0xc420013280, 0xc4200132c0)
	/Users/kurt/gopath/src/example.com/x/vendor/github.com/gorilla/schema/encoder.go:63 +0x433
,example.com/x/vendor/github.com/gorilla/schema.(*Encoder).Encode(0xc4200132b0, 0x1135740, 0xc42001ea00, 0xc42000eb40,, 0xc42000eb40, 0xc420022000)
	/Users/kurt/gopath/src/example.com/x/vendor/github.com/gorilla/schema/encoder.go:,29 +0x6b
example.com/x/vendor/github.com/gorilla/schema.TestSlices(,0xc420074750)
	/Users/kurt/gopath/src/example.com/x/vendor/github.com/gorilla/schema/encoder_test.go:161, +0x2ec
testing.tRunner(0xc420074750,, 0x11764e0)
	/usr/local/Cellar/go/1.8.1/libexec/src/testing/testing.go:657, +0x96
created by testing.(*T).Run,
	/usr/local/Cellar/go/1.8.1/libexec/src/testing/testing.go:697 +0x2ca
Error: Tests failed.

Checkbox boolean values

I have the following struct

type DeviceProfile struct {
    Title        string `json:"title"`
    Model        string `json:"model"`
    Mfr          string `json:"mfr"`
    Ssl          bool   `json:"ssl"`
}

And a checkbox in my html form:

<input type="checkbox" name="Ssl">

When I decode the form DeviceProfile.Ssl is always false because the HTML value for a checked checkbox is the string "on".

It seems like it would be helpful to accept "on" as a valid boolean true value. Note that if the checkbox is not checked the returned value is empty.

Custom array type provokes panic

The code below provokes a panic. If I revert the changes done in e6c8221 / #91 the code below works.

I am not sure what exactly how the problem can be solved. I tried to tweak the fix in e6c8221 but I didn't make too much progress.

func TestRegisterEncoderCustomArrayType(t *testing.T) {
	vals := map[string][]string{}
	
	type CustomInt []int
	s1 := &struct {
		SomeInts CustomInt `schema:",omitempty"`
	}{
		CustomInt{1,2,3},
	}
	
	encoder := NewEncoder()
	encoder.RegisterEncoder(CustomInt{}, func(value reflect.Value) string {
		return fmt.Sprint(value.Interface())
	})
	
	encoder.Encode(s1, vals)
	t.Log(vals)
}
panic: runtime error: comparing uncomparable type schema.CustomInt [recovered]
	panic: runtime error: comparing uncomparable type schema.CustomInt

goroutine 5 [running]:
testing.tRunner.func1(0xc4200a60f0)
	/usr/local/Cellar/go/1.9.2/libexec/src/testing/testing.go:711 +0x2d2
panic(0x114d340, 0xc420048720)
	/usr/local/Cellar/go/1.9.2/libexec/src/runtime/panic.go:491 +0x283
github.com/gorilla/schema.(*Encoder).encode(0xc42006bc18, 0x113cc20, 0xc42000a0c0, 0x16, 0xc420074390, 0xc42000a0e0, 0xc420044d28)
	/Users/olve/go/src/github.com/gorilla/schema/encoder.go:70 +0x78b
github.com/gorilla/schema.(*Encoder).Encode(0xc420044c18, 0x113cc20, 0xc42000a0c0, 0xc420074390, 0xc420044c60, 0x56600000002)
	/Users/olve/go/src/github.com/gorilla/schema/encoder.go:29 +0x6b
github.com/gorilla/schema.TestRegisterEncoderCustomArrayType(0xc4200a60f0)
	/Users/olve/go/src/github.com/gorilla/schema/encoder_test.go:352 +0x3a9
testing.tRunner(0xc4200a60f0, 0x117f3a0)
	/usr/local/Cellar/go/1.9.2/libexec/src/testing/testing.go:746 +0xd0
created by testing.(*T).Run
	/usr/local/Cellar/go/1.9.2/libexec/src/testing/testing.go:789 +0x2de

Empty string element in a slice disappears after decoding

For example, I have a struct:

type Post struct { Images []string }

If I want to put in the struct values like (contains three elements, including empty string):

["a", "", "b"]

After decoding I have a slice with two elements excluding an empty string as a result.

Could you please tell me if it Is a bug or a way it works? Thank you!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.