dsl struct tags; wip
diff --git a/openstack/db/v1/configurations/requests.go b/openstack/db/v1/configurations/requests.go
index abb0013..eb59cc2 100644
--- a/openstack/db/v1/configurations/requests.go
+++ b/openstack/db/v1/configurations/requests.go
@@ -8,11 +8,9 @@
 
 // List will list all of the available configurations.
 func List(client *gophercloud.ServiceClient) pagination.Pager {
-	pageFn := func(r pagination.PageResult) pagination.Page {
+	return pagination.NewPager(client, baseURL(client), func(r pagination.PageResult) pagination.Page {
 		return ConfigPage{pagination.SinglePageBase(r)}
-	}
-
-	return pagination.NewPager(client, baseURL(client), pageFn)
+	})
 }
 
 // CreateOptsBuilder is a top-level interface which renders a JSON map.
@@ -23,109 +21,51 @@
 // DatastoreOpts is the primary options struct for creating and modifying
 // how configuration resources are associated with datastores.
 type DatastoreOpts struct {
-	// [OPTIONAL] The type of datastore. Defaults to "MySQL".
-	Type string
-
-	// [OPTIONAL] The specific version of a datastore. Defaults to "5.6".
-	Version string
-}
-
-// ToMap renders a JSON map for a datastore setting.
-func (opts DatastoreOpts) ToMap() (map[string]string, error) {
-	datastore := map[string]string{}
-
-	if opts.Type != "" {
-		datastore["type"] = opts.Type
-	}
-
-	if opts.Version != "" {
-		datastore["version"] = opts.Version
-	}
-
-	return datastore, nil
+	// The type of datastore. Defaults to "MySQL".
+	Type string `json:"type,omitempty"`
+	// The specific version of a datastore. Defaults to "5.6".
+	Version string `json:"version,omitempty"`
 }
 
 // CreateOpts is the struct responsible for configuring new configurations.
 type CreateOpts struct {
 	// [REQUIRED] The configuration group name
-	Name string
+	Name string `json:"name" required:"true"`
 
 	// [REQUIRED] A map of user-defined configuration settings that will define
 	// how each associated datastore works. Each key/value pair is specific to a
 	// datastore type.
-	Values map[string]interface{}
+	Values map[string]interface{} `json:"values" required:"true"`
 
-	// [OPTIONAL] Associates the configuration group with a particular datastore.
-	Datastore *DatastoreOpts
+	// Associates the configuration group with a particular datastore.
+	Datastore *DatastoreOpts `json:"datastore,omitempty"`
 
-	// [OPTIONAL] A human-readable explanation for the group.
-	Description string
+	// A human-readable explanation for the group.
+	Description string `json:"description,omitempty"`
 }
 
 // ToConfigCreateMap casts a CreateOpts struct into a JSON map.
 func (opts CreateOpts) ToConfigCreateMap() (map[string]interface{}, error) {
-	if opts.Name == "" {
-		err := gophercloud.ErrMissingInput{}
-		err.Function = "configurations.ToConfigCreateMap"
-		err.Argument = "configurations.CreateOpts.Name"
-		return nil, err
-	}
-	if len(opts.Values) == 0 {
-		err := gophercloud.ErrMissingInput{}
-		err.Function = "configurations.ToConfigCreateMap"
-		err.Argument = "configurations.CreateOpts.Values"
-		return nil, err
-	}
-
-	config := map[string]interface{}{
-		"name":   opts.Name,
-		"values": opts.Values,
-	}
-
-	if opts.Datastore != nil {
-		ds, err := opts.Datastore.ToMap()
-		if err != nil {
-			return config, err
-		}
-		config["datastore"] = ds
-	}
-
-	if opts.Description != "" {
-		config["description"] = opts.Description
-	}
-
-	return map[string]interface{}{"configuration": config}, nil
+	return gophercloud.BuildRequestBody(opts, "configuration")
 }
 
 // Create will create a new configuration group.
 func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
-	var res CreateResult
-
-	reqBody, err := opts.ToConfigCreateMap()
+	var r CreateResult
+	b, err := opts.ToConfigCreateMap()
 	if err != nil {
-		res.Err = err
-		return res
+		r.Err = err
+		return r
 	}
-
-	_, res.Err = client.Request("POST", baseURL(client), &gophercloud.RequestOpts{
-		OkCodes:      []int{200},
-		JSONBody:     &reqBody,
-		JSONResponse: &res.Body,
-	})
-
-	return res
+	_, r.Err = client.Post(baseURL(client), &b, &r.Body, &gophercloud.RequestOpts{OkCodes: []int{200}})
+	return r
 }
 
 // Get will retrieve the details for a specified configuration group.
 func Get(client *gophercloud.ServiceClient, configID string) GetResult {
-	var res GetResult
-
-	_, res.Err = client.Request("GET", resourceURL(client, configID), &gophercloud.RequestOpts{
-		OkCodes:      []int{200},
-		JSONResponse: &res.Body,
-	})
-
-	return res
+	var r GetResult
+	_, r.Err = client.Get(resourceURL(client, configID), &r.Body, nil)
+	return r
 }
 
 // UpdateOptsBuilder is the top-level interface for casting update options into
