Coder Social home page Coder Social logo

binding's People

Contributors

clinyong avatar corelchen avatar dieterbe avatar lzh-lab avatar neoeinstein avatar unknwon avatar willhope avatar woodsaj avatar xmh19936688 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

Watchers

 avatar  avatar  avatar  avatar

binding's Issues

apply validation rules to each item in a Slice

I would like to be able to apply validation rules to each item in a slice.

eg

type MyStruct struct {
   Id int
   MyNumbers []int `json:"my_numbers" binding:"range(1, 10)"`
}

The following should then fail validation as one of the items in the list is outside of the range.

{
  "id": 1,
  "my_numbers": [1,2,3,4,100]
}

This would require replacing MinSize and MaxSize from being applied to slice lengths, so that rules can instead be used for length of each item in a slice of strings. New rules specific to slice length would then need to be introduced.

support validation of slices of structs

Validation does not currently work for slices of structs.
eg.

type Person struct {
  FirstName string `json:"first_name" binding:"Required"`
  LastName string `json:"last_name" binding:"Required"`
}
type Group struct {
  Name string `json:"name" binding:"Required"`
  People []*Person `json:"people"`
}

sending a payload with the following is currently validated as correct, though it should raise an issue for the missing FirstName

{
  "name": "Group1",
  "people": [
    {"first_name": "anthony", "last_name": "woods"},
    {"first_name": "", "last_name": "invalid"}
  ]
}

无法解析数组参数

type ConsoleForm struct {
	Operation string   `form:"operation"`
	Command   string   `form:"command"`
	Args      []string `form:"args"`
}

发送参数operation=test&command=run&args[]=1&args[]=2

args无法映射到struct中

AutoBinding via Mapper

type ContactForm struct {

    Email   string `form:"email"`

}

We hope that "Email" property in Form struct can be automap to form:email , We don't need to type 'form:email' by default.

This big feature should be used to simplify a lot of work.

ErrorHandler 不接受指针类型

Validate 和Error 对指针的处理方式不统一, 前者接受指针类型而后者不接受

// 这样的方法不被识别
func (form *VariantForm) Error(ctx *macaron.Context, errs binding.Errors) {}

