in api/common/request.go [46:156]
func ReadRequest(r *http.Request, obj interface{}, withRequests ...WithRequest) error {
vValue := reflect.ValueOf(obj)
vType := reflect.TypeOf(obj)
if vType.Kind() != reflect.Ptr || vType.Elem().Kind() != reflect.Struct {
return utils.APIError{
Code: http.StatusInternalServerError,
Message: "Expecting request object to be a pointer to struct",
}
}
var formParsed bool
for i := 0; i < vType.Elem().NumField(); i++ {
var isPathParam, isQueryParam, isHeaderParam, optional bool
var paramName, paramValue string
field := vType.Elem().Field(i)
valueField := vValue.Elem().Field(i)
// If it's anonymous field, we apply ReadRequest to this struct directly.
if field.Type.Kind() == reflect.Struct && field.Anonymous {
if err := ReadRequest(r, valueField.Addr().Interface(), withRequests...); err != nil {
return err
}
}
if paramName, isHeaderParam = field.Tag.Lookup("header"); isHeaderParam {
tagValues := strings.Split(paramName, ",")
paramName = tagValues[0]
if len(tagValues) == 2 && tagValues[1] == "optional" {
optional = true
}
paramValue = r.Header.Get(paramName)
} else if paramName, isPathParam = field.Tag.Lookup("path"); isPathParam {
vars := mux.Vars(r)
if vars == nil {
return ErrMissingParameter
}
paramValue = vars[paramName]
} else if paramName, isQueryParam = field.Tag.Lookup("query"); isQueryParam {
tagValues := strings.Split(paramName, ",")
paramName = tagValues[0]
if len(tagValues) == 2 && tagValues[1] == "optional" {
optional = true
}
if !formParsed {
if err := r.ParseForm(); err != nil && !optional {
return ErrMissingParameter
}
formParsed = true
}
paramValue = r.Form.Get(paramName)
}
if isPathParam || isQueryParam || isHeaderParam {
if paramValue == "" {
if optional {
continue
}
return ErrMissingParameter
}
// Only string and int is supported in request path fields.
switch field.Type.Kind() {
case reflect.String:
valueField.SetString(paramValue)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
intVal, err := strconv.ParseInt(paramValue, 10, 64)
if err != nil {
return ErrMissingParameter
}
valueField.SetInt(intVal)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
uintVal, err := strconv.ParseUint(paramValue, 10, 64)
if err != nil {
return ErrMissingParameter
}
valueField.SetUint(uintVal)
default:
return ErrMissingParameter
}
} else if _, isPostBody := field.Tag.Lookup("body"); isPostBody {
requestBody, err := ioutil.ReadAll(r.Body)
if err != nil {
return utils.APIError{
Code: http.StatusBadRequest,
Message: ErrMsgFailedToReadRequestBody,
Cause: err,
}
}
switch valueField.Addr().Interface().(type) {
case *[]byte:
valueField.SetBytes(requestBody)
case *json.RawMessage:
valueField.SetBytes(requestBody)
default:
err = json.Unmarshal(requestBody, valueField.Addr().Interface())
if err != nil {
return utils.APIError{
Code: http.StatusBadRequest,
Message: ErrMsgFailedToUnmarshalRequest,
Cause: err,
}
}
}
}
}
for _, withRequest := range withRequests {
withRequest(vValue.Elem().Interface())
}
return nil
}