https://github.com/mholt/binding
Reflectionless data binding for Go's net/http (not actively maintained)
https://github.com/mholt/binding
Last synced: 2 months ago
JSON representation
Reflectionless data binding for Go's net/http (not actively maintained)
- Host: GitHub
- URL: https://github.com/mholt/binding
- Owner: mholt
- License: mit
- Archived: true
- Created: 2014-05-20T23:35:14.000Z (almost 12 years ago)
- Default Branch: master
- Last Pushed: 2018-03-28T23:47:34.000Z (almost 8 years ago)
- Last Synced: 2024-05-18T20:46:44.134Z (almost 2 years ago)
- Language: Go
- Homepage: http://mholt.github.io/binding
- Size: 252 KB
- Stars: 796
- Watchers: 31
- Forks: 84
- Open Issues: 8
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- awesome-go - binding - Binds form and JSON data from net/http Request to struct. (Forms / Search and Analytic Databases)
- awesome-go - binding - Binds form and JSON data from net/http Request to struct. (Forms / Search and Analytic Databases)
- go-awesome-with-star-updatetime - binding - Binds form and JSON data from net/http Request to struct. (Forms / Advanced Console UIs)
- awesome-go - binding - Binds form and JSON data from net/http Request to struct. - :arrow_down:102 - :star:510 (Forms / Advanced Console UIs)
- awesome-go-cn - binding
- fucking-awesome-go - :octocat: binding - Binds form and JSON data from net/http Request to struct. :star: 476 :fork_and_knife: 39 (Forms / Advanced Console UIs)
- awesome-Char - binding - Binds form and JSON data from net/http Request to struct. (Forms / Advanced Console UIs)
- awesome-go - binding - Reflectionless data binding for Go's net/http (not yet a stable 1.0, but not likely to change much either) - ★ 713 (Forms)
- awesome-go-cn - binding
- awesome-go-cn - binding
- awesome-go - binding - Binds form and JSON data from net/http Request to struct. (Forms / Advanced Console UIs)
- awesome-go - binding - Binds form and JSON data from net/http Request to struct. (Forms / Search and Analytic Databases)
- awesome-go - binding - Binds form and JSON data from net/http Request to struct. (Forms / Search and Analytic Databases)
- awesome-go-extra - ARCHIVED - 05-20T23:35:14Z|2018-03-28T23:47:34Z| (Forms / Advanced Console UIs)
- awesome-go - binding - 将表单和JSON数据从net/http请求绑定到struct。 (<span id="表单-forms">表单 Forms</span> / <span id="高级控制台用户界面-advanced-console-uis">高级控制台用户界面 Advanced Console UIs</span>)
- awesome-go-processed - binding - Binds form and JSON data from net/http Request to struct.| (Forms / Advanced Console UIs)
- awesome-go - binding - Binds form and JSON data from net/http Request to struct. (Forms / Advanced Console UIs)
- awesome-go - binding - Binds form and JSON data from net/http Request to struct. (Forms / Search and Analytic Databases)
- awesome-go - binding - | - | - | (Forms / Advanced Console UIs)
- awesome-go-info - binding
README
[
](http://mholt.github.io/binding)
[](https://godoc.org/github.com/mholt/binding)
binding
=======
Reflectionless data binding for Go's net/http
Features
---------
- HTTP request data binding
- Data validation (custom and built-in)
- Error handling
Benefits
---------
- Moves data binding, validation, and error handling out of your application's handler
- Reads Content-Type to deserialize form, multipart form, and JSON data from requests
- No middleware: just a function call
- Usable in any setting where `net/http` is present (Negroni, gocraft/web, std lib, etc.)
- No reflection
Usage example
--------------
```go
package main
import (
"fmt"
"net/http"
"github.com/mholt/binding"
)
// First define a type to hold the data
// (If the data comes from JSON, see: http://mholt.github.io/json-to-go)
type ContactForm struct {
User struct {
ID int
}
Email string
Message string
}
// Then provide a field mapping (pointer receiver is vital)
func (cf *ContactForm) FieldMap(req *http.Request) binding.FieldMap {
return binding.FieldMap{
&cf.User.ID: "user_id",
&cf.Email: "email",
&cf.Message: binding.Field{
Form: "message",
Required: true,
},
}
}
// Now your handlers can stay clean and simple
func handler(resp http.ResponseWriter, req *http.Request) {
contactForm := new(ContactForm)
if errs := binding.Bind(req, contactForm); errs != nil {
http.Error(resp, errs.Error(), http.StatusBadRequest)
return
}
fmt.Fprintf(resp, "From: %d\n", contactForm.User.ID)
fmt.Fprintf(resp, "Message: %s\n", contactForm.Message)
}
func main() {
http.HandleFunc("/contact", handler)
http.ListenAndServe(":3000", nil)
}
```
Multipart/form-data usage example
---------------------------------
```go
package main
import (
"bytes"
"fmt"
"github.com/mholt/binding"
"io"
"log"
"mime/multipart"
"net/http"
)
// We expect a multipart/form-data upload with
// a file field named 'data'
type MultipartForm struct {
Data *multipart.FileHeader `json:"data"`
}
func (f *MultipartForm) FieldMap(req *http.Request) binding.FieldMap {
return binding.FieldMap{
&f.Data: "data",
}
}
// Handlers are still clean and simple
func handler(resp http.ResponseWriter, req *http.Request) {
multipartForm := new(MultipartForm)
if errs := binding.Bind(req, multipartForm); errs != nil {
http.Error(resp, errs.Error(), http.StatusBadRequest)
return
}
// To access the file data you need to Open the file
// handler and read the bytes out.
var fh io.ReadCloser
var err error
if fh, err = multipartForm.Data.Open(); err != nil {
http.Error(resp,
fmt.Sprint("Error opening Mime::Data %v", err),
http.StatusInternalServerError)
return
}
defer fh.Close()
dataBytes := bytes.Buffer{}
var size int64
if size, err = dataBytes.ReadFrom(fh); err != nil {
http.Error(resp,
fmt.Sprint("Error reading Mime::Data %v", err),
http.StatusInternalServerError)
return
}
// Now you have the attachment in databytes.
// Maximum size is default is 10MB.
log.Printf("Read %v bytes with filename %s",
size, multipartForm.Data.Filename)
}
func main() {
http.HandleFunc("/upload", handler)
http.ListenAndServe(":3000", nil)
}
```
You can test from CLI using the excellent httpie client
`http -f POST localhost:3000/upload data@myupload`
Custom data validation
-----------------------
You may optionally have your type implement the `binding.Validator` interface to perform your own data validation. The `.Validate()` method is called after the struct is populated.
```go
func (cf ContactForm) Validate(req *http.Request) error {
if cf.Message == "Go needs generics" {
return binding.Errors{
binding.NewError([]string{"message"}, "ComplaintError", "Go has generics. They're called interfaces.")
}
}
return nil
}
```
Binding custom types
---------------------
For types you've defined, you can bind form data to it by implementing the `Binder` interface. Here's a contrived example:
```go
type MyBinder map[string]string
func (t MyBinder) Bind(fieldName string, strVals []string) error {
t["formData"] = strVals[0]
return nil
}
```
If you can't add a method to the type, you can still specify a `Binder` func in the field spec. Here's a contrived example that binds an integer (not necessary, but you get the idea):
```go
func (t *MyType) FieldMap(req *http.Request) binding.FieldMap {
return binding.FieldMap{
"a-key": binding.Field{
Form: "number",
Binder: func(fieldName string, formVals []string) error {
val, err := strconv.Atoi(formVals[0])
if err != nil {
return binding.Errors{binding.NewError([]string{fieldName}, binding.DeserializationError, err.Error())}
}
t.SomeNumber = val
return nil
},
},
}
}
```
The `Errors` type has a convenience method, `Add`, which you can use to append to the slice if you prefer.
Supported types (forms)
------------------------
The following types are supported in form deserialization by default. (JSON requests are delegated to `encoding/json`.)
- uint, \*uint, []uint, uint8, \*uint8, []uint8, uint16, \*uint16, []uint16, uint32, \*uint32, []uint32, uint64, \*uint64, []uint64
- int, \*int, []int, int8, \*int8, []int8, int16, \*int16, []int16, int32, \*int32, []int32, int64, \*int64, []int64
- float32, \*float32, []float32, float64, \*float64, []float64
- bool, \*bool, []bool
- string, \*string, []string
- time.Time, \*time.Time, []time.Time
- \*multipart.FileHeader, []\*multipart.FileHeader