Moving calls to client helper while I'm at it
diff --git a/_site/params.go b/_site/params.go
new file mode 100644
index 0000000..26c48c0
--- /dev/null
+++ b/_site/params.go
@@ -0,0 +1,182 @@
+package gophercloud
+
+import (
+	"fmt"
+	"net/url"
+	"reflect"
+	"strconv"
+	"strings"
+	"time"
+)
+
+// MaybeString takes a string that might be a zero-value, and either returns a
+// pointer to its address or a nil value (i.e. empty pointer). This is useful
+// for converting zero values in options structs when the end-user hasn't
+// defined values. Those zero values need to be nil in order for the JSON
+// serialization to ignore them.
+func MaybeString(original string) *string {
+	if original != "" {
+		return &original
+	}
+	return nil
+}
+
+// MaybeInt takes an int that might be a zero-value, and either returns a
+// pointer to its address or a nil value (i.e. empty pointer).
+func MaybeInt(original int) *int {
+	if original != 0 {
+		return &original
+	}
+	return nil
+}
+
+var t time.Time
+
+func isZero(v reflect.Value) bool {
+	switch v.Kind() {
+	case reflect.Func, reflect.Map, reflect.Slice:
+		return v.IsNil()
+	case reflect.Array:
+		z := true
+		for i := 0; i < v.Len(); i++ {
+			z = z && isZero(v.Index(i))
+		}
+		return z
+	case reflect.Struct:
+		if v.Type() == reflect.TypeOf(t) {
+			if v.Interface().(time.Time).IsZero() {
+				return true
+			}
+			return false
+		}
+		z := true
+		for i := 0; i < v.NumField(); i++ {
+			z = z && isZero(v.Field(i))
+		}
+		return z
+	}
+	// Compare other types directly:
+	z := reflect.Zero(v.Type())
+	return v.Interface() == z.Interface()
+}
+
+// BuildQueryString accepts a generic structure and parses it URL struct. It
+// converts field names into query names based on tags. So for example, this
+// type:
+//
+// struct {
+//    Bar string `q:"x_bar"`
+//    Baz int    `q:"lorem_ipsum"`
+// }{
+//    Bar: "XXX",
+//    Baz: "YYY",
+// }
+//
+// will be converted into ?x_bar=XXX&lorem_ipsum=YYYY
+func BuildQueryString(opts interface{}) (*url.URL, error) {
+	optsValue := reflect.ValueOf(opts)
+	if optsValue.Kind() == reflect.Ptr {
+		optsValue = optsValue.Elem()
+	}
+
+	optsType := reflect.TypeOf(opts)
+	if optsType.Kind() == reflect.Ptr {
+		optsType = optsType.Elem()
+	}
+
+	var optsSlice []string
+	if optsValue.Kind() == reflect.Struct {
+		for i := 0; i < optsValue.NumField(); i++ {
+			v := optsValue.Field(i)
+			f := optsType.Field(i)
+			qTag := f.Tag.Get("q")
+
+			// if the field has a 'q' tag, it goes in the query string
+			if qTag != "" {
+				tags := strings.Split(qTag, ",")
+
+				// if the field is set, add it to the slice of query pieces
+				if !isZero(v) {
+					switch v.Kind() {
+					case reflect.String:
+						optsSlice = append(optsSlice, tags[0]+"="+v.String())
+					case reflect.Int:
+						optsSlice = append(optsSlice, tags[0]+"="+strconv.FormatInt(v.Int(), 10))
+					case reflect.Bool:
+						optsSlice = append(optsSlice, tags[0]+"="+strconv.FormatBool(v.Bool()))
+					}
+				} else {
+					// Otherwise, the field is not set.
+					if len(tags) == 2 && tags[1] == "required" {
+						// And the field is required. Return an error.
+						return nil, fmt.Errorf("Required query parameter [%s] not set.", f.Name)
+					}
+				}
+			}
+
+		}
+		// URL encode the string for safety.
+		s := strings.Join(optsSlice, "&")
+		if s != "" {
+			s = "?" + s
+		}
+		u, err := url.Parse(s)
+		if err != nil {
+			return nil, err
+		}
+		return u, nil
+	}
+	// Return an error if the underlying type of 'opts' isn't a struct.
+	return nil, fmt.Errorf("Options type is not a struct.")
+}
+
+// BuildHeaders accepts a generic structure and parses it string map. It
+// converts field names into header names based on "h" tags, and field values
+// into header values by a simple one-to-one mapping.
+func BuildHeaders(opts interface{}) (map[string]string, error) {
+	optsValue := reflect.ValueOf(opts)
+	if optsValue.Kind() == reflect.Ptr {
+		optsValue = optsValue.Elem()
+	}
+
+	optsType := reflect.TypeOf(opts)
+	if optsType.Kind() == reflect.Ptr {
+		optsType = optsType.Elem()
+	}
+
+	optsMap := make(map[string]string)
+	if optsValue.Kind() == reflect.Struct {
+		for i := 0; i < optsValue.NumField(); i++ {
+			v := optsValue.Field(i)
+			f := optsType.Field(i)
+			hTag := f.Tag.Get("h")
+
+			// if the field has a 'h' tag, it goes in the header
+			if hTag != "" {
+				tags := strings.Split(hTag, ",")
+
+				// if the field is set, add it to the slice of query pieces
+				if !isZero(v) {
+					switch v.Kind() {
+					case reflect.String:
+						optsMap[tags[0]] = v.String()
+					case reflect.Int:
+						optsMap[tags[0]] = strconv.FormatInt(v.Int(), 10)
+					case reflect.Bool:
+						optsMap[tags[0]] = strconv.FormatBool(v.Bool())
+					}
+				} else {
+					// Otherwise, the field is not set.
+					if len(tags) == 2 && tags[1] == "required" {
+						// And the field is required. Return an error.
+						return optsMap, fmt.Errorf("Required header not set.")
+					}
+				}
+			}
+
+		}
+		return optsMap, nil
+	}
+	// Return an error if the underlying type of 'opts' isn't a struct.
+	return optsMap, fmt.Errorf("Options type is not a struct.")
+}