dsl struct tags; wip
diff --git a/openstack/compute/v2/extensions/bootfromvolume/requests.go b/openstack/compute/v2/extensions/bootfromvolume/requests.go
index 7171afa..086cc0a 100644
--- a/openstack/compute/v2/extensions/bootfromvolume/requests.go
+++ b/openstack/compute/v2/extensions/bootfromvolume/requests.go
@@ -1,9 +1,6 @@
 package bootfromvolume
 
 import (
-	"fmt"
-	"strconv"
-
 	"github.com/gophercloud/gophercloud"
 	"github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
 )
@@ -12,37 +9,35 @@
 type SourceType string
 
 const (
-	Volume   SourceType = "volume"
+	// Volume SourceType
+	Volume SourceType = "volume"
+	// Snapshot SourceType
 	Snapshot SourceType = "snapshot"
-	Image    SourceType = "image"
-	Blank    SourceType = "blank"
+	// Image SourceType
+	Image SourceType = "image"
+	// Blank SourceType
+	Blank SourceType = "blank"
 )
 
 // BlockDevice is a structure with options for booting a server instance
 // from a volume. The volume may be created from an image, snapshot, or another
 // volume.
 type BlockDevice struct {
-	// BootIndex [optional] is the boot index. It defaults to 0.
+	// SourceType must be one of: "volume", "snapshot", "image".
+	SourceType SourceType `json:"source_type" required:"true"`
+	// UUID is the unique identifier for the volume, snapshot, or image (see above)
+	UUID string `json:"uuid,omitempty"`
+	// BootIndex is the boot index. It defaults to 0.
 	BootIndex int `json:"boot_index"`
-
-	// DeleteOnTermination [optional] specifies whether or not to delete the attached volume
+	// DeleteOnTermination specifies whether or not to delete the attached volume
 	// when the server is deleted. Defaults to `false`.
 	DeleteOnTermination bool `json:"delete_on_termination"`
-
-	// DestinationType [optional] is the type that gets created. Possible values are "volume"
+	// DestinationType is the type that gets created. Possible values are "volume"
 	// and "local".
-	DestinationType string `json:"destination_type"`
-
-	// GuestFormat [optional] specifies the format of the block device.
-	GuestFormat string `json:"guest_format"`
-
-	// SourceType [required] must be one of: "volume", "snapshot", "image".
-	SourceType SourceType `json:"source_type"`
-
-	// UUID [required] is the unique identifier for the volume, snapshot, or image (see above)
-	UUID string `json:"uuid"`
-
-	// VolumeSize [optional] is the size of the volume to create (in gigabytes).
+	DestinationType string `json:"destination_type,omitempty"`
+	// GuestFormat specifies the format of the block device.
+	GuestFormat string `json:"guest_format,omitempty"`
+	// VolumeSize is the size of the volume to create (in gigabytes).
 	VolumeSize int `json:"volume_size"`
 }
 
@@ -63,7 +58,6 @@
 
 	if len(opts.BlockDevice) == 0 {
 		err := gophercloud.ErrMissingInput{}
-		err.Function = "bootfromvolume.ToServerCreateMap"
 		err.Argument = "bootfromvolume.CreateOptsExt.BlockDevice"
 		return nil, err
 	}
@@ -73,29 +67,11 @@
 	blockDevice := make([]map[string]interface{}, len(opts.BlockDevice))
 
 	for i, bd := range opts.BlockDevice {
-		if string(bd.SourceType) == "" {
-			err := gophercloud.ErrMissingInput{}
-			err.Function = "bootfromvolume.ToServerCreateMap"
-			err.Argument = fmt.Sprintf("bootfromvolume.CreateOptsExt.BlockDevice[%d].SourceType", i)
+		b, err := gophercloud.BuildRequestBody(bd, "")
+		if err != nil {
 			return nil, err
 		}
-
-		blockDevice[i] = make(map[string]interface{})
-
-		blockDevice[i]["source_type"] = bd.SourceType
-		blockDevice[i]["boot_index"] = strconv.Itoa(bd.BootIndex)
-		blockDevice[i]["delete_on_termination"] = strconv.FormatBool(bd.DeleteOnTermination)
-		blockDevice[i]["volume_size"] = strconv.Itoa(bd.VolumeSize)
-		if bd.UUID != "" {
-			blockDevice[i]["uuid"] = bd.UUID
-		}
-		if bd.DestinationType != "" {
-			blockDevice[i]["destination_type"] = bd.DestinationType
-		}
-		if bd.GuestFormat != "" {
-			blockDevice[i]["guest_format"] = bd.GuestFormat
-		}
-
+		blockDevice[i] = b
 	}
 	serverMap["block_device_mapping_v2"] = blockDevice
 
@@ -104,21 +80,14 @@
 
 // Create requests the creation of a server from the given block device mapping.
 func Create(client *gophercloud.ServiceClient, opts servers.CreateOptsBuilder) servers.CreateResult {
-	var res servers.CreateResult
-
-	reqBody, err := opts.ToServerCreateMap()
+	var r servers.CreateResult
+	b, err := opts.ToServerCreateMap()
 	if err != nil {
-		res.Err = err
-		return res
+		r.Err = err
+		return r
 	}
-
-	// Delete imageName and flavorName that come from ToServerCreateMap().
-	// As of Liberty, Boot From Volume is failing if they are passed.
-	delete(reqBody["server"].(map[string]interface{}), "imageName")
-	delete(reqBody["server"].(map[string]interface{}), "flavorName")
-
-	_, res.Err = client.Post(createURL(client), reqBody, &res.Body, &gophercloud.RequestOpts{
+	_, r.Err = client.Post(createURL(client), b, &r.Body, &gophercloud.RequestOpts{
 		OkCodes: []int{200, 202},
 	})
-	return res
+	return r
 }
diff --git a/openstack/compute/v2/extensions/bootfromvolume/requests_test.go b/openstack/compute/v2/extensions/bootfromvolume/requests_test.go
index 2359a77..d85070d 100644
--- a/openstack/compute/v2/extensions/bootfromvolume/requests_test.go
+++ b/openstack/compute/v2/extensions/bootfromvolume/requests_test.go
@@ -18,10 +18,11 @@
 		CreateOptsBuilder: base,
 		BlockDevice: []BlockDevice{
 			BlockDevice{
-				UUID:            "123456",
-				SourceType:      Image,
-				DestinationType: "volume",
-				VolumeSize:      10,
+				UUID:                "123456",
+				SourceType:          Image,
+				DestinationType:     "volume",
+				VolumeSize:          10,
+				DeleteOnTermination: false,
 			},
 		},
 	}
@@ -37,9 +38,9 @@
             "uuid":"123456",
             "source_type":"image",
             "destination_type":"volume",
-            "boot_index": "0",
-            "delete_on_termination": "false",
-            "volume_size": "10"
+            "boot_index": 0,
+            "delete_on_termination": false,
+            "volume_size": 10
           }
         ]
       }