@@ -136,108 +76,66 @@
 
 // UpdateOpts is the struct responsible for modifying existing configurations.
 type UpdateOpts struct {
-	// [OPTIONAL] The configuration group name
-	Name string
-
-	// [OPTIONAL] A map of user-defined configuration settings that will define
+	// The configuration group name
+	Name string `json:"name,omitempty"`
+	// A map of user-defined configuration settings that will define
 	// how each associated datastore works. Each key/value pair is specific to a
 	// datastore type.
-	Values map[string]interface{}
-
-	// [OPTIONAL] Associates the configuration group with a particular datastore.
-	Datastore *DatastoreOpts
-
-	// [OPTIONAL] A human-readable explanation for the group.
-	Description string
+	Values map[string]interface{} `json:"values,omitempty"`
+	// Associates the configuration group with a particular datastore.
+	Datastore *DatastoreOpts `json:"datastore,omitempty"`
+	// A human-readable explanation for the group.
+	Description string `json:"description,omitempty"`
 }
 
 // ToConfigUpdateMap will cast an UpdateOpts struct into a JSON map.
 func (opts UpdateOpts) ToConfigUpdateMap() (map[string]interface{}, error) {
-	config := map[string]interface{}{}
-
-	if opts.Name != "" {
-		config["name"] = opts.Name
-	}
-
-	if opts.Description != "" {
-		config["description"] = opts.Description
-	}
-
-	if opts.Datastore != nil {
-		ds, err := opts.Datastore.ToMap()
-		if err != nil {
-			return config, err
-		}
-		config["datastore"] = ds
-	}
-
-	if len(opts.Values) > 0 {
-		config["values"] = opts.Values
-	}
-
-	return map[string]interface{}{"configuration": config}, nil
+	return gophercloud.BuildRequestBody(opts, "configuration")
 }
 
 // Update will modify an existing configuration group by performing a merge
 // between new and existing values. If the key already exists, the new value
 // will overwrite. All other keys will remain unaffected.
 func Update(client *gophercloud.ServiceClient, configID string, opts UpdateOptsBuilder) UpdateResult {
-	var res UpdateResult
-
-	reqBody, err := opts.ToConfigUpdateMap()
+	var r UpdateResult
+	b, err := opts.ToConfigUpdateMap()
 	if err != nil {
-		res.Err = err
-		return res
+		r.Err = err
+		return r
 	}
-
-	_, res.Err = client.Request("PATCH", resourceURL(client, configID), &gophercloud.RequestOpts{
-		OkCodes:  []int{200},
-		JSONBody: &reqBody,
-	})
-
-	return res
+	_, r.Err = client.Patch(resourceURL(client, configID), &b, nil, nil)
+	return r
 }
 
 // Replace will modify an existing configuration group by overwriting the
 // entire parameter group with the new values provided. Any existing keys not
 // included in UpdateOptsBuilder will be deleted.
 func Replace(client *gophercloud.ServiceClient, configID string, opts UpdateOptsBuilder) ReplaceResult {
-	var res ReplaceResult
-
-	reqBody, err := opts.ToConfigUpdateMap()
+	var r ReplaceResult
+	b, err := opts.ToConfigUpdateMap()
 	if err != nil {
-		res.Err = err
-		return res
+		r.Err = err
+		return r
 	}
-
-	_, res.Err = client.Request("PUT", resourceURL(client, configID), &gophercloud.RequestOpts{
-		OkCodes:  []int{202},
-		JSONBody: &reqBody,
-	})
-
-	return res
+	_, r.Err = client.Put(resourceURL(client, configID), &b, nil, nil)
+	return r
 }
 
 // Delete will permanently delete a configuration group. Please note that
 // config groups cannot be deleted whilst still attached to running instances -
 // you must detach and then delete them.
 func Delete(client *gophercloud.ServiceClient, configID string) DeleteResult {
-	var res DeleteResult
-
-	_, res.Err = client.Request("DELETE", resourceURL(client, configID), &gophercloud.RequestOpts{
-		OkCodes: []int{202},
-	})
-
-	return res
+	var r DeleteResult
+	_, r.Err = client.Delete(resourceURL(client, configID), nil)
+	return r
 }
 
 // ListInstances will list all the instances associated with a particular
 // configuration group.
 func ListInstances(client *gophercloud.ServiceClient, configID string) pagination.Pager {
-	pageFn := func(r pagination.PageResult) pagination.Page {
+	return pagination.NewPager(client, instancesURL(client, configID), func(r pagination.PageResult) pagination.Page {
 		return instances.InstancePage{pagination.LinkedPageBase{PageResult: r}}
-	}
-	return pagination.NewPager(client, instancesURL(client, configID), pageFn)
+	})
 }
 
 // ListDatastoreParams will list all the available and supported parameters