// macaron 识别这样的方法
func (form *VariantForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {}

Security checks for Json()

In Go's net/http ParseForm() method, the following checks are done:
https://github.com/golang/go/blob/700e969d5b23732179ea86cfe67e8d1a0a1cc10a/src/net/http/request.go#L1176

// For other HTTP methods, or when the Content-Type is not
// application/x-www-form-urlencoded, the request Body is not read, and
// r.PostForm is initialized to a non-nil, empty value.
//
// If the request Body's size has not already been limited by MaxBytesReader,
// the size is capped at 10MB.

Should the similar checks in Request body be done in Json() method, too?

  1. Check that request body content type is application/json ?
  2. Limit request body size to 10MB ?

Called inject.InterfaceOf with a value that is not a pointer to an interface. (*MyInterface)(nil)

Have been trying to set up a JSON Post Request using the Macaron Example

  type ContactForm struct {
    Name string `json:"name" binding:"Required"`
  }
  r.Post("/api/journals", binding.Bind(ContactForm{}), func(contact ContactForm) string {
    return fmt.Sprintf("Name: %s", contact.Name)
  })

However calling this with the following JSON request from within jquery:

      $.ajax({
          type: 'POST',
          url: '/api/journals',
          data: '{"name":"hello"}',
          success: function(data) { alert('data: ' + data); },
          contentType: "application/json",
          dataType: 'json'
      });

returns the following error when the request is sent:

*Called inject.InterfaceOf with a value that is not a pointer to an interface. (MyInterface)(nil)

with the following stack trace:

/home/sean/go/pkg/mod/github.com/go-macaron/[email protected]/inject.go:113 (0x792c6d)
	InterfaceOf: panic("Called inject.InterfaceOf with a value that is not a pointer to an interface. (*MyInterface)(nil)")
/home/sean/go/pkg/mod/github.com/go-macaron/[email protected]/inject.go:222 (0x793a7e)
	(*injector).MapTo: i.values[InterfaceOf(ifacePtr)] = reflect.ValueOf(val)
/home/sean/go/pkg/mod/github.com/go-macaron/[email protected]/binding.go:752 (0x8258c4)
	validateAndMap: ctx.MapTo(obj.Elem().Interface(), ifacePtr[0])
/home/sean/go/pkg/mod/github.com/go-macaron/[email protected]/binding.go:210 (0x826edb)
	Json.func1: validateAndMap(jsonStruct, ctx, errors, ifacePtr...)
/usr/local/go/src/reflect/value.go:475 (0x49af66)
	Value.call: call(frametype, fn, args, uint32(frametype.size), uint32(retOffset))
/usr/local/go/src/reflect/value.go:336 (0x49a458)
	Value.Call: return v.call("Call", in)
/home/sean/go/pkg/mod/github.com/go-macaron/[email protected]/inject.go:177 (0x793379)
	(*injector).callInvoke: return reflect.ValueOf(f).Call(in), nil
/home/sean/go/pkg/mod/github.com/go-macaron/[email protected]/inject.go:137 (0x792d4a)
	(*injector).Invoke: return inj.callInvoke(f, t, t.NumIn())
/home/sean/go/pkg/mod/github.com/go-macaron/[email protected]/binding.go:45 (0x81e5be)
	bind: ctx.Invoke(Json(obj, ifacePtr...))
/home/sean/go/pkg/mod/github.com/go-macaron/[email protected]/binding.go:104 (0x8260c5)
	Bind.func1: bind(ctx, obj, ifacePtr...)
/home/sean/go/pkg/mod/gopkg.in/[email protected]/context.go:79 (0x7c5a72)
	ContextInvoker.Invoke: invoke(params[0].(*Context))
/home/sean/go/pkg/mod/github.com/go-macaron/[email protected]/inject.go:157 (0x793094)
	(*injector).fastInvoke: return f.Invoke(in)
/home/sean/go/pkg/mod/github.com/go-macaron/[email protected]/inject.go:135 (0x792e39)
	(*injector).Invoke: return inj.fastInvoke(v, t, t.NumIn())
/home/sean/go/pkg/mod/gopkg.in/[email protected]/context.go:121 (0x7c5bfc)
	(*Context).run: vals, err := c.Invoke(c.handler())
/home/sean/go/pkg/mod/gopkg.in/[email protected]/context.go:112 (0x7d6da5)
	(*Context).Next: c.run()
/home/sean/go/pkg/mod/gopkg.in/[email protected]/recovery.go:161 (0x7d6d98)
	Recovery.func1: c.Next()
/home/sean/go/pkg/mod/gopkg.in/[email protected]/logger.go:40 (0x7c97b7)
	LoggerInvoker.Invoke: invoke(params[0].(*Context), params[1].(*log.Logger))
/home/sean/go/pkg/mod/github.com/go-macaron/[email protected]/inject.go:157 (0x793094)
	(*injector).fastInvoke: return f.Invoke(in)
/home/sean/go/pkg/mod/github.com/go-macaron/[email protected]/inject.go:135 (0x792e39)
	(*injector).Invoke: return inj.fastInvoke(v, t, t.NumIn())
/home/sean/go/pkg/mod/gopkg.in/[email protected]/context.go:121 (0x7c5bfc)
	(*Context).run: vals, err := c.Invoke(c.handler())
/home/sean/go/pkg/mod/gopkg.in/[email protected]/router.go:187 (0x7d7ff0)
	(*Router).Handle.func1: c.run()
/home/sean/go/pkg/mod/gopkg.in/[email protected]/router.go:303 (0x7d2125)
	(*Router).ServeHTTP: h(rw, req, p)
/home/sean/go/pkg/mod/gopkg.in/[email protected]/macaron.go:220 (0x7cab0d)
	(*Macaron).ServeHTTP: m.Router.ServeHTTP(rw, req)
/usr/local/go/src/net/http/server.go:2843 (0x767bc2)
	serverHandler.ServeHTTP: handler.ServeHTTP(rw, req)
/usr/local/go/src/net/http/server.go:1925 (0x7633cc)
	(*conn).serve: serverHandler{c.server}.ServeHTTP(w, w.req)
/usr/local/go/src/runtime/asm_amd64.s:1374 (0x470480)
	goexit: BYTE	$0x90	// NOP

Cannot parse multipart form without form: attributes

This works:

type UploadForm struct {
    Title      string                `form:"Title"`
    TextUpload *multipart.FileHeader `form:"TextUpload"`
}

But this produces an empty struct:

type UploadForm struct {
    Title      string
    TextUpload *multipart.FileHeader
}

修改ErrorHandler 的方法签名,可以接受指针类型

比如,我想在错误处理中实现这样的逻辑:
flash.Error(err.Error())
目前的方法不能实现

ErrorHandler interface {
// Error handles validation errors with custom process.
Error(*macaron.Context, Errors)
}

可否修改为 Error(...interface{})

Error on upload Files - no data sent to the handler.

Hi @unknwon .
I need to do file uploading (import formated data to a config database) and I have been testing with your example here (https://go-macaron.com/docs/middlewares/binding)

My code is exactly this, and the export API is working fine.

package webui

import (
	"bytes"
	"encoding/json"
	"github.com/go-macaron/binding"
	"github.com/toni-moreno/snmpcollector/pkg/data/impexp"
	"gopkg.in/macaron.v1"
	"io/ioutil"
	"mime/multipart"
	"os"
)

type UploadForm struct {
	Title      string                `form:"Title"`
	TextUpload *multipart.FileHeader `form:"TextUpload"`
}

func NewImportExport(m *macaron.Macaron) error {

	bind := binding.Bind

	m.Group("/api/cfg/export", func() {
		m.Get("/:objtype/:id", reqSignedIn, ExportMeasurementGroup)
		m.Post("/:objtype/:id", reqSignedIn, bind(impexp.ExportInfo{}), ExportMeasurementGroupFile)

	})
	m.Group("/api/cfg/import", func() {
		m.Post("/", reqSignedIn, binding.MultipartForm(UploadForm{}), UploadHandler)
	})
	return nil
}

/****************/
/*IMPORT*/
/*****************/

func UploadHandler( /*ctx *Context,*/ uf UploadForm) {
	if (UploadForm{}) == uf {
		log.Error("Error no data in expected struct")
		return
	}
	log.Debugf("Uploaded file : %s", uf.Title)
	log.Debugf("Uploaded File : %+v", uf)
	file, err := uf.TextUpload.Open()
	if err != nil {
		log.Warningf("Error on Open Uploaded File: %s", err)
		//	ctx.JSON(404, err.Error())
	}
	buf := new(bytes.Buffer)
	buf.ReadFrom(file)
	s := buf.String()
	log.Debug("DATA: %s", s)
}

/****************/
/*EXPORT*/
/****************/

func Export(ctx *Context) {
....
 //more code working ok here
}

func ExportFile(ctx *Context, info impexp.ExportInfo) {
....
//more code working ok  here
}

This is the ouput when a upload have been done

ERRO[2017-02-18 08:03:40] Error no data in expected struct 

IT seems like no data is sent to the UploadForm struct.

I've got HTTP real data with wireshark and this i exactly what we are sending to the macaron handler.

POST /api/cfg/import HTTP/1.1
Host: localhost:8090
Connection: keep-alive
Content-Length: 7275
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36
Origin: chrome-extension://apcedakaoficjlofohhcmkkljehnmebp
Content-Type: multipart/form-data
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: es,ca;q=0.8,en;q=0.6,en-US;q=0.4
Cookie: MacaronSession=127714bd60ec66e0; snmpcollector-sess-lan=9da867813c641552

------WebKitFormBoundaryfin1vPdBlN5ZQrnv
Content-Disposition: form-data; name="fileUpload1"; filename="blob"
Content-Type: text/plain

{"Info":{"FileName":"","Description":"","Author":"","Tags":""},"AgentVersion":"","ExportVersion":"1.0","CreationDate":"2017-02-18T06:37:28.159948966+01:00","Objects":[{"ObjectTypeID":"influxcfg","ObjectID":"default","ObjectPtr":{"ID":"default","Host":"127.0.0.1","Port":8086,"DB":"snmp","User":"snmpuser","Password":"snmppass","Retention":"autogen","Timeout":5,"UserAgent":"snmpcollector_agent_00","Description":""}},{"ObjectTypeID":"oidconditioncfg","ObjectID":"test_multiple","ObjectPtr":{"ID":"test_multiple","IsMultiple":true,"OIDCond":"filter_port_if_status_up \u0026\u0026 filter_port_if_name_match_eth0","CondType":"","CondValue":"","Description":"adf"}},{"ObjectTypeID":"measfiltercfg","ObjectID":"filter_multiple_test","ObjectPtr":{"ID":"filter_multiple_test","IDMeasurementCfg":"linux_ports","FType":"OIDCondition","FilterName":"test_multiple","EnableAlias":false,"Description":"test"}},{"ObjectTypeID":"snmpmetriccfg","ObjectID":"ifOutErrors","ObjectPtr":{"ID":"ifOutErrors","FieldName":"ifOutErrors","Description":"","BaseOID":".1.3.6.1.2.1.2.2.1.20","DataSrcType":"COUNTER32","GetRate":false,"Scale":0,"Shift":0,"IsTag":false,"ExtraData":""}},{"ObjectTypeID":"snmpmetriccfg","ObjectID":"ifInErrors","ObjectPtr":{"ID":"ifInErrors","FieldName":"ifInErrors","Description":"","BaseOID":".1.3.6.1.2.1.2.2.1.14","DataSrcType":"COUNTER32","GetRate":false,"Scale":0,"Shift":0,"IsTag":false,"ExtraData":""}},{"ObjectTypeID":"snmpmetriccfg","ObjectID":"evaluated_prefix_for_ifname","ObjectPtr":{"ID":"evaluated_prefix_for_ifname","FieldName":"prefixed_ifname","Description":"Add Prefix for ifname","BaseOID":"","DataSrcType":"STRINGEVAL","GetRate":false,"Scale":0,"Shift":0,"IsTag":true,"ExtraData":"'myprefix_'+IfName"}},{"ObjectTypeID":"snmpmetriccfg","ObjectID":"ifName","ObjectPtr":{"ID":"ifName","FieldName":"IfName","Description":"Tags","BaseOID":".1.3.6.1.2.1.31.1.1.1.1","DataSrcType":"OCTETSTRING","GetRate":false,"Scale":0,"Shift":0,"IsTag":true,"ExtraData":""}},{"ObjectTypeID":"snmpmetriccfg","ObjectID":"IfH_out_percent_utilization","ObjectPtr":{"ID":"IfH_out_percent_utilization","FieldName":"out_percent_utilization","Description":"% utlization out","BaseOID":"","DataSrcType":"STRINGEVAL","GetRate":false,"Scale":0,"Shift":0,"IsTag":false,"ExtraData":"(out_octets * 8) / ( ifhspeed * 10000)"}},{"ObjectTypeID":"snmpmetriccfg","ObjectID":"ifH_in_percent_utilization","ObjectPtr":{"ID":"ifH_in_percent_utilization","FieldName":"in_percent_utilization","Description":"% utlization in","BaseOID":"","DataSrcType":"STRINGEVAL","GetRate":false,"Scale":0,"Shift":0,"IsTag":false,"ExtraData":"(in_octets * 8 ) /  (ifhspeed * 10000)"}},{"ObjectTypeID":"snmpmetriccfg","ObjectID":"ifHighSpeed","ObjectPtr":{"ID":"ifHighSpeed","FieldName":"ifhspeed","Description":"Bytes Out - 64-bit Counters","BaseOID":".1.3.6.1.2.1.31.1.1.1.15","DataSrcType":"Gauge32","GetRate":false,"Scale":0,"Shift":0,"IsTag":false,"ExtraData":"user + system + idle"}},{"ObjectTypeID":"snmpmetriccfg","ObjectID":"ifHCOutOctets","ObjectPtr":{"ID":"ifHCOutOctets","FieldName":"out_octets","Description":"Bytes Out - 64-bit Counters","BaseOID":".1.3.6.1.2.1.31.1.1.1.10","DataSrcType":"COUNTER64","GetRate":true,"Scale":0,"Shift":0,"IsTag":false,"ExtraData":"user + system + idle"}},{"ObjectTypeID":"snmpmetriccfg","ObjectID":"ifHCInOctets","ObjectPtr":{"ID":"ifHCInOctets","FieldName":"in_octets","Description":"Bytes In - 64-bit Counters","BaseOID":".1.3.6.1.2.1.31.1.1.1.6","DataSrcType":"COUNTER64","GetRate":true,"Scale":0,"Shift":0,"IsTag":false,"ExtraData":"user + system + idle"}},{"ObjectTypeID":"measurementcfg","ObjectID":"linux_ports","ObjectPtr":{"ID":"linux_ports","Name":"linux_ports","GetMode":"indexed","IndexOID":".1.3.6.1.2.1.31.1.1.1.1","TagOID":"","IndexTag":"portName","IndexTagFormat":"","IndexAsValue":false,"Fields":[{"ID":"ifHCInOctets","Report":1},{"ID":"ifHCOutOctets","Report":1},{"ID":"ifHighSpeed","Report":1},{"ID":"ifH_in_percent_utilization","Report":1},{"ID":"IfH_out_percent_utilization","Report":1},{"ID":"ifName","Report":1},{"ID":"evaluated_prefix_for_ifname","Report":1},{"ID":"ifInErrors","Report":2},{"ID":"ifOutErrors","Report":2}],"Description":""}},{"ObjectTypeID":"oidconditioncfg","ObjectID":"filter_port_if_status_up","ObjectPtr":{"ID":"filter_port_if_status_up","IsMultiple":false,"OIDCond":".1.3.6.1.2.1.2.2.1.8","CondType":"neq","CondValue":"1","Description":""}},{"ObjectTypeID":"snmpmetriccfg","ObjectID":"test_cond_oid","ObjectPtr":{"ID":"test_cond_oid","FieldName":"oidtest","Description":"afaf","BaseOID":"","DataSrcType":"CONDITIONEVAL","GetRate":false,"Scale":0,"Shift":0,"IsTag":false,"ExtraData":"filter_port_if_status_up"}},{"ObjectTypeID":"snmpmetriccfg","ObjectID":"Linux_user_CPU_total","ObjectPtr":{"ID":"Linux_user_CPU_total","FieldName":"cpu_total","Description":"calculo de CPU total","BaseOID":"","DataSrcType":"STRINGEVAL","GetRate":false,"Scale":0,"Shift":0,"IsTag":false,"ExtraData":"user + system + idle"}},{"ObjectTypeID":"snmpmetriccfg","ObjectID":"Linux_idle_CPU_percent","ObjectPtr":{"ID":"Linux_idle_CPU_percent","FieldName":"idle","Description":"percentage of Idle CPU time","BaseOID":".1.3.6.1.4.1.2021.11.11.0","DataSrcType":"INTEGER","GetRate":false,"Scale":0,"Shift":0,"IsTag":false,"ExtraData":""}},{"ObjectTypeID":"snmpmetriccfg","ObjectID":"Linux_system_CPU_percent","ObjectPtr":{"ID":"Linux_system_CPU_percent","FieldName":"system","Description":"percentage of system CPU time","BaseOID":".1.3.6.1.4.1.2021.11.10.0","DataSrcType":"INTEGER","GetRate":false,"Scale":0,"Shift":0,"IsTag":false,"ExtraData":""}},{"ObjectTypeID":"snmpmetriccfg","ObjectID":"Linux_user_CPU_percent","ObjectPtr":{"ID":"Linux_user_CPU_percent","FieldName":"user","Description":"percentage of user CPU time","BaseOID":".1.3.6.1.4.1.2021.11.9.0","DataSrcType":"INTEGER","GetRate":false,"Scale":0,"Shift":0,"IsTag":false,"ExtraData":""}},{"ObjectTypeID":"measurementcfg","ObjectID":"linux_cpu","ObjectPtr":{"ID":"linux_cpu","Name":"linux.cpu","GetMode":"value","IndexOID":"","TagOID":"","IndexTag":"","IndexTagFormat":"","IndexAsValue":false,"Fields":[{"ID":"Linux_user_CPU_percent","Report":1},{"ID":"Linux_system_CPU_percent","Report":1},{"ID":"Linux_idle_CPU_percent","Report":1},{"ID":"Linux_user_CPU_total","Report":1},{"ID":"test_cond_oid","Report":1}],"Description":""}},{"ObjectTypeID":"measgroupscfg","ObjectID":"Linux","ObjectPtr":{"ID":"Linux","Measurements":["linux_cpu","linux_ports"],"Description":""}},{"ObjectTypeID":"snmpdevicecfg","ObjectID":"hostsnmpv3a","ObjectPtr":{"ID":"hostsnmpv3a","Host":"hostsnmpv3a","Port":161,"Retries":5,"Timeout":20,"Repeat":0,"Active":true,"SnmpVersion":"3","Community":"public","V3SecLevel":"NoAuthNoPriv","V3AuthUser":"v3usernoauth","V3AuthPass":"v3passauth","V3AuthProt":"MD5","V3PrivPass":"","V3PrivProt":"","DisableBulk":false,"Freq":30,"UpdateFltFreq":1,"OutDB":"default","LogLevel":"debug","LogFile":"","SnmpDebug":false,"DeviceTagName":"router","DeviceTagValue":"id","ExtraTags":["tagA=4","tagB=5","tagC=6"],"Description":"","MeasurementGroups":["Linux"],"MeasFilters":["filter_multiple_test"]}}]}

There is no any warning error , and I've done exact as you did in the above example. I will be happy if you can help me.

Thank you very much

Related resource validation?

Hi,

what's the proper pattern to validate related entities?

A minimal example of what I would want to achieve:

type ProfileForm struct {
    Bio    string `binding:"Required"`
}

type UserForm struct {
    Username    string  `binding:"Required;MaxSize(30)"`
    Email       string  `binding:"Required;Email"`
    Profile     *ProfileForm
}
<form ...>
    <input type="text" name="username">
    <input type="email" name="email">
    <input type="text" name="profile.bio">
</form>

Thank you!

[Feature Request] Enable macaron binding Validation outside a request context.

I've working with macaron/binding to validate input data from a API REST . But also could import data in JSON format from a file with lots of json formated objects of diferent type (https://github.com/toni-moreno/snmpcollector/blob/master/pkg/data/impexp/import.go#L91) . In this use case I would like also validate as input in the same way than if inserted via API REST and validated with macaron/binding.

Would be interesting if we can use the same binding.Validate method decoupled of the http request.

GET requests with content-type header set result in errors

hello,
a GET request has no body, yet the HTTP RFC allows to set content-type on GET requests
(https://tools.ietf.org/html/rfc7231#section-3.1.1.5)
in this case it simply does not apply.
We see this commonly with customers that switch requests between GET and POST, but leaving the content-type header specified. For GET requests, it should simply have no effect.

However, the binding middleware will, upon detection of a non-zero content-type header, switch to trying to use the json decoder on the body, even when there is no body such as in a GET request.
This results in errors such as grafana/metrictank#1465 :

http  'http://localhost:6060/render?target=stats.docker-env.response.200&from=-6s' 'Content-Type:application/json'
HTTP/1.1 422 Unprocessable Entity
Content-Encoding: gzip
Content-Length: 96
Content-Type: application/json; charset=utf-8
Date: Wed, 18 Sep 2019 14:29:00 GMT
Vary: Accept-Encoding

[
    {
        "classification": "RequiredError",
        "fieldNames": [
            "target"
        ],
        "message": "Required"
    }
]

the correct behavior would be to process the request based on its method (e.g. GET requests use GET parameters)

Multiple sub-forms from html not json ?

It seems that the JSON part supports having multiple "sub-forms" (slices of structs ?).

I would like to have something like (not File Uploads here, plain HTML input forms):

type ItemFile struct {
    Filename string
    Content string `binding:"Required;Text"`
}
type Item struct {
    Description string `binding:"Required"`
    Files []ItemFile // ?
}

Is it possible to do that ? how should I use the "ItemFile" and naming in html for fields names ?

Error In Validation "In()" also implies Required

When I'm defining an enum validation , I would like also give a default value.

SnmpDebug bool `xorm:"snmpdebug" binding:"Default(0);In(0,1)"`  

but when omitting the "snmpdebug" parameter the following error is shown

[
  {
    "fieldNames": [
      "SnmpDebug"
    ],
    "classification": "InError",
    "message": "In"
  }
]

But I've set the Default value as 0, so validation has been done erroneously.

Custom validation on the documentation can not be compiled (undefined "rule" error).

The custom validation on the example is not working.

func init() {
	// Min(1) set de minimun integer value
	binding.AddRule(&binding.Rule{
		IsMatch: func(rule string) bool {
			return strings.HasPrefix(rule, "Min(")
		},
		IsValid: func(errs binding.Errors, name string, v interface{}) (bool, binding.Errors) {
			num, ok := v.(int)
			if !ok {
				return false, errs
			}
			min, _ := strconv.Atoi(rule[4 : len(rule)-1])
			if num < min {
				errs.Add([]string{name}, "MinimumValue", "Value is too small")
				return false, errs
			}
			return true, errs
		},
	})

}

On compile we have this error.

pkg/webui/extravalidations.go:22: undefined: rule

There is no "rule" variable defined inside IsValid function. But I need build custom rules similars to the Min(10) example . How can I access to the rule definition in the IsValid function?

Pls upd mod vendor as in main macaron package

Hey! i use macaron with binding and after update packages i see error:

go: finding github.com/Unknwon/com latest
go: github.com/Unknwon/[email protected]: parsing go.mod: unexpected module path "github.com/unknwon/com"
go: error loading module requirements

Aand... i see two packages:
Unknwon and unknwon... and error :(

建议可以自定义默认的errorHandler

常见的一种开发场景是作为api服务,有统一的数据返回格式,比如:

{"code":0,"message":"成功","data":{}}

binding默认的errorHandler返回的数据格式不符合要求,现在也不能修改默认的errorHandler实现方法。binding虽然提供了两种自定义错误处理机制,但一种是需要为每一个绑定的struct定义Error(ctx *macaron.Context, errs binding.Errors)方法,比较麻烦,另一种是使用 binding.BindIgnErr 函数来忽略对错误的自动处理,然后再定义一个中间件统一处理binding的错误,同样需要在调用binding.BindIgnErr中间件之后再加上这个自定义中间件的调用,也有点麻烦。
所以,请问是否可以增加自定义默认的errorHandler的功能?
最后说一句,非常喜欢macaron和gogs,感谢Unkown为开源社区的无私奉献。

Unicode support

Is it possible to change the pattern binding.go#L247 to "[^\d\p{L}-_\.]" ? (also L246)
I want to use Unicode names for repositories in gogs.

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.