한국어: 요청 바인딩
Bind[T] decodes the request body into a struct and automatically runs validation.
type CreateUserDTO struct {
Name string `validate:"required,min=2,max=50"`
Email string `validate:"required,email"`
Age int `validate:"min=0,max=150"`
Role string `validate:"oneof=admin user guest"`
}
func (c *UserController) create(r *http.Request) (any, error) {
dto, err := core.Bind[CreateUserDTO](r)
if err \!= nil {
return nil, err // already a 400 Bad Request
}
return c.svc.Create(dto), nil
}Returns ErrBadRequest automatically if:
Content-Typeis notapplication/json- Body is missing or malformed JSON
- Validation fails
Body size limit (default 1 MB):
core.SetMaxBodySize(5 << 20) // 5 MB; set 0 to disable| Tag | Description |
|---|---|
required |
Field must be present and non-zero |
min=N |
Minimum length (string), value (number), or item count (slice/map) |
max=N |
Maximum length (string), value (number), or item count (slice/map) |
len=N |
Exact length (string, slice, array, map) |
email |
Valid email format |
url |
Valid HTTP/HTTPS URL |
uuid |
Valid UUID format |
oneof=a|b|c |
Value must be one of the listed options (string or int) |
alpha |
Letters only |
alphanum |
Letters and numbers only |
numeric |
Digits only |
lowercase |
Must be lowercase |
uppercase |
Must be uppercase |
contains=sub |
Must contain substring |
startswith=pre |
Must start with prefix |
endswith=suf |
Must end with suffix |
regex=pattern |
Must match regex pattern |
dive |
Validate each element of a slice/array |
Nested structs are validated recursively with dot-separated field paths (e.g. address.city).
// Supported types: string, int, int64, uint, uint64
id, err := core.Param[int64](r, "id") // /users/{id}
name, err := core.Param[string](r, "slug") // /posts/{slug}Returns ErrBadRequest if the parameter is missing or cannot be converted to the requested type.
Single value:
page := core.BindQuery(r, "page") // GET /users?page=2 → "2"
q := core.BindQuery(r, "q") // returns "" if absentStruct binding (with validation):
type ListQuery struct {
Page int `query:"page"`
Limit int `query:"limit" validate:"max=100"`
Sort string `query:"sort" validate:"oneof=asc|desc"`
Tags []string `query:"tag"`
}
func (c *Controller) list(r *http.Request) (any, error) {
q, err := core.BindQueryStruct[ListQuery](r)
if err != nil {
return nil, err
}
// q.Page, q.Limit, q.Sort, q.Tags are typed and validated
}Supported types: string, int, int64, uint, uint64, float32, float64, bool, []string.
token := core.BindHeader(r, "Authorization")
accept := core.BindHeader(r, "Accept")func (c *Controller) upload(r *http.Request) (any, error) {
f, err := core.BindFile(r, "avatar")
if err \!= nil {
return nil, err
}
// f.Filename — sanitized base name (path components stripped)
// f.ContentType — server-detected MIME type (not client-declared)
// f.Size — byte length
// f.Content — []byte file data
// f.Header — raw multipart.FileHeader for custom metadata
return map[string]any{"name": f.Filename, "size": f.Size}, nil
}files, err := core.BindFiles(r, "images")
if err \!= nil {
return nil, err
}
for _, f := range files {
// process f.Content
}Upload limits:
core.SetMaxUploadSize(64 << 20) // total form size (default 32 MB)
core.SetMaxFileCount(10) // max files per request (default 20)
core.SetMaxSingleFileSize(5 << 20) // max per file (default 10 MB)Security note:
Filenameis sanitized server-side (path separators and null bytes removed).ContentTypeis detected from file content, not the client's declared value. Do not useFilenameas a filesystem path without additional validation.