@@ -246,10 +144,9 @@
 // you can use this operation (you will need to retrieve the MySQL datastore ID
 // by using the datastores API).
 func ListDatastoreParams(client *gophercloud.ServiceClient, datastoreID, versionID string) pagination.Pager {
-	pageFn := func(r pagination.PageResult) pagination.Page {
+	return pagination.NewPager(client, listDSParamsURL(client, datastoreID, versionID), func(r pagination.PageResult) pagination.Page {
 		return ParamPage{pagination.SinglePageBase(r)}
-	}
-	return pagination.NewPager(client, listDSParamsURL(client, datastoreID, versionID), pageFn)
+	})
 }
 
 // GetDatastoreParam will retrieve information about a specific configuration
@@ -258,34 +155,23 @@
 // need the param's ID first, which can be attained by using the ListDatastoreParams
 // operation.
 func GetDatastoreParam(client *gophercloud.ServiceClient, datastoreID, versionID, paramID string) ParamResult {
-	var res ParamResult
-
-	_, res.Err = client.Request("GET", getDSParamURL(client, datastoreID, versionID, paramID), &gophercloud.RequestOpts{
-		OkCodes:      []int{200},
-		JSONResponse: &res.Body,
-	})
-
-	return res
+	var r ParamResult
+	_, r.Err = client.Get(getDSParamURL(client, datastoreID, versionID, paramID), &r.Body, nil)
+	return r
 }
 
 // ListGlobalParams is similar to ListDatastoreParams but does not require a
 // DatastoreID.
 func ListGlobalParams(client *gophercloud.ServiceClient, versionID string) pagination.Pager {
-	pageFn := func(r pagination.PageResult) pagination.Page {
+	return pagination.NewPager(client, listGlobalParamsURL(client, versionID), func(r pagination.PageResult) pagination.Page {
 		return ParamPage{pagination.SinglePageBase(r)}
-	}
-	return pagination.NewPager(client, listGlobalParamsURL(client, versionID), pageFn)
+	})
 }
 
 // GetGlobalParam is similar to GetDatastoreParam but does not require a
 // DatastoreID.
 func GetGlobalParam(client *gophercloud.ServiceClient, versionID, paramID string) ParamResult {
-	var res ParamResult
-
-	_, res.Err = client.Request("GET", getGlobalParamURL(client, versionID, paramID), &gophercloud.RequestOpts{
-		OkCodes:      []int{200},
-		JSONResponse: &res.Body,
-	})
-
-	return res
+	var r ParamResult
+	_, r.Err = client.Get(getGlobalParamURL(client, versionID, paramID), &r.Body, nil)
+	return r
 }
diff --git a/openstack/db/v1/databases/requests.go b/openstack/db/v1/databases/requests.go
index 18e1af5..7338112 100644
--- a/openstack/db/v1/databases/requests.go
+++ b/openstack/db/v1/databases/requests.go
@@ -13,52 +13,35 @@
 // CreateOpts is the struct responsible for configuring a database; often in
 // the context of an instance.
 type CreateOpts struct {
-	// [REQUIRED] Specifies the name of the database. Valid names can be composed
+	// Specifies the name of the database. Valid names can be composed
 	// of the following characters: letters (either case); numbers; these
 	// characters '@', '?', '#', ' ' but NEVER beginning a name string; '_' is
 	// permitted anywhere. Prohibited characters that are forbidden include:
 	// single quotes, double quotes, back quotes, semicolons, commas, backslashes,
 	// and forward slashes.
-	Name string
-
-	// [OPTIONAL] Set of symbols and encodings. The default character set is
+	Name string `json:"name" required:"true"`
+	// Set of symbols and encodings. The default character set is
 	// "utf8". See http://dev.mysql.com/doc/refman/5.1/en/charset-mysql.html for
 	// supported character sets.
-	CharSet string
-
-	// [OPTIONAL] Set of rules for comparing characters in a character set. The
+	CharSet string `json:"character_set,omitempty"`
+	// Set of rules for comparing characters in a character set. The
 	// default value for collate is "utf8_general_ci". See
 	// http://dev.mysql.com/doc/refman/5.1/en/charset-mysql.html for supported
 	// collations.
-	Collate string
+	Collate string `json:"collate,omitempty"`
 }
 
 // ToMap is a helper function to convert individual DB create opt structures
 // into sub-maps.
