Macaron Documentation
  • Welcome
  • Starter Guide
  • Core Concepts
  • Core Services
  • Custom Services
  • Middlewares
    • Routing
    • Templating
    • Gzip
    • Localization
    • Data Binding and Validation
    • Cache
    • Captcha
    • Session
    • Cross-Site Request Forgery
    • Embed Binary Data
    • Serving Multiple Sites
  • FAQs
  • 简体中文
    • 初学者指南
    • 核心概念
    • 核心服务
    • 自定义服务
    • 中间件和辅助模块
      • 路由模块
      • 模板引擎
      • Gzip 压缩
      • 应用本地化
      • 数据绑定与验证
      • 缓存管理(Cache)
      • 验证码服务
      • 会话管理(Session)
      • 跨域请求攻击(CSRF)
      • 嵌入二进制数据
      • 服务多个站点
    • 常见问题
Powered by GitBook
On this page
  • Installation
  • Usage
  • Getting form data from a request
  • Getting JSON data from a request
  • Binding to interfaces
  • Description of Handlers
  • Bind
  • Form
  • MultipartForm and File Uploads
  • Json
  • Validate
  • Customize Operations
  • Custom Validation
  • Custom Validation Rules
  • Custom Error Handler

Was this helpful?

  1. Middlewares

Data Binding and Validation

PreviousLocalizationNextCache

Last updated 5 years ago

Was this helpful?

Middlware binding provides request data binding and validation for Macaron .

Installation

go get github.com/go-macaron/binding

Usage

Getting form data from a request

Suppose you have a contact form on your site where at least name and message are required. We'll need a struct to receive the data:

type ContactForm struct {
    Name           string `form:"name" binding:"Required"`
    Email          string `form:"email"`
    Message        string `form:"message" binding:"Required"`
    MailingAddress string `form:"mailing_address"`
}

Then we simply add our route in Macaron:

m.Post("/contact/submit", binding.Bind(ContactForm{}), func(contact ContactForm) string {
    return fmt.Sprintf("Name: %s\nEmail: %s\nMessage: %s\nMailing Address: %v",
        contact.Name, contact.Email, contact.Message, contact.MailingAddress)
})

Naming Convention

By default, there is one naming convention for form tag name, which are:

  • Name -> name

  • UnitPrice -> unit_price

For example, previous example can be simplified with following code:

type ContactForm struct {
    Name           string `binding:"Required"`
    Email          string
    Message        string `binding:"Required"`
    MailingAddress string
}

Clean and neat, isn't it?

Getting JSON data from a request

To get data from JSON payloads, simply use the json: struct tags instead of form:.

Binding to interfaces

If you'd like to bind the data to an interface rather than to a concrete struct, you can specify the interface and use it like this:

m.Post("/contact/submit", binding.Bind(ContactForm{}, (*MyInterface)(nil)), func(contact MyInterface) {
    // ... your struct became an interface!
})

Description of Handlers

Each of these middleware handlers are independent and optional, though be aware that some handlers invoke other ones.

Bind

  1. Deserializes request data into a struct

Notes:

  • Your application (the final handler) will not even see the request if there are any errors when default error handling is applied.

  • Header Content-Type will be used to know how to deserialize the requests.

Form

  1. Deserializes request data into a struct

MultipartForm and File Uploads

This handler does the following:

  1. Deserializes request data into a struct

Example

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

func main() {
    m := macaron.Classic()
    m.Post("/", binding.MultipartForm(UploadForm{}), uploadHandler(uf UploadForm) string {
        file, err := uf.TextUpload.Open()
        // ... you can now read the uploaded file
    })
    m.Run()
}

Json

  1. Deserializes request data into a struct

Validate

Validation Rules

There are some builtin validation rules. To use them, the tag format is binding:"<Name>".

Name

Note

OmitEmpty

Omit rest of validations if value is empty

Required

Must be non-zero value

AlphaDash

Must be alpha characters or numerics or -_

AlphaDashDot

Must be alpha characters or numerics, -_ or .

Size(int)

Fixed length

MinSize(int)

Minimum length

MaxSize(int)

Maximum length

Range(int,int)

Value range(inclusive)