@@ -94,28 +95,28 @@
         "flavorRef": "performance1-1",
         "block_device_mapping_v2":[
           {
-            "boot_index": "0",
-            "delete_on_termination": "true",
+            "boot_index": 0,
+            "delete_on_termination": true,
             "destination_type":"local",
             "source_type":"image",
             "uuid":"123456",
-            "volume_size": "0"
+            "volume_size": 0
           },
           {
-            "boot_index": "-1",
-            "delete_on_termination": "true",
+            "boot_index": -1,
+            "delete_on_termination": true,
             "destination_type":"local",
             "guest_format":"ext4",
             "source_type":"blank",
-            "volume_size": "1"
+            "volume_size": 1
           },
           {
-            "boot_index": "-1",
-            "delete_on_termination": "true",
+            "boot_index": -1,
+            "delete_on_termination": true,
             "destination_type":"local",
             "guest_format":"ext4",
             "source_type":"blank",
-            "volume_size": "1"
+            "volume_size": 1
           }
         ]
       }
diff --git a/openstack/compute/v2/extensions/defsecrules/requests.go b/openstack/compute/v2/extensions/defsecrules/requests.go
index 5e2d686..62c112e 100644
--- a/openstack/compute/v2/extensions/defsecrules/requests.go
+++ b/openstack/compute/v2/extensions/defsecrules/requests.go
@@ -7,24 +7,19 @@
 
 // List will return a collection of default rules.
 func List(client *gophercloud.ServiceClient) pagination.Pager {
-	createPage := func(r pagination.PageResult) pagination.Page {
+	return pagination.NewPager(client, rootURL(client), func(r pagination.PageResult) pagination.Page {
 		return DefaultRulePage{pagination.SinglePageBase(r)}
-	}
-
-	return pagination.NewPager(client, rootURL(client), createPage)
+	})
 }
 
 // CreateOpts represents the configuration for adding a new default rule.
 type CreateOpts struct {
-	// Required - the lower bound of the port range that will be opened.
-	FromPort int `json:"from_port"`
-
-	// Required - the upper bound of the port range that will be opened.
-	ToPort int `json:"to_port"`
-
-	// Required - the protocol type that will be allowed, e.g. TCP.
-	IPProtocol string `json:"ip_protocol"`
-
+	// The lower bound of the port range that will be opened.
+	FromPort int `json:"from_port" required:"true"`
+	// The upper bound of the port range that will be opened.
+	ToPort int `json:"to_port" required:"true"`
+	// The protocol type that will be allowed, e.g. TCP.
+	IPProtocol string `json:"ip_protocol" required:"true"`
 	// ONLY required if FromGroupID is blank. This represents the IP range that
 	// will be the source of network traffic to your security group. Use
 	// 0.0.0.0/0 to allow all IP addresses.
@@ -38,68 +33,33 @@
 
 // ToRuleCreateMap builds the create rule options into a serializable format.
 func (opts CreateOpts) ToRuleCreateMap() (map[string]interface{}, error) {
-	if opts.FromPort == 0 {
-		err := gophercloud.ErrMissingInput{}
-		err.Function = "defsecrules.ToRuleCreateMap"
-		err.Argument = "defsecrules.CreateOpts.FromPort"
-		return nil, err
-	}
-	if opts.ToPort == 0 {
-		err := gophercloud.ErrMissingInput{}
-		err.Function = "defsecrules.ToRuleCreateMap"
-		err.Argument = "defsecrules.CreateOpts.ToPort"
-		return nil, err
-	}
-	if opts.IPProtocol == "" {
-		err := gophercloud.ErrMissingInput{}
-		err.Function = "defsecrules.ToRuleCreateMap"
-		err.Argument = "defsecrules.CreateOpts.IPProtocol"
-		return nil, err
-	}
-	if opts.CIDR == "" {
-		err := gophercloud.ErrMissingInput{}
-		err.Function = "defsecrules.ToRuleCreateMap"
-		err.Argument = "defsecrules.CreateOpts.CIDR"
-		return nil, err
-	}
-
-	rule := make(map[string]interface{})
-
-	rule["from_port"] = opts.FromPort
-	rule["to_port"] = opts.ToPort
-	rule["ip_protocol"] = opts.IPProtocol
-	rule["cidr"] = opts.CIDR
-
-	return map[string]interface{}{"security_group_default_rule": rule}, nil
+	return gophercloud.BuildRequestBody(opts, "security_group_default_rule")
 }
 
 // Create is the operation responsible for creating a new default rule.
 func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
-	var result CreateResult
-
-	reqBody, err := opts.ToRuleCreateMap()
+	var r CreateResult
+	b, err := opts.ToRuleCreateMap()
 	if err != nil {
-		result.Err = err
-		return result
+		r.Err = err
+		return r
 	}
-
-	_, result.Err = client.Post(rootURL(client), reqBody, &result.Body, &gophercloud.RequestOpts{
+	_, r.Err = client.Post(rootURL(client), b, &r.Body, &gophercloud.RequestOpts{
 		OkCodes: []int{200},
 	})
-
-	return result
+	return r
 }
 
 // Get will return details for a particular default rule.
 func Get(client *gophercloud.ServiceClient, id string) GetResult {
-	var result GetResult
-	_, result.Err = client.Get(resourceURL(client, id), &result.Body, nil)
-	return result
+	var r GetResult
+	_, r.Err = client.Get(resourceURL(client, id), &r.Body, nil)
+	return r
 }
 
 // Delete will permanently delete a default rule from the project.
 func Delete(client *gophercloud.ServiceClient, id string) gophercloud.ErrResult {
-	var result gophercloud.ErrResult
-	_, result.Err = client.Delete(resourceURL(client, id), nil)
-	return result
+	var r gophercloud.ErrResult
+	_, r.Err = client.Delete(resourceURL(client, id), nil)
+	return r
 }
diff --git a/openstack/compute/v2/extensions/diskconfig/requests.go b/openstack/compute/v2/extensions/diskconfig/requests.go
index 19798d7..41d04b9 100644
--- a/openstack/compute/v2/extensions/diskconfig/requests.go
+++ b/openstack/compute/v2/extensions/diskconfig/requests.go
@@ -50,16 +50,14 @@
 // RebuildOptsExt adds a DiskConfig option to the base RebuildOpts.
 type RebuildOptsExt struct {
 	servers.RebuildOptsBuilder
-
-	// DiskConfig [optional] controls how the rebuilt server's disk is partitioned.
-	DiskConfig DiskConfig
+	// DiskConfig controls how the rebuilt server's disk is partitioned.
+	DiskConfig DiskConfig `json:"OS-DCF:diskConfig,omitempty"`
 }
 
 // ToServerRebuildMap adds the diskconfig option to the base server rebuild options.
 func (opts RebuildOptsExt) ToServerRebuildMap() (map[string]interface{}, error) {
 	if opts.DiskConfig != Auto && opts.DiskConfig != Manual {
 		err := gophercloud.ErrInvalidInput{}
-		err.Function = "diskconfig.ToServerRebuildMap"
 		err.Argument = "diskconfig.RebuildOptsExt.DiskConfig"
 		err.Info = "Must be either diskconfig.Auto or diskconfig.Manual"
 		return nil, err
@@ -88,7 +86,6 @@
 func (opts ResizeOptsExt) ToServerResizeMap() (map[string]interface{}, error) {
 	if opts.DiskConfig != Auto && opts.DiskConfig != Manual {
 		err := gophercloud.ErrInvalidInput{}
-		err.Function = "diskconfig.ToServerResizeMap"
 		err.Argument = "diskconfig.ResizeOptsExt.DiskConfig"
 		err.Info = "Must be either diskconfig.Auto or diskconfig.Manual"
 		return nil, err
diff --git a/openstack/compute/v2/extensions/floatingips/requests.go b/openstack/compute/v2/extensions/floatingips/requests.go
index 00b2520..8137d76 100644
--- a/openstack/compute/v2/extensions/floatingips/requests.go
+++ b/openstack/compute/v2/extensions/floatingips/requests.go
@@ -21,158 +21,97 @@
 // CreateOpts specifies a Floating IP allocation request
 type CreateOpts struct {
 	// Pool is the pool of floating IPs to allocate one from
-	Pool string
-}
-
-// AssociateOpts specifies the required information to associate or disassociate a floating IP to an instance
-type AssociateOpts struct {
-	// ServerID is the UUID of the server
-	ServerID string
-
-	// FixedIP is an optional fixed IP address of the server
-	FixedIP string
-
-	// FloatingIP is the floating IP to associate with an instance
-	FloatingIP string
+	Pool string `json:"pool" required:"true"`
 }
 
 // ToFloatingIPCreateMap constructs a request body from CreateOpts.
 func (opts CreateOpts) ToFloatingIPCreateMap() (map[string]interface{}, error) {
-	if opts.Pool == "" {
-		err := gophercloud.ErrMissingInput{}
-		err.Function = "floatingips.ToFloatingIPCreateMap"
-		err.Argument = "floatingips.CreateOpts.Pool"
-		return nil, err
-	}
-
-	return map[string]interface{}{"pool": opts.Pool}, nil
-}
-
-// ToAssociateMap constructs a request body from AssociateOpts.
-func (opts AssociateOpts) ToAssociateMap() (map[string]interface{}, error) {
-	if opts.ServerID == "" {
-		err := gophercloud.ErrMissingInput{}
-		err.Function = "floatingips.ToAssociateMap"
-		err.Argument = "floatingips.AssociateOpts.ServerID"
-		return nil, err
-	}
-
-	if opts.FloatingIP == "" {
-		err := gophercloud.ErrMissingInput{}
-		err.Function = "floatingips.ToAssociateMap"
-		err.Argument = "floatingips.AssociateOpts.FloatingIP"
-		return nil, err
-	}
-
-	associateInfo := map[string]interface{}{
-		"serverId":   opts.ServerID,
-		"floatingIp": opts.FloatingIP,
-		"fixedIp":    opts.FixedIP,
-	}
-
-	return associateInfo, nil
-
+	return gophercloud.BuildRequestBody(opts, "")
 }
 
 // Create requests the creation of a new floating IP
 func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
-	var res CreateResult
-
-	reqBody, err := opts.ToFloatingIPCreateMap()
+	var r CreateResult
+	b, err := opts.ToFloatingIPCreateMap()
 	if err != nil {
-		res.Err = err
-		return res
+		r.Err = err
+		return r
 	}
-
-	_, res.Err = client.Post(createURL(client), reqBody, &res.Body, &gophercloud.RequestOpts{
+	_, r.Err = client.Post(createURL(client), b, &r.Body, &gophercloud.RequestOpts{
 		OkCodes: []int{200},
 	})
-	return res
+	return r
 }
 
 // Get returns data about a previously created FloatingIP.
 func Get(client *gophercloud.ServiceClient, id string) GetResult {
-	var res GetResult
-	_, res.Err = client.Get(getURL(client, id), &res.Body, nil)
-	return res
+	var r GetResult
+	_, r.Err = client.Get(getURL(client, id), &r.Body, nil)
+	return r
 }
 
 // Delete requests the deletion of a previous allocated FloatingIP.
 func Delete(client *gophercloud.ServiceClient, id string) DeleteResult {
-	var res DeleteResult
-	_, res.Err = client.Delete(deleteURL(client, id), nil)
-	return res
+	var r DeleteResult
+	_, r.Err = client.Delete(deleteURL(client, id), nil)
+	return r
 }
 
-// association / disassociation
+// AssociateOptsBuilder is the interface types must satfisfy to be used as
+// Associate options
+type AssociateOptsBuilder interface {
+	ToFloatingIPAssociateMap() (map[string]interface{}, error)
+}
 
-// Associate pairs an allocated floating IP with an instance
-// Deprecated. Use AssociateInstance.
-func Associate(client *gophercloud.ServiceClient, serverId, fip string) AssociateResult {
-	var res AssociateResult
+// AssociateOpts specifies the required information to associate a floating IP with an instance
+type AssociateOpts struct {
+	// FloatingIP is the floating IP to associate with an instance
+	FloatingIP string `json:"address" required:"true"`
+	// FixedIP is an optional fixed IP address of the server
+	FixedIP string `json:"fixed_address,omitempty"`
+}
 
-	addFloatingIp := make(map[string]interface{})
-	addFloatingIp["address"] = fip
-	reqBody := map[string]interface{}{"addFloatingIp": addFloatingIp}
-
-	_, res.Err = client.Post(associateURL(client, serverId), reqBody, nil, nil)
-	return res
+// ToFloatingIPAssociateMap constructs a request body from AssociateOpts.
+func (opts AssociateOpts) ToFloatingIPAssociateMap() (map[string]interface{}, error) {
+	return gophercloud.BuildRequestBody(opts, "addFloatingIp")
 }
 
 // AssociateInstance pairs an allocated floating IP with an instance.
-func AssociateInstance(client *gophercloud.ServiceClient, opts AssociateOpts) AssociateResult {
-	var res AssociateResult
-
-	associateInfo, err := opts.ToAssociateMap()
+func AssociateInstance(client *gophercloud.ServiceClient, serverID string, opts AssociateOptsBuilder) AssociateResult {
+	var r AssociateResult
+	b, err := opts.ToFloatingIPAssociateMap()
 	if err != nil {
-		res.Err = err
-		return res
+		r.Err = err
+		return r
 	}
-
-	addFloatingIp := make(map[string]interface{})
-	addFloatingIp["address"] = associateInfo["floatingIp"].(string)
-
-	// fixedIp is not required
-	if associateInfo["fixedIp"] != "" {
-		addFloatingIp["fixed_address"] = associateInfo["fixedIp"].(string)
-	}
-
-	serverId := associateInfo["serverId"].(string)
-
-	reqBody := map[string]interface{}{"addFloatingIp": addFloatingIp}
-	_, res.Err = client.Post(associateURL(client, serverId), reqBody, nil, nil)
-	return res
+	_, r.Err = client.Post(associateURL(client, serverID), b, nil, nil)
+	return r
 }
 
-// Disassociate decouples an allocated floating IP from an instance
-// Deprecated. Use DisassociateInstance.
-func Disassociate(client *gophercloud.ServiceClient, serverId, fip string) DisassociateResult {
-	var res DisassociateResult
+// DisassociateOptsBuilder is the interface types must satfisfy to be used as
+// Disassociate options
+type DisassociateOptsBuilder interface {
+	ToFloatingIPDisassociateMap() (map[string]interface{}, error)
+}
 
-	removeFloatingIp := make(map[string]interface{})
-	removeFloatingIp["address"] = fip
-	reqBody := map[string]interface{}{"removeFloatingIp": removeFloatingIp}
+// DisassociateOpts specifies the required information to disassociate a floating IP with an instance
+type DisassociateOpts struct {
+	FloatingIP string `json:"address" required:"true"`
+}
 
-	_, res.Err = client.Post(disassociateURL(client, serverId), reqBody, nil, nil)
-	return res
+// ToFloatingIPDisassociateMap constructs a request body from AssociateOpts.
+func (opts DisassociateOpts) ToFloatingIPDisassociateMap() (map[string]interface{}, error) {
+	return gophercloud.BuildRequestBody(opts, "removeFloatingIp")
 }
 
 // DisassociateInstance decouples an allocated floating IP from an instance
-func DisassociateInstance(client *gophercloud.ServiceClient, opts AssociateOpts) DisassociateResult {
-	var res DisassociateResult
-
-	associateInfo, err := opts.ToAssociateMap()
+func DisassociateInstance(client *gophercloud.ServiceClient, serverID string, opts DisassociateOptsBuilder) DisassociateResult {
+	var r DisassociateResult
+	b, err := opts.ToFloatingIPDisassociateMap()
 	if err != nil {
-		res.Err = err
-		return res
+		r.Err = err
+		return r
 	}
-
-	removeFloatingIp := make(map[string]interface{})
-	removeFloatingIp["address"] = associateInfo["floatingIp"].(string)
-	reqBody := map[string]interface{}{"removeFloatingIp": removeFloatingIp}
-
-	serverId := associateInfo["serverId"].(string)
-
-	_, res.Err = client.Post(disassociateURL(client, serverId), reqBody, nil, nil)
-	return res
+	_, r.Err = client.Post(disassociateURL(client, serverID), b, nil, nil)
+	return r
 }
diff --git a/openstack/compute/v2/extensions/floatingips/requests_test.go b/openstack/compute/v2/extensions/floatingips/requests_test.go
index 705c92f..f0e9560 100644
--- a/openstack/compute/v2/extensions/floatingips/requests_test.go
+++ b/openstack/compute/v2/extensions/floatingips/requests_test.go
@@ -57,28 +57,16 @@
 	th.AssertNoErr(t, err)
 }
 
-func TestAssociateDeprecated(t *testing.T) {
-	th.SetupHTTP()
-	defer th.TeardownHTTP()
-	HandleAssociateSuccessfully(t)
-	serverId := "4d8c3732-a248-40ed-bebc-539a6ffd25c0"
-	fip := "10.10.10.2"
-
-	err := Associate(client.ServiceClient(), serverId, fip).ExtractErr()
-	th.AssertNoErr(t, err)
-}
-
 func TestAssociate(t *testing.T) {
 	th.SetupHTTP()
 	defer th.TeardownHTTP()
 	HandleAssociateSuccessfully(t)
 
 	associateOpts := AssociateOpts{
-		ServerID:   "4d8c3732-a248-40ed-bebc-539a6ffd25c0",
 		FloatingIP: "10.10.10.2",
 	}
 
-	err := AssociateInstance(client.ServiceClient(), associateOpts).ExtractErr()
+	err := AssociateInstance(client.ServiceClient(), "4d8c3732-a248-40ed-bebc-539a6ffd25c0", associateOpts).ExtractErr()
 	th.AssertNoErr(t, err)
 }
 
@@ -88,23 +76,11 @@
 	HandleAssociateFixedSuccessfully(t)
 
 	associateOpts := AssociateOpts{
-		ServerID:   "4d8c3732-a248-40ed-bebc-539a6ffd25c0",
 		FloatingIP: "10.10.10.2",
 		FixedIP:    "166.78.185.201",
 	}
 
-	err := AssociateInstance(client.ServiceClient(), associateOpts).ExtractErr()
-	th.AssertNoErr(t, err)
-}
-
-func TestDisassociateDeprecated(t *testing.T) {
-	th.SetupHTTP()
-	defer th.TeardownHTTP()
-	HandleDisassociateSuccessfully(t)
-	serverId := "4d8c3732-a248-40ed-bebc-539a6ffd25c0"
-	fip := "10.10.10.2"
-
-	err := Disassociate(client.ServiceClient(), serverId, fip).ExtractErr()
+	err := AssociateInstance(client.ServiceClient(), "4d8c3732-a248-40ed-bebc-539a6ffd25c0", associateOpts).ExtractErr()
 	th.AssertNoErr(t, err)
 }
 
@@ -113,11 +89,10 @@
 	defer th.TeardownHTTP()
 	HandleDisassociateSuccessfully(t)
 
-	associateOpts := AssociateOpts{
-		ServerID:   "4d8c3732-a248-40ed-bebc-539a6ffd25c0",
+	disassociateOpts := DisassociateOpts{
 		FloatingIP: "10.10.10.2",
 	}
 
-	err := DisassociateInstance(client.ServiceClient(), associateOpts).ExtractErr()
+	err := DisassociateInstance(client.ServiceClient(), "4d8c3732-a248-40ed-bebc-539a6ffd25c0", disassociateOpts).ExtractErr()
 	th.AssertNoErr(t, err)
 }
diff --git a/openstack/compute/v2/extensions/keypairs/requests.go b/openstack/compute/v2/extensions/keypairs/requests.go
index b9b32ee..2a01084 100644
--- a/openstack/compute/v2/extensions/keypairs/requests.go
+++ b/openstack/compute/v2/extensions/keypairs/requests.go
@@ -45,59 +45,43 @@
 
 // CreateOpts specifies keypair creation or import parameters.
 type CreateOpts struct {
-	// Name [required] is a friendly name to refer to this KeyPair in other services.
-	Name string
-
+	// Name is a friendly name to refer to this KeyPair in other services.
+	Name string `json:"name" required:"true"`
 	// PublicKey [optional] is a pregenerated OpenSSH-formatted public key. If provided, this key
 	// will be imported and no new key will be created.
-	PublicKey string
+	PublicKey string `json:"public_key,omitempty"`
 }
 
 // ToKeyPairCreateMap constructs a request body from CreateOpts.
 func (opts CreateOpts) ToKeyPairCreateMap() (map[string]interface{}, error) {
-	if opts.Name == "" {
-		err := gophercloud.ErrMissingInput{}
-		err.Function = "keypairs.ToKeyPairCreateMap"
-		err.Argument = "keypairs.CreateOpts.Name"
-		return nil, err
-	}
-
-	keypair := make(map[string]interface{})
-	keypair["name"] = opts.Name
-	if opts.PublicKey != "" {
-		keypair["public_key"] = opts.PublicKey
-	}
-
-	return map[string]interface{}{"keypair": keypair}, nil
+	return gophercloud.BuildRequestBody(opts, "keypair")
 }
 
 // Create requests the creation of a new keypair on the server, or to import a pre-existing
 // keypair.
 func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
-	var res CreateResult
-
-	reqBody, err := opts.ToKeyPairCreateMap()
+	var r CreateResult
+	b, err := opts.ToKeyPairCreateMap()
 	if err != nil {
-		res.Err = err
-		return res
+		r.Err = err
+		return r
 	}
-
-	_, res.Err = client.Post(createURL(client), reqBody, &res.Body, &gophercloud.RequestOpts{
+	_, r.Err = client.Post(createURL(client), b, &r.Body, &gophercloud.RequestOpts{
 		OkCodes: []int{200},
 	})
-	return res
+	return r
 }
 
 // Get returns public data about a previously uploaded KeyPair.
 func Get(client *gophercloud.ServiceClient, name string) GetResult {
-	var res GetResult
-	_, res.Err = client.Get(getURL(client, name), &res.Body, nil)
-	return res
+	var r GetResult
+	_, r.Err = client.Get(getURL(client, name), &r.Body, nil)
+	return r
 }
 
 // Delete requests the deletion of a previous stored KeyPair from the server.
 func Delete(client *gophercloud.ServiceClient, name string) DeleteResult {
-	var res DeleteResult
-	_, res.Err = client.Delete(deleteURL(client, name), nil)
-	return res
+	var r DeleteResult
+	_, r.Err = client.Delete(deleteURL(client, name), nil)
+	return r
 }
diff --git a/openstack/compute/v2/extensions/networks/requests.go b/openstack/compute/v2/extensions/networks/requests.go
index a505733..6f0f182 100644
--- a/openstack/compute/v2/extensions/networks/requests.go
+++ b/openstack/compute/v2/extensions/networks/requests.go
@@ -7,16 +7,14 @@
 
 // List returns a Pager that allows you to iterate over a collection of Network.
 func List(client *gophercloud.ServiceClient) pagination.Pager {
-	url := listURL(client)
-	createPage := func(r pagination.PageResult) pagination.Page {
+	return pagination.NewPager(client, listURL(client), func(r pagination.PageResult) pagination.Page {
 		return NetworkPage{pagination.SinglePageBase(r)}
-	}
-	return pagination.NewPager(client, url, createPage)
+	})
 }
 
 // Get returns data about a previously created Network.
 func Get(client *gophercloud.ServiceClient, id string) GetResult {
-	var res GetResult
-	_, res.Err = client.Get(getURL(client, id), &res.Body, nil)
-	return res
+	var r GetResult
+	_, r.Err = client.Get(getURL(client, id), &r.Body, nil)
+	return r
 }
diff --git a/openstack/compute/v2/extensions/schedulerhints/requests.go b/openstack/compute/v2/extensions/schedulerhints/requests.go
index 5713e72..1e06b46 100644
--- a/openstack/compute/v2/extensions/schedulerhints/requests.go
+++ b/openstack/compute/v2/extensions/schedulerhints/requests.go
@@ -14,33 +14,28 @@
 type SchedulerHints struct {
 	// Group specifies a Server Group to place the instance in.
 	Group string
-
 	// DifferentHost will place the instance on a compute node that does not
 	// host the given instances.
 	DifferentHost []string
-
 	// SameHost will place the instance on a compute node that hosts the given
 	// instances.
 	SameHost []string
-
 	// Query is a conditional statement that results in compute nodes able to
 	// host the instance.
 	Query []interface{}
-
 	// TargetCell specifies a cell name where the instance will be placed.
-	TargetCell string
-
+	TargetCell string `json:"target_cell,omitempty"`
 	// BuildNearHostIP specifies a subnet of compute nodes to host the instance.
 	BuildNearHostIP string
 }
 
-// SchedulerHintsBuilder builds the scheduler hints into a serializable format.
-type SchedulerHintsBuilder interface {
-	ToServerSchedulerHintsMap() (map[string]interface{}, error)
+// CreateOptsBuilder builds the scheduler hints into a serializable format.
+type CreateOptsBuilder interface {
+	ToServerSchedulerHintsCreateMap() (map[string]interface{}, error)
 }
 
 // ToServerSchedulerHintsMap builds the scheduler hints into a serializable format.
-func (opts SchedulerHints) ToServerSchedulerHintsMap() (map[string]interface{}, error) {
+func (opts SchedulerHints) ToServerSchedulerHintsCreateMap() (map[string]interface{}, error) {
 	sh := make(map[string]interface{})
 
 	uuidRegex, _ := regexp.Compile("^[a-z0-9]{8}-[a-z0-9]{4}-[1-5][a-z0-9]{3}-[a-z0-9]{4}-[a-z0-9]{12}$")
@@ -48,7 +43,6 @@
 	if opts.Group != "" {
 		if !uuidRegex.MatchString(opts.Group) {
 			err := gophercloud.ErrInvalidInput{}
-			err.Function = "schedulerhints.ToServerSchedulerHintsMap"
 			err.Argument = "schedulerhints.SchedulerHints.Group"
 			err.Value = opts.Group
 			err.Info = "Group must be a UUID"
@@ -61,7 +55,6 @@
 		for _, diffHost := range opts.DifferentHost {
 			if !uuidRegex.MatchString(diffHost) {
 				err := gophercloud.ErrInvalidInput{}
-				err.Function = "schedulerhints.ToServerSchedulerHintsMap"
 				err.Argument = "schedulerhints.SchedulerHints.DifferentHost"
 				err.Value = opts.DifferentHost
 				err.Info = "The hosts must be in UUID format."
@@ -75,7 +68,6 @@
 		for _, sameHost := range opts.SameHost {
 			if !uuidRegex.MatchString(sameHost) {
 				err := gophercloud.ErrInvalidInput{}
-				err.Function = "schedulerhints.ToServerSchedulerHintsMap"
 				err.Argument = "schedulerhints.SchedulerHints.SameHost"
 				err.Value = opts.SameHost
 				err.Info = "The hosts must be in UUID format."
@@ -99,7 +91,6 @@
 	if len(opts.Query) > 0 {
 		if len(opts.Query) < 3 {
 			err := gophercloud.ErrInvalidInput{}
-			err.Function = "schedulerhints.ToServerSchedulerHintsMap"
 			err.Argument = "schedulerhints.SchedulerHints.Query"
 			err.Value = opts.Query
 			err.Info = "Must be a conditional statement in the format of [op,variable,value]"
@@ -115,7 +106,6 @@
 	if opts.BuildNearHostIP != "" {
 		if _, _, err := net.ParseCIDR(opts.BuildNearHostIP); err != nil {
 			err := gophercloud.ErrInvalidInput{}
-			err.Function = "schedulerhints.ToServerSchedulerHintsMap"
 			err.Argument = "schedulerhints.SchedulerHints.BuildNearHostIP"
 			err.Value = opts.BuildNearHostIP
 			err.Info = "Must be a valid subnet in the form 192.168.1.1/24"
@@ -132,9 +122,8 @@
 // CreateOptsExt adds a SchedulerHints option to the base CreateOpts.
 type CreateOptsExt struct {
 	servers.CreateOptsBuilder
-
 	// SchedulerHints provides a set of hints to the scheduler.
-	SchedulerHints SchedulerHintsBuilder
+	SchedulerHints CreateOptsBuilder
 }
 
 // ToServerCreateMap adds the SchedulerHints option to the base server creation options.
@@ -144,7 +133,7 @@
 		return nil, err
 	}
 
-	schedulerHints, err := opts.SchedulerHints.ToServerSchedulerHintsMap()
+	schedulerHints, err := opts.SchedulerHints.ToServerSchedulerHintsCreateMap()
 	if err != nil {
 		return nil, err
 	}
diff --git a/openstack/compute/v2/extensions/secgroups/requests.go b/openstack/compute/v2/extensions/secgroups/requests.go
index a0bb025..48ff698 100644
--- a/openstack/compute/v2/extensions/secgroups/requests.go
+++ b/openstack/compute/v2/extensions/secgroups/requests.go
@@ -6,11 +6,9 @@
 )
 
 func commonList(client *gophercloud.ServiceClient, url string) pagination.Pager {
-	createPage := func(r pagination.PageResult) pagination.Page {
+	return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page {
 		return SecurityGroupPage{pagination.SinglePageBase(r)}
-	}
-
-	return pagination.NewPager(client, url, createPage)
+	})
 }
 
 // List will return a collection of all the security groups for a particular
@@ -29,11 +27,10 @@
 // security groups. It therefore represents the mutable attributes of a
 // security group.
 type GroupOpts struct {
-	// Required - the name of your security group.
-	Name string `json:"name"`
-
-	// Required - the description of your security group.
-	Description string `json:"description"`
+	// the name of your security group.
+	Name string `json:"name" required:"true"`
+	// the description of your security group.
+	Description string `json:"description" required:"true"`
 }
 
 // CreateOpts is the struct responsible for creating a security group.
@@ -46,42 +43,21 @@
 
 // ToSecGroupCreateMap builds the create options into a serializable format.
 func (opts CreateOpts) ToSecGroupCreateMap() (map[string]interface{}, error) {
-	sg := make(map[string]interface{})
-
-	if opts.Name == "" {
-		err := gophercloud.ErrMissingInput{}
-		err.Function = "secgroups.ToSecGroupCreateMap"
-		err.Argument = "secgroups.CreateOpts.Name"
-		return nil, err
-	}
-	if opts.Description == "" {
-		err := gophercloud.ErrMissingInput{}
-		err.Function = "secgroups.ToSecGroupCreateMap"
-		err.Argument = "secgroups.CreateOpts.Description"
-		return nil, err
-	}
-
-	sg["name"] = opts.Name
-	sg["description"] = opts.Description
-
-	return map[string]interface{}{"security_group": sg}, nil
+	return gophercloud.BuildRequestBody(opts, "security_group")
 }
 
 // Create will create a new security group.
 func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
-	var result CreateResult
-
-	reqBody, err := opts.ToSecGroupCreateMap()
+	var r CreateResult
+	b, err := opts.ToSecGroupCreateMap()
 	if err != nil {
-		result.Err = err
-		return result
+		r.Err = err
+		return r
 	}
-
-	_, result.Err = client.Post(rootURL(client), reqBody, &result.Body, &gophercloud.RequestOpts{
+	_, r.Err = client.Post(rootURL(client), b, &r.Body, &gophercloud.RequestOpts{
 		OkCodes: []int{200},
 	})
-
-	return result
+	return r
 }
 
 // UpdateOpts is the struct responsible for updating an existing security group.
@@ -94,79 +70,53 @@
 
 // ToSecGroupUpdateMap builds the update options into a serializable format.
 func (opts UpdateOpts) ToSecGroupUpdateMap() (map[string]interface{}, error) {
-	sg := make(map[string]interface{})
-
-	if opts.Name == "" {
-		err := gophercloud.ErrMissingInput{}
-		err.Function = "secgroups.ToSecGroupUpdateMap"
-		err.Argument = "secgroups.UpdateOpts.Name"
-		return nil, err
-	}
-	if opts.Description == "" {
-		err := gophercloud.ErrMissingInput{}
-		err.Function = "secgroups.ToSecGroupUpdateMap"
-		err.Argument = "secgroups.UpdateOpts.Description"
-		return nil, err
-	}
-
-	sg["name"] = opts.Name
-	sg["description"] = opts.Description
-
-	return map[string]interface{}{"security_group": sg}, nil
+	return gophercloud.BuildRequestBody(opts, "security_group")
 }
 
 // Update will modify the mutable properties of a security group, notably its
 // name and description.
 func Update(client *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) UpdateResult {
-	var result UpdateResult
-
-	reqBody, err := opts.ToSecGroupUpdateMap()
+	var r UpdateResult
+	b, err := opts.ToSecGroupUpdateMap()
 	if err != nil {
-		result.Err = err
-		return result
+		r.Err = err
+		return r
 	}
-
-	_, result.Err = client.Put(resourceURL(client, id), reqBody, &result.Body, &gophercloud.RequestOpts{
+	_, r.Err = client.Put(resourceURL(client, id), b, &r.Body, &gophercloud.RequestOpts{
 		OkCodes: []int{200},
 	})
-
-	return result
+	return r
 }
 
 // Get will return details for a particular security group.
 func Get(client *gophercloud.ServiceClient, id string) GetResult {
-	var result GetResult
-	_, result.Err = client.Get(resourceURL(client, id), &result.Body, nil)
-	return result
+	var r GetResult
+	_, r.Err = client.Get(resourceURL(client, id), &r.Body, nil)
+	return r
 }
 
 // Delete will permanently delete a security group from the project.
 func Delete(client *gophercloud.ServiceClient, id string) gophercloud.ErrResult {
-	var result gophercloud.ErrResult
-	_, result.Err = client.Delete(resourceURL(client, id), nil)
-	return result
+	var r gophercloud.ErrResult
+	_, r.Err = client.Delete(resourceURL(client, id), nil)
+	return r
 }
 
 // CreateRuleOpts represents the configuration for adding a new rule to an
 // existing security group.
 type CreateRuleOpts struct {
 	// Required - the ID of the group that this rule will be added to.
-	ParentGroupID string `json:"parent_group_id"`
-
+	ParentGroupID string `json:"parent_group_id" required:"true"`
 	// Required - the lower bound of the port range that will be opened.
-	FromPort int `json:"from_port"`
-
+	FromPort int `json:"from_port" required:"true"`
 	// Required - the upper bound of the port range that will be opened.
-	ToPort int `json:"to_port"`
-
+	ToPort int `json:"to_port" required:"true"`
 	// Required - the protocol type that will be allowed, e.g. TCP.
-	IPProtocol string `json:"ip_protocol"`
-
+	IPProtocol string `json:"ip_protocol" required:"true"`
 	// ONLY required if FromGroupID is blank. This represents the IP range that
 	// will be the source of network traffic to your security group. Use
 	// 0.0.0.0/0 to allow all IP addresses.
 	CIDR string `json:"cidr,omitempty"`
-
 	// ONLY required if CIDR is blank. This value represents the ID of a group
 	// that forwards traffic to the parent group. So, instead of accepting
 	// network traffic from an entire IP range, you can instead refine the
@@ -181,78 +131,30 @@
 
 // ToRuleCreateMap builds the create rule options into a serializable format.
 func (opts CreateRuleOpts) ToRuleCreateMap() (map[string]interface{}, error) {
-	if opts.ParentGroupID == "" {
-		err := gophercloud.ErrMissingInput{}
-		err.Function = "secgroups.ToRuleCreateMap"
-		err.Argument = "secgroups.CreateRuleOpts.ParentGroupID"
-		return nil, err
-	}
-	if opts.FromPort == 0 {
-		err := gophercloud.ErrMissingInput{}
-		err.Function = "secgroups.ToRuleCreateMap"
-		err.Argument = "secgroups.CreateRuleOpts.FromPort"
-		return nil, err
-	}
-	if opts.ToPort == 0 {
-		err := gophercloud.ErrMissingInput{}
-		err.Function = "secgroups.ToRuleCreateMap"
-		err.Argument = "secgroups.CreateRuleOpts.ToPort"
-		return nil, err
-	}
-	if opts.IPProtocol == "" {
-		err := gophercloud.ErrMissingInput{}
-		err.Function = "secgroups.ToRuleCreateMap"
-		err.Argument = "secgroups.CreateRuleOpts.IPProtocol"
-		return nil, err
-	}
-	if opts.CIDR == "" && opts.FromGroupID == "" {
-		err := gophercloud.ErrMissingInput{}
-		err.Function = "secgroups.ToRuleCreateMap"
-		err.Argument = "secgroups.CreateRuleOpts.CIDR/secgroups.CreateRuleOpts.FromGroupID"
-		return nil, err
-	}
-
-	rule := make(map[string]interface{})
-
-	rule["parent_group_id"] = opts.ParentGroupID
-	rule["from_port"] = opts.FromPort
-	rule["to_port"] = opts.ToPort
-	rule["ip_protocol"] = opts.IPProtocol
-
-	if opts.CIDR != "" {
-		rule["cidr"] = opts.CIDR
-	}
-	if opts.FromGroupID != "" {
-		rule["group_id"] = opts.FromGroupID
-	}
-
-	return map[string]interface{}{"security_group_rule": rule}, nil
+	return gophercloud.BuildRequestBody(opts, "security_group_rule")
 }
 
 // CreateRule will add a new rule to an existing security group (whose ID is
 // specified in CreateRuleOpts). You have the option of controlling inbound
 // traffic from either an IP range (CIDR) or from another security group.
 func CreateRule(client *gophercloud.ServiceClient, opts CreateRuleOptsBuilder) CreateRuleResult {
-	var result CreateRuleResult
-
-	reqBody, err := opts.ToRuleCreateMap()
+	var r CreateRuleResult
+	b, err := opts.ToRuleCreateMap()
 	if err != nil {
-		result.Err = err
-		return result
+		r.Err = err
+		return r
 	}
-
-	_, result.Err = client.Post(rootRuleURL(client), reqBody, &result.Body, &gophercloud.RequestOpts{
+	_, r.Err = client.Post(rootRuleURL(client), b, &r.Body, &gophercloud.RequestOpts{
 		OkCodes: []int{200},
 	})
-
-	return result
+	return r
 }
 
 // DeleteRule will permanently delete a rule from a security group.
 func DeleteRule(client *gophercloud.ServiceClient, id string) gophercloud.ErrResult {
-	var result gophercloud.ErrResult
-	_, result.Err = client.Delete(resourceRuleURL(client, id), nil)
-	return result
+	var r gophercloud.ErrResult
+	_, r.Err = client.Delete(resourceRuleURL(client, id), nil)
+	return r
 }
 
 func actionMap(prefix, groupName string) map[string]map[string]string {
@@ -261,17 +163,17 @@
 	}
 }
 
-// AddServerToGroup will associate a server and a security group, enforcing the
+// AddServer will associate a server and a security group, enforcing the
 // rules of the group on the server.
-func AddServerToGroup(client *gophercloud.ServiceClient, serverID, groupName string) gophercloud.ErrResult {
-	var result gophercloud.ErrResult
-	_, result.Err = client.Post(serverActionURL(client, serverID), actionMap("add", groupName), &result.Body, nil)
-	return result
+func AddServer(client *gophercloud.ServiceClient, serverID, groupName string) gophercloud.ErrResult {
+	var r gophercloud.ErrResult
+	_, r.Err = client.Post(serverActionURL(client, serverID), actionMap("add", groupName), &r.Body, nil)
+	return r
 }
 
-// RemoveServerFromGroup will disassociate a server from a security group.
-func RemoveServerFromGroup(client *gophercloud.ServiceClient, serverID, groupName string) gophercloud.ErrResult {
-	var result gophercloud.ErrResult
-	_, result.Err = client.Post(serverActionURL(client, serverID), actionMap("remove", groupName), &result.Body, nil)
-	return result
+// RemoveServer will disassociate a server from a security group.
+func RemoveServer(client *gophercloud.ServiceClient, serverID, groupName string) gophercloud.ErrResult {
+	var r gophercloud.ErrResult
+	_, r.Err = client.Post(serverActionURL(client, serverID), actionMap("remove", groupName), &r.Body, nil)
+	return r
 }
diff --git a/openstack/compute/v2/extensions/secgroups/requests_test.go b/openstack/compute/v2/extensions/secgroups/requests_test.go
index 59a3898..9496d4a 100644
--- a/openstack/compute/v2/extensions/secgroups/requests_test.go
+++ b/openstack/compute/v2/extensions/secgroups/requests_test.go
@@ -233,7 +233,7 @@
 
 	mockAddServerToGroupResponse(t, serverID)
 
-	err := AddServerToGroup(client.ServiceClient(), serverID, "test").ExtractErr()
+	err := AddServer(client.ServiceClient(), serverID, "test").ExtractErr()
 	th.AssertNoErr(t, err)
 }
 
@@ -243,6 +243,6 @@
 
 	mockRemoveServerFromGroupResponse(t, serverID)
 
-	err := RemoveServerFromGroup(client.ServiceClient(), serverID, "test").ExtractErr()
+	err := RemoveServer(client.ServiceClient(), serverID, "test").ExtractErr()
 	th.AssertNoErr(t, err)
 }
diff --git a/openstack/compute/v2/extensions/servergroups/requests.go b/openstack/compute/v2/extensions/servergroups/requests.go
index 212edac..1348cfa 100644
--- a/openstack/compute/v2/extensions/servergroups/requests.go
+++ b/openstack/compute/v2/extensions/servergroups/requests.go
@@ -21,61 +21,40 @@
 // CreateOpts specifies a Server Group allocation request
 type CreateOpts struct {
 	// Name is the name of the server group
-	Name string
-
+	Name string `json:"name" required:"true"`
 	// Policies are the server group policies
-	Policies []string
+	Policies []string `json:"policies" required:"true"`
 }
 
 // ToServerGroupCreateMap constructs a request body from CreateOpts.
 func (opts CreateOpts) ToServerGroupCreateMap() (map[string]interface{}, error) {
-	if opts.Name == "" {
-		err := gophercloud.ErrMissingInput{}
-		err.Function = "servergroups.ToServerGroupCreateMap"
-		err.Argument = "servergroups.CreateOpts.Name"
-		return nil, err
-	}
-
-	if len(opts.Policies) < 1 {
-		err := gophercloud.ErrMissingInput{}
-		err.Function = "servergroups.ToServerGroupCreateMap"
-		err.Argument = "servergroups.CreateOpts.Policies"
-		return nil, err
-	}
-
-	serverGroup := make(map[string]interface{})
-	serverGroup["name"] = opts.Name
-	serverGroup["policies"] = opts.Policies
-
-	return map[string]interface{}{"server_group": serverGroup}, nil
+	return gophercloud.BuildRequestBody(opts, "server_group")
 }
 
 // Create requests the creation of a new Server Group
 func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
-	var res CreateResult
-
-	reqBody, err := opts.ToServerGroupCreateMap()
+	var r CreateResult
+	b, err := opts.ToServerGroupCreateMap()
 	if err != nil {
-		res.Err = err
-		return res
+		r.Err = err
+		return r
 	}
-
-	_, res.Err = client.Post(createURL(client), reqBody, &res.Body, &gophercloud.RequestOpts{
+	_, r.Err = client.Post(createURL(client), b, &r.Body, &gophercloud.RequestOpts{
 		OkCodes: []int{200},
 	})
-	return res
+	return r
 }
 
 // Get returns data about a previously created ServerGroup.
 func Get(client *gophercloud.ServiceClient, id string) GetResult {
-	var res GetResult
-	_, res.Err = client.Get(getURL(client, id), &res.Body, nil)
-	return res
+	var r GetResult
+	_, r.Err = client.Get(getURL(client, id), &r.Body, nil)
+	return r
 }
 
 // Delete requests the deletion of a previously allocated ServerGroup.
 func Delete(client *gophercloud.ServiceClient, id string) DeleteResult {
-	var res DeleteResult
-	_, res.Err = client.Delete(deleteURL(client, id), nil)
-	return res
+	var r DeleteResult
+	_, r.Err = client.Delete(deleteURL(client, id), nil)
+	return r
 }
diff --git a/openstack/compute/v2/extensions/startstop/requests.go b/openstack/compute/v2/extensions/startstop/requests.go
index 8364487..460223a 100644
--- a/openstack/compute/v2/extensions/startstop/requests.go
+++ b/openstack/compute/v2/extensions/startstop/requests.go
@@ -8,16 +8,14 @@
 
 // Start is the operation responsible for starting a Compute server.
 func Start(client *gophercloud.ServiceClient, id string) gophercloud.ErrResult {
-	var res gophercloud.ErrResult
-	reqBody := map[string]interface{}{"os-start": nil}
-	_, res.Err = client.Post(actionURL(client, id), reqBody, nil, nil)
-	return res
+	var r gophercloud.ErrResult
+	_, r.Err = client.Post(actionURL(client, id), map[string]interface{}{"os-start": nil}, nil, nil)
+	return r
 }
 
 // Stop is the operation responsible for stopping a Compute server.
 func Stop(client *gophercloud.ServiceClient, id string) gophercloud.ErrResult {
-	var res gophercloud.ErrResult
-	reqBody := map[string]interface{}{"os-stop": nil}
-	_, res.Err = client.Post(actionURL(client, id), reqBody, nil, nil)
-	return res
+	var r gophercloud.ErrResult
+	_, r.Err = client.Post(actionURL(client, id), map[string]interface{}{"os-stop": nil}, nil, nil)
+	return r
 }
diff --git a/openstack/compute/v2/extensions/tenantnetworks/requests.go b/openstack/compute/v2/extensions/tenantnetworks/requests.go
index 68159f2..ca33c37 100644
--- a/openstack/compute/v2/extensions/tenantnetworks/requests.go
+++ b/openstack/compute/v2/extensions/tenantnetworks/requests.go
@@ -7,16 +7,14 @@
 
 // List returns a Pager that allows you to iterate over a collection of Network.
 func List(client *gophercloud.ServiceClient) pagination.Pager {
-	url := listURL(client)
-	createPage := func(r pagination.PageResult) pagination.Page {
+	return pagination.NewPager(client, listURL(client), func(r pagination.PageResult) pagination.Page {
 		return NetworkPage{pagination.SinglePageBase(r)}
-	}
-	return pagination.NewPager(client, url, createPage)
+	})
 }
 
 // Get returns data about a previously created Network.
 func Get(client *gophercloud.ServiceClient, id string) GetResult {
-	var res GetResult
-	_, res.Err = client.Get(getURL(client, id), &res.Body, nil)
-	return res
+	var r GetResult
+	_, r.Err = client.Get(getURL(client, id), &r.Body, nil)
+	return r
 }
diff --git a/openstack/compute/v2/extensions/volumeattach/requests.go b/openstack/compute/v2/extensions/volumeattach/requests.go
index c2bc2ee..c8ef930 100644
--- a/openstack/compute/v2/extensions/volumeattach/requests.go
+++ b/openstack/compute/v2/extensions/volumeattach/requests.go
@@ -6,8 +6,8 @@
 )
 
 // List returns a Pager that allows you to iterate over a collection of VolumeAttachments.
-func List(client *gophercloud.ServiceClient, serverId string) pagination.Pager {
-	return pagination.NewPager(client, listURL(client, serverId), func(r pagination.PageResult) pagination.Page {
+func List(client *gophercloud.ServiceClient, serverID string) pagination.Pager {
+	return pagination.NewPager(client, listURL(client, serverID), func(r pagination.PageResult) pagination.Page {
 		return VolumeAttachmentPage{pagination.SinglePageBase(r)}
 	})
 }
@@ -21,56 +21,40 @@
 // CreateOpts specifies volume attachment creation or import parameters.
 type CreateOpts struct {
 	// Device is the device that the volume will attach to the instance as. Omit for "auto"
-	Device string
-
+	Device string `json:"device,omitempty"`
 	// VolumeID is the ID of the volume to attach to the instance
-	VolumeID string
+	VolumeID string `json:"volumeId" required:"true"`
 }
 
 // ToVolumeAttachmentCreateMap constructs a request body from CreateOpts.
 func (opts CreateOpts) ToVolumeAttachmentCreateMap() (map[string]interface{}, error) {
-	if opts.VolumeID == "" {
-		err := gophercloud.ErrMissingInput{}
-		err.Function = "volumeattach.ToVolumeAttachmentCreateMap"
-		err.Argument = "volumeattach.CreateOpts.VolumeID"
-		return nil, err
-	}
-
-	volumeAttachment := make(map[string]interface{})
-	volumeAttachment["volumeId"] = opts.VolumeID
-	if opts.Device != "" {
-		volumeAttachment["device"] = opts.Device
-	}
-
-	return map[string]interface{}{"volumeAttachment": volumeAttachment}, nil
+	return gophercloud.BuildRequestBody(opts, "volumeAttachment")
 }
 
 // Create requests the creation of a new volume attachment on the server
-func Create(client *gophercloud.ServiceClient, serverId string, opts CreateOptsBuilder) CreateResult {
-	var res CreateResult
-
-	reqBody, err := opts.ToVolumeAttachmentCreateMap()
+func Create(client *gophercloud.ServiceClient, serverID string, opts CreateOptsBuilder) CreateResult {
+	var r CreateResult
+	b, err := opts.ToVolumeAttachmentCreateMap()
 	if err != nil {
-		res.Err = err
-		return res
+		r.Err = err
+		return r
 	}
-
-	_, res.Err = client.Post(createURL(client, serverId), reqBody, &res.Body, &gophercloud.RequestOpts{
+	_, r.Err = client.Post(createURL(client, serverID), b, &r.Body, &gophercloud.RequestOpts{
 		OkCodes: []int{200},
 	})
-	return res
+	return r
 }
 
 // Get returns public data about a previously created VolumeAttachment.
-func Get(client *gophercloud.ServiceClient, serverId, aId string) GetResult {
-	var res GetResult
-	_, res.Err = client.Get(getURL(client, serverId, aId), &res.Body, nil)
-	return res
+func Get(client *gophercloud.ServiceClient, serverID, attachmentID string) GetResult {
+	var r GetResult
+	_, r.Err = client.Get(getURL(client, serverID, attachmentID), &r.Body, nil)
+	return r
 }
 
 // Delete requests the deletion of a previous stored VolumeAttachment from the server.
-func Delete(client *gophercloud.ServiceClient, serverId, aId string) DeleteResult {
-	var res DeleteResult
-	_, res.Err = client.Delete(deleteURL(client, serverId, aId), nil)
-	return res
+func Delete(client *gophercloud.ServiceClient, serverID, attachmentID string) DeleteResult {
+	var r DeleteResult
+	_, r.Err = client.Delete(deleteURL(client, serverID, attachmentID), nil)
+	return r
 }