-func (opts CreateOpts) ToMap() (map[string]string, error) {
-	if opts.Name == "" {
-		err := gophercloud.ErrMissingInput{}
-		err.Function = "databases.ToMap"
-		err.Argument = "databases.CreateOpts.Name"
-	}
+func (opts CreateOpts) ToMap() (map[string]interface{}, error) {
 	if len(opts.Name) > 64 {
 		err := gophercloud.ErrInvalidInput{}
-		err.Function = "databases.ToMap"
 		err.Argument = "databases.CreateOpts.Name"
 		err.Value = opts.Name
 		err.Info = "Must be less than 64 chars long"
 		return nil, err
 	}
-
-	db := map[string]string{"name": opts.Name}
-
-	if opts.CharSet != "" {
-		db["character_set"] = opts.CharSet
-	}
-	if opts.Collate != "" {
-		db["collate"] = opts.Collate
-	}
-	return db, nil
+	return gophercloud.BuildRequestBody(opts, "")
 }
 
 // BatchCreateOpts allows for multiple databases to created and modified.
@@ -66,7 +49,7 @@
 
 // ToDBCreateMap renders a JSON map for creating DBs.
 func (opts BatchCreateOpts) ToDBCreateMap() (map[string]interface{}, error) {
-	dbs := make([]map[string]string, len(opts))
+	dbs := make([]map[string]interface{}, len(opts))
 	for i, db := range opts {
 		dbMap, err := db.ToMap()
 		if err != nil {
@@ -80,41 +63,29 @@
 // Create will create a new database within the specified instance. If the
 // specified instance does not exist, a 404 error will be returned.
 func Create(client *gophercloud.ServiceClient, instanceID string, opts CreateOptsBuilder) CreateResult {
-	var res CreateResult
-
-	reqBody, err := opts.ToDBCreateMap()
+	var r CreateResult
+	b, err := opts.ToDBCreateMap()
 	if err != nil {
-		res.Err = err
-		return res
+		r.Err = err
+		return r
 	}
-
-	_, res.Err = client.Request("POST", baseURL(client, instanceID), &gophercloud.RequestOpts{
-		JSONBody: &reqBody,
-		OkCodes:  []int{202},
-	})
-
-	return res
+	_, r.Err = client.Post(baseURL(client, instanceID), &b, nil, nil)
+	return r
 }
 
 // List will list all of the databases for a specified instance. Note: this
 // operation will only return user-defined databases; it will exclude system
 // databases like "mysql", "information_schema", "lost+found" etc.
 func List(client *gophercloud.ServiceClient, instanceID string) pagination.Pager {
-	createPageFn := func(r pagination.PageResult) pagination.Page {
+	return pagination.NewPager(client, baseURL(client, instanceID), func(r pagination.PageResult) pagination.Page {
 		return DBPage{pagination.LinkedPageBase{PageResult: r}}
-	}
-
-	return pagination.NewPager(client, baseURL(client, instanceID), createPageFn)
+	})
 }
 
 // Delete will permanently delete the database within a specified instance.
 // All contained data inside the database will also be permanently deleted.
 func Delete(client *gophercloud.ServiceClient, instanceID, dbName string) DeleteResult {
-	var res DeleteResult
-
-	_, res.Err = client.Request("DELETE", dbURL(client, instanceID, dbName), &gophercloud.RequestOpts{
-		OkCodes: []int{202},
-	})
-
-	return res
+	var r DeleteResult
+	_, r.Err = client.Delete(dbURL(client, instanceID, dbName), nil)
+	return r
 }
diff --git a/openstack/db/v1/datastores/requests.go b/openstack/db/v1/datastores/requests.go
index 277c797..d820915 100644
--- a/openstack/db/v1/datastores/requests.go
+++ b/openstack/db/v1/datastores/requests.go
@@ -7,41 +7,29 @@
 
 // List will list all available datastore types that instances can use.
 func List(client *gophercloud.ServiceClient) pagination.Pager {
-	pageFn := func(r pagination.PageResult) pagination.Page {
+	return pagination.NewPager(client, baseURL(client), func(r pagination.PageResult) pagination.Page {
 		return DatastorePage{pagination.SinglePageBase(r)}
-	}
-	return pagination.NewPager(client, baseURL(client), pageFn)
+	})
 }
 
 // Get will retrieve the details of a specified datastore type.
 func Get(client *gophercloud.ServiceClient, datastoreID string) GetResult {
-	var res GetResult
-
-	_, res.Err = client.Request("GET", resourceURL(client, datastoreID), &gophercloud.RequestOpts{
-		OkCodes:      []int{200},
-		JSONResponse: &res.Body,
-	})
-
-	return res
+	var r GetResult
+	_, r.Err = client.Get(resourceURL(client, datastoreID), &r.Body, nil)
+	return r
 }
 
 // ListVersions will list all of the available versions for a specified
 // datastore type.
 func ListVersions(client *gophercloud.ServiceClient, datastoreID string) pagination.Pager {
-	pageFn := func(r pagination.PageResult) pagination.Page {
+	return pagination.NewPager(client, versionsURL(client, datastoreID), func(r pagination.PageResult) pagination.Page {
 		return VersionPage{pagination.SinglePageBase(r)}
-	}
-	return pagination.NewPager(client, versionsURL(client, datastoreID), pageFn)
+	})
 }
 
 // GetVersion will retrieve the details of a specified datastore version.
 func GetVersion(client *gophercloud.ServiceClient, datastoreID, versionID string) GetVersionResult {
-	var res GetVersionResult
-
-	_, res.Err = client.Request("GET", versionURL(client, datastoreID, versionID), &gophercloud.RequestOpts{
-		OkCodes:      []int{200},
-		JSONResponse: &res.Body,
-	})
-
-	return res
+	var r GetVersionResult
+	_, r.Err = client.Get(versionURL(client, datastoreID, versionID), &r.Body, nil)
+	return r
 }
diff --git a/openstack/db/v1/flavors/requests.go b/openstack/db/v1/flavors/requests.go
index c767606..8b7797f 100644
--- a/openstack/db/v1/flavors/requests.go
+++ b/openstack/db/v1/flavors/requests.go
@@ -9,21 +9,14 @@
 // operation is identical to the one supported by the Nova API, but without the
 // "disk" property.
 func List(client *gophercloud.ServiceClient) pagination.Pager {
-	createPage := func(r pagination.PageResult) pagination.Page {
+	return pagination.NewPager(client, listURL(client), func(r pagination.PageResult) pagination.Page {
 		return FlavorPage{pagination.LinkedPageBase{PageResult: r}}
-	}
-
-	return pagination.NewPager(client, listURL(client), createPage)
+	})
 }
 
 // Get will retrieve information for a specified hardware flavor.
 func Get(client *gophercloud.ServiceClient, id string) GetResult {
-	var gr GetResult
-
-	_, gr.Err = client.Request("GET", getURL(client, id), &gophercloud.RequestOpts{
-		JSONResponse: &gr.Body,
-		OkCodes:      []int{200},
-	})
-
-	return gr
+	var r GetResult
+	_, r.Err = client.Get(getURL(client, id), &r.Body, nil)
+	return r
 }
diff --git a/openstack/db/v1/instances/requests.go b/openstack/db/v1/instances/requests.go
index 8e33dfe..b8cae03 100644
--- a/openstack/db/v1/instances/requests.go
+++ b/openstack/db/v1/instances/requests.go
@@ -14,16 +14,13 @@
 
 // DatastoreOpts represents the configuration for how an instance stores data.
 type DatastoreOpts struct {
-	Version string
-	Type    string
+	Version string `json:"version"`
+	Type    string `json:"type"`
 }
 
 // ToMap converts a DatastoreOpts to a map[string]string (for a request body)
-func (opts DatastoreOpts) ToMap() (map[string]string, error) {
-	return map[string]string{
-		"version": opts.Version,
-		"type":    opts.Type,
-	}, nil
+func (opts DatastoreOpts) ToMap() (map[string]interface{}, error) {
+	return gophercloud.BuildRequestBody(opts, "")
 }
 
 // CreateOpts is the struct responsible for configuring a new database instance.
@@ -31,21 +28,16 @@
 	// Either the integer UUID (in string form) of the flavor, or its URI
 	// reference as specified in the response from the List() call. Required.
 	FlavorRef string
-
 	// Specifies the volume size in gigabytes (GB). The value must be between 1
 	// and 300. Required.
 	Size int
-
 	// Name of the instance to create. The length of the name is limited to
 	// 255 characters and any characters are permitted. Optional.
 	Name string
-
 	// A slice of database information options.
 	Databases db.CreateOptsBuilder
-
 	// A slice of user information options.
 	Users users.CreateOptsBuilder
-
 	// Options to configure the type of datastore the instance will use. This is
 	// optional, and if excluded will default to MySQL.
 	Datastore *DatastoreOpts
@@ -55,17 +47,14 @@
 func (opts CreateOpts) ToInstanceCreateMap() (map[string]interface{}, error) {
 	if opts.Size > 300 || opts.Size < 1 {
 		err := gophercloud.ErrInvalidInput{}
-		err.Function = "instances.ToInstanceCreateMap"
 		err.Argument = "instances.CreateOpts.Size"
 		err.Value = opts.Size
 		err.Info = "Size (GB) must be between 1-300"
 		return nil, err
 	}
+
 	if opts.FlavorRef == "" {
-		err := gophercloud.ErrMissingInput{}
-		err.Function = "instances.ToInstanceCreateMap"
-		err.Argument = "instances.CreateOpts.FlavorRef"
-		return nil, err
+		return nil, gophercloud.ErrMissingInput{Argument: "instances.CreateOpts.FlavorRef"}
 	}
 
 	instance := map[string]interface{}{
@@ -110,143 +99,79 @@
 // can create an instance with multiple databases and users. The default
 // binding for a MySQL instance is port 3306.
 func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
-	var res CreateResult
-
-	reqBody, err := opts.ToInstanceCreateMap()
+	var r CreateResult
+	b, err := opts.ToInstanceCreateMap()
 	if err != nil {
-		res.Err = err
-		return res
+		r.Err = err
+		return r
 	}
-
-	_, res.Err = client.Request("POST", baseURL(client), &gophercloud.RequestOpts{
-		JSONBody:     &reqBody,
-		JSONResponse: &res.Body,
-		OkCodes:      []int{200},
-	})
-
-	return res
+	_, r.Err = client.Post(baseURL(client), &b, &r.Body, &gophercloud.RequestOpts{OkCodes: []int{200}})
+	return r
 }
 
 // List retrieves the status and information for all database instances.
 func List(client *gophercloud.ServiceClient) pagination.Pager {
-	createPageFn := func(r pagination.PageResult) pagination.Page {
+	return pagination.NewPager(client, baseURL(client), func(r pagination.PageResult) pagination.Page {
 		return InstancePage{pagination.LinkedPageBase{PageResult: r}}
-	}
-
-	return pagination.NewPager(client, baseURL(client), createPageFn)
+	})
 }
 
 // Get retrieves the status and information for a specified database instance.
 func Get(client *gophercloud.ServiceClient, id string) GetResult {
-	var res GetResult
-
-	_, res.Err = client.Request("GET", resourceURL(client, id), &gophercloud.RequestOpts{
-		JSONResponse: &res.Body,
-		OkCodes:      []int{200},
-	})
-
-	return res
+	var r GetResult
+	_, r.Err = client.Get(resourceURL(client, id), &r.Body, nil)
+	return r
 }
 
 // Delete permanently destroys the database instance.
 func Delete(client *gophercloud.ServiceClient, id string) DeleteResult {
-	var res DeleteResult
-
-	_, res.Err = client.Request("DELETE", resourceURL(client, id), &gophercloud.RequestOpts{
-		OkCodes: []int{202},
-	})
-
-	return res
+	var r DeleteResult
+	_, r.Err = client.Delete(resourceURL(client, id), nil)
+	return r
 }
 
 // EnableRootUser enables the login from any host for the root user and
 // provides the user with a generated root password.
-func EnableRootUser(client *gophercloud.ServiceClient, id string) UserRootResult {
-	var res UserRootResult
-
-	_, res.Err = client.Request("POST", userRootURL(client, id), &gophercloud.RequestOpts{
-		JSONResponse: &res.Body,
-		OkCodes:      []int{200},
-	})
-
-	return res
+func EnableRootUser(client *gophercloud.ServiceClient, id string) EnableRootUserResult {
+	var r EnableRootUserResult
+	_, r.Err = client.Post(userRootURL(client, id), nil, &r.Body, &gophercloud.RequestOpts{OkCodes: []int{200}})
+	return r
 }
 
 // IsRootEnabled checks an instance to see if root access is enabled. It returns
 // True if root user is enabled for the specified database instance or False
 // otherwise.
-func IsRootEnabled(client *gophercloud.ServiceClient, id string) (bool, error) {
-	var res gophercloud.Result
-
-	_, err := client.Request("GET", userRootURL(client, id), &gophercloud.RequestOpts{
-		JSONResponse: &res.Body,
-		OkCodes:      []int{200},
-	})
-
-	return res.Body.(map[string]interface{})["rootEnabled"] == true, err
+func IsRootEnabled(client *gophercloud.ServiceClient, id string) IsRootEnabledResult {
+	var r IsRootEnabledResult
+	_, r.Err = client.Get(userRootURL(client, id), &r.Body, nil)
+	return r
 }
 
 // Restart will restart only the MySQL Instance. Restarting MySQL will
 // erase any dynamic configuration settings that you have made within MySQL.
 // The MySQL service will be unavailable until the instance restarts.
 func Restart(client *gophercloud.ServiceClient, id string) ActionResult {
-	var res ActionResult
-
-	_, res.Err = client.Request("POST", actionURL(client, id), &gophercloud.RequestOpts{
-		JSONBody: map[string]interface{}{"restart": struct{}{}},
-		OkCodes:  []int{202},
-	})
-
-	return res
+	var r ActionResult
+	b := map[string]interface{}{"restart": struct{}{}}
+	_, r.Err = client.Post(actionURL(client, id), &b, nil, nil)
+	return r
 }
 
 // Resize changes the memory size of the instance, assuming a valid
 // flavorRef is provided. It will also restart the MySQL service.
 func Resize(client *gophercloud.ServiceClient, id, flavorRef string) ActionResult {
-	var res ActionResult
-
-	type resize struct {
-		FlavorRef string `json:"flavorRef"`
-	}
-
-	type req struct {
-		Resize resize `json:"resize"`
-	}
-
-	reqBody := req{Resize: resize{FlavorRef: flavorRef}}
-
-	_, res.Err = client.Request("POST", actionURL(client, id), &gophercloud.RequestOpts{
-		JSONBody: reqBody,
-		OkCodes:  []int{202},
-	})
-
-	return res
+	var r ActionResult
+	b := map[string]interface{}{"resize": map[string]string{"flavorRef": flavorRef}}
+	_, r.Err = client.Post(actionURL(client, id), &b, nil, nil)
+	return r
 }
 
 // ResizeVolume will resize the attached volume for an instance. It supports
 // only increasing the volume size and does not support decreasing the size.
 // The volume size is in gigabytes (GB) and must be an integer.
 func ResizeVolume(client *gophercloud.ServiceClient, id string, size int) ActionResult {
-	var res ActionResult
-
-	type volume struct {
-		Size int `json:"size"`
-	}
-
-	type resize struct {
-		Volume volume `json:"volume"`
-	}
-
-	type req struct {
-		Resize resize `json:"resize"`
-	}
-
-	reqBody := req{Resize: resize{Volume: volume{Size: size}}}
-
-	_, res.Err = client.Request("POST", actionURL(client, id), &gophercloud.RequestOpts{
-		JSONBody: reqBody,
-		OkCodes:  []int{202},
-	})
-
-	return res
+	var r ActionResult
+	b := map[string]interface{}{"resize": map[string]interface{}{"volume": map[string]int{"size": size}}}
+	_, r.Err = client.Post(actionURL(client, id), &b, nil, nil)
+	return r
 }
diff --git a/openstack/db/v1/instances/requests_test.go b/openstack/db/v1/instances/requests_test.go
index b56165a..3caac23 100644
--- a/openstack/db/v1/instances/requests_test.go
+++ b/openstack/db/v1/instances/requests_test.go
@@ -99,7 +99,7 @@
 	defer th.TeardownHTTP()
 	HandleIsRootEnabled(t)
 
-	isEnabled, err := IsRootEnabled(fake.ServiceClient(), instanceID)
+	isEnabled, err := IsRootEnabled(fake.ServiceClient(), instanceID).Extract()
 
 	th.AssertNoErr(t, err)
 	th.AssertEquals(t, true, isEnabled)
diff --git a/openstack/db/v1/instances/results.go b/openstack/db/v1/instances/results.go
index f32632c..21900d7 100644
--- a/openstack/db/v1/instances/results.go
+++ b/openstack/db/v1/instances/results.go
@@ -117,13 +117,13 @@
 	return s.Instances, err
 }
 
-// UserRootResult represents the result of an operation to enable the root user.
-type UserRootResult struct {
+// EnableRootUserResult represents the result of an operation to enable the root user.
+type EnableRootUserResult struct {
 	gophercloud.Result
 }
 
 // Extract will extract root user information from a UserRootResult.
-func (r UserRootResult) Extract() (*users.User, error) {
+func (r EnableRootUserResult) Extract() (*users.User, error) {
 	var s struct {
 		User *users.User `json:"user"`
 	}
@@ -137,3 +137,14 @@
 type ActionResult struct {
 	gophercloud.ErrResult
 }
+
+// IsRootEnabledResult is the result of a call to IsRootEnabled. To see if
+// root is enabled, call the type's Extract method.
+type IsRootEnabledResult struct {
+	gophercloud.Result
+}
+
+// Extract is used to extract the data from a IsRootEnabledResult.
+func (r IsRootEnabledResult) Extract() (bool, error) {
+	return r.Body.(map[string]interface{})["rootEnabled"] == true, r.Err
+}
diff --git a/openstack/db/v1/users/requests.go b/openstack/db/v1/users/requests.go
index 6815c1c..910a615 100644
--- a/openstack/db/v1/users/requests.go
+++ b/openstack/db/v1/users/requests.go
@@ -14,71 +14,35 @@
 // CreateOpts is the struct responsible for configuring a new user; often in the
 // context of an instance.
 type CreateOpts struct {
-	// [REQUIRED] Specifies a name for the user. Valid names can be composed
+	// Specifies a name for the user. Valid names can be composed
 	// of the following characters: letters (either case); numbers; these
 	// characters '@', '?', '#', ' ' but NEVER beginning a name string; '_' is
 	// permitted anywhere. Prohibited characters that are forbidden include:
 	// single quotes, double quotes, back quotes, semicolons, commas, backslashes,
 	// and forward slashes. Spaces at the front or end of a user name are also
 	// not permitted.
-	Name string
-
-	// [REQUIRED] Specifies a password for the user.
-	Password string
-
-	// [OPTIONAL] An array of databases that this user will connect to. The
+	Name string `json:"name" required:"true"`
+	// Specifies a password for the user.
+	Password string `json:"password" required:"true"`
+	// An array of databases that this user will connect to. The
 	// "name" field is the only requirement for each option.
-	Databases db.BatchCreateOpts
-
-	// [OPTIONAL] Specifies the host from which a user is allowed to connect to
+	Databases db.BatchCreateOpts `json:"databases,omitempty"`
+	// Specifies the host from which a user is allowed to connect to
 	// the database. Possible values are a string containing an IPv4 address or
 	// "%" to allow connecting from any host. Optional; the default is "%".
-	Host string
+	Host string `json:"host,omitempty"`
 }
 
 // ToMap is a convenience function for creating sub-maps for individual users.
 func (opts CreateOpts) ToMap() (map[string]interface{}, error) {
-
 	if opts.Name == "root" {
 		err := gophercloud.ErrInvalidInput{}
-		err.Function = "users.ToUserCreateMap"
 		err.Argument = "users.CreateOpts.Name"
 		err.Value = "root"
 		err.Info = "root is a reserved user name and cannot be used"
 		return nil, err
 	}
-	if opts.Name == "" {
-		err := gophercloud.ErrMissingInput{}
-		err.Function = "users.ToUserCreateMap"
-		err.Argument = "users.CreateOpts.Name"
-		return nil, err
-	}
-	if opts.Password == "" {
-		err := gophercloud.ErrMissingInput{}
-		err.Function = "users.ToUserCreateMap"
-		err.Argument = "users.CreateOpts.Password"
-		return nil, err
-	}
-
-	user := map[string]interface{}{
-		"name":     opts.Name,
-		"password": opts.Password,
-	}
-
-	if opts.Host != "" {
-		user["host"] = opts.Host
-	}
-
-	dbs := make([]map[string]string, len(opts.Databases))
-	for i, db := range opts.Databases {
-		dbs[i] = map[string]string{"name": db.Name}
-	}
-
-	if len(dbs) > 0 {
-		user["databases"] = dbs
-	}
-
-	return user, nil
+	return gophercloud.BuildRequestBody(opts, "")
 }
 
 // BatchCreateOpts allows multiple users to be created at once.
@@ -102,40 +66,28 @@
 // assigned for a particular user, the user will be granted all privileges
 // for those specified databases. "root" is a reserved name and cannot be used.
 func Create(client *gophercloud.ServiceClient, instanceID string, opts CreateOptsBuilder) CreateResult {
-	var res CreateResult
-
-	reqBody, err := opts.ToUserCreateMap()
+	var r CreateResult
+	b, err := opts.ToUserCreateMap()
 	if err != nil {
-		res.Err = err
-		return res
+		r.Err = err
+		return r
 	}
-
-	_, res.Err = client.Request("POST", baseURL(client, instanceID), &gophercloud.RequestOpts{
-		JSONBody: &reqBody,
-		OkCodes:  []int{202},
-	})
-
-	return res
+	_, r.Err = client.Post(baseURL(client, instanceID), &b, nil, nil)
+	return r
 }
 
 // List will list all the users associated with a specified database instance,
 // along with their associated databases. This operation will not return any
 // system users or administrators for a database.
 func List(client *gophercloud.ServiceClient, instanceID string) pagination.Pager {
-	createPageFn := func(r pagination.PageResult) pagination.Page {
+	return pagination.NewPager(client, baseURL(client, instanceID), func(r pagination.PageResult) pagination.Page {
 		return UserPage{pagination.LinkedPageBase{PageResult: r}}
-	}
-
-	return pagination.NewPager(client, baseURL(client, instanceID), createPageFn)
+	})
 }
 
 // Delete will permanently delete a user from a specified database instance.
 func Delete(client *gophercloud.ServiceClient, instanceID, userName string) DeleteResult {
-	var res DeleteResult
-
-	_, res.Err = client.Request("DELETE", userURL(client, instanceID, userName), &gophercloud.RequestOpts{
-		OkCodes: []int{202},
-	})
-
-	return res
+	var r DeleteResult
+	_, r.Err = client.Delete(userURL(client, instanceID, userName), nil)
+	return r
 }