Email

Must be E-mail address

Url

Must be HTTP/HTTPS URL address

In(a,b,c,...)

Must be one of element in array

NotIn(a,b,c,...)

Must not be one of element in array

Include(string)

Must contain

Exclude(string)

Must not contain

Default(string)

Set default value when field is zero-value(cannot use this when bind with interface wrapper)

To combine multiple rules: binding:"Required;MinSize(10)".

Customize Operations

Custom Validation

func (cf ContactForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
    if strings.Contains(cf.Message, "Go needs generics") {
        errs = append(errors, binding.Error{
            FieldNames:     []string{"message"},
            Classification: "ComplaintError",
            Message:        "Go has generics. They're called interfaces.",
        })
    }
    return errs
}

Now, any contact form submissions with "Go needs generics" in the message will return an error explaining your folly.

Custom Validation Rules

Suppose you want to limit minimum value:

binding.AddParamRule(&binding.ParamRule{
    IsMatch: func(rule string) bool {
        return strings.HasPrefix(rule, "Min(")
    },
    IsValid: func(errs binding.Errors, rule, 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
    },
})
binding.AddRule(&binding.Rule{
    IsMatch: func(rule string) bool {
        return rule == "String"
    },
    IsValid: func(errs binding.Errors, name string, v interface{}) (bool, binding.Errors) {
        _, ok := v.(string)
        return ok, errs
    },
})

Custom validation rules are applied after builtin rules.

Custom Error Handler

func (cf ContactForm) Error(ctx *macaron.Context, errs binding.Errors) {
    // Custom process to handle error.
}

This operation happens after your custom validation.

That's it! The function takes care of validating required fields.

By default, if there are any errors (like a required field is empty), binding middleware will return an error to the client and your app won't even see the request. To prevent this behavior, you can use instead.

Don't try to bind to embedded struct pointers; it won't work. See if you want to help with this.

If you want to custom your app naming convention, you can use function, which accepts a function that is type of .

Use to correctly convert JSON to a Go type definition. It's useful if you're new to this or the structure is large/complex.

is a convenient wrapper over the other handlers in this package. It does the following boilerplate for you:

Performs validation with

If your struct doesn't implement , then default error handling will be applied. Otherwise, calls ErrorHandler.Error method to perform custom error handling.

Don't attempt to bind a pointer to a struct. This will cause a panic where every request would be pointing to the same struct.

deserializes form data from the request, whether in the query string or as a form-urlencoded payload. It only does these things:

Performs validation with

Note that it does not handle errors. You may receive a into your own handler if you want to handle errors.

Like , deserializes form data from a request into the struct you pass in. Additionally, this will deserialize a POST request that has a form of enctype="multipart/form-data". If the bound struct contains a field of type (or []*multipart.FileHeader), you also can read any uploaded files that were part of the form.

Performs validation with

Again, like , no error handling is performed, but you can get the errors in your handler by receiving a type.

deserializes JSON data in the payload of the request. It does the following things:

Performs validation with

Similar to , no error handling is performed, but you can get the errors and handle them yourself.

receives a populated struct and checks it for errors with basic rules. It will execute the Validator.Validate() method on the struct, if it is a .

If you want additional validation beyond just checking required fields, your struct can implement the interface like so:

If you need to more validation rules that are applied automatically for you, you can add custom rules by function , it accepts type as argument.

If your rule is simple, you can also use , it accepts type :

If you want to avoid default error handle process but still want binding middleware calls handle function for you, your struct can implement the interface like so:

binding.Bind
binding.BindIgnErr
martini-contrib/binding issue 30
binding.SetNameMapper
binding.NameMapper
JSON-to-Go
binding.Bind
binding.Validate
binding.ErrorHandler
to prevent a race condition
binding.Form
binding.Validate
binding.Errors
binding.Form
binding.MultipartForm
*multipart.FileHeader
binding.Validate
binding.Form
binding.Errors
binding.Json
binding.Validate
binding.Form
binding.Validate
binding.Validator
binding.Validator
binding.AddParamRule
binding.ParamRule
binding.AddRule
binding.Rule
binding.ErrorHandler
GitHub
API Reference
Instances