package binding import ( "net/http" ) const ( MIMEJSON = "application/json" MIMEHTML = "text/html" MIMEXML = "application/xml" MIMEXML2 = "text/xml" MIMEPlain = "text/plain" MIMEPOSTForm = "application/x-www-form-urlencoded" MIMEMultipartPOSTForm = "multipart/form-data" MIMEPROTOBUF = "application/x-protobuf" MIMEMSGPACK = "application/x-msgpack" MIMEMSGPACK2 = "application/msgpack" MIMEYAML = "application/x-yaml" MIMEYAML2 = "application/yaml" MIMETOML = "application/toml" ) type Binding interface { Name() string Bind(*http.Request, any) error } type BindingBody interface { Binding BindBody([]byte, any) error } type BindingUri interface { Name() string BindUri(map[string][]string, any) error } // StructValidator is the minimal interface which needs to be implemented in // order for it to be used as the validator engine for ensuring the correctness // of the request. Gin provides a default implementation for this using // https://github.com/go-playground/validator/tree/v10.6.1. type StructValidator interface { // ValidateStruct can receive any kind of type and it should never panic, even if the configuration is not right. // If the received type is a slice|array, the validation should be performed travel on every element. // If the received type is not a struct or slice|array, any validation should be skipped and nil must be returned. // If the received type is a struct or pointer to a struct, the validation should be performed. // If the struct is not valid or the validation itself fails, a descriptive error should be returned. // Otherwise nil must be returned. ValidateStruct(any) error // Engine returns the underlying validator engine which powers the // StructValidator implementation. Engine() any } // Validator is the default validator which implements the StructValidator // interface. It uses https://github.com/go-playground/validator/tree/v10.6.1 // under the hood. var Validator StructValidator = &defaultValidator{} var ( JSON BindingBody = jsonBinding{} // XML BindingBody = xmlBinding{} Form Binding = formBinding{} Query Binding = queryBinding{} FormPost Binding = formPostBinding{} FormMultipart Binding = formMultipartBinding{} // ProtoBuf BindingBody = protobufBinding{} // MsgPack BindingBody = msgpackBinding{} // YAML BindingBody = yamlBinding{} // Uri BindingUri = uriBinding{} // Header Binding = headerBinding{} // Plain BindingBody = plainBinding{} // TOML BindingBody = tomlBinding{} ) // Default returns the appropriate Binding instance based on the HTTP method // and the content type. func Default(method, contentType string) Binding { if method == http.MethodGet { return Form } switch contentType { case MIMEJSON: return JSON // case MIMEXML, MIMEXML2: // return XML // case MIMEPROTOBUF: // return ProtoBuf // case MIMEMSGPACK, MIMEMSGPACK2: // return MsgPack // case MIMEYAML, MIMEYAML2: // return YAML // case MIMETOML: // return TOML case MIMEMultipartPOSTForm: return FormMultipart default: // case MIMEPOSTForm: return Form } } func validate(obj any) error { if Validator == nil { return nil } return Validator.ValidateStruct(obj) } // ShouldBind checks the Method and Content-Type to select a binding engine automatically, // Depending on the "Content-Type" header different bindings are used, for example: // // "application/json" --> JSON binding // "application/xml" --> XML binding // // It parses the request's body as JSON if Content-Type == "application/json" using JSON or XML as a JSON input. // It decodes the json payload into the struct specified as a pointer. // Like c.Bind() but this method does not set the response status code to 400 or abort if input is not valid. func ShouldBind(r *http.Request, obj any) error { b := Default(r.Method, r.Header.Get("Content-Type")) return ShouldBindWith(r, obj, b) } // ShouldBindJSON is a shortcut for c.ShouldBindWith(obj, JSON). func ShouldBindJSON(r *http.Request, obj any) error { return ShouldBindWith(r, obj, JSON) } // ShouldBindWith binds the passed struct pointer using the specified binding engine. // See the binding package. func ShouldBindWith(r *http.Request, obj any, b Binding) error { return b.Bind(r, obj) } // ShouldBindQuery is a shortcut for c.ShouldBindWith(obj, Query). func ShouldBindQuery(r *http.Request, obj any) error { return ShouldBindWith(r, obj, Query) }