dsl struct tags; wip
diff --git a/openstack/compute/v2/servers/requests.go b/openstack/compute/v2/servers/requests.go
index 4129471..4257a4a 100644
--- a/openstack/compute/v2/servers/requests.go
+++ b/openstack/compute/v2/servers/requests.go
@@ -55,16 +55,12 @@
 // ToServerListQuery formats a ListOpts into a query string.
 func (opts ListOpts) ToServerListQuery() (string, error) {
 	q, err := gophercloud.BuildQueryString(opts)
-	if err != nil {
-		return "", err
-	}
-	return q.String(), nil
+	return q.String(), err
 }
 
 // List makes a request against the API to list servers accessible to you.
 func List(client *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
 	url := listDetailURL(client)
-
 	if opts != nil {
 		query, err := opts.ToServerListQuery()
 		if err != nil {
@@ -72,12 +68,9 @@
 		}
 		url += query
 	}
-
-	createPageFn := func(r pagination.PageResult) pagination.Page {
+	return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page {
 		return ServerPage{pagination.LinkedPageBase{PageResult: r}}
-	}
-
-	return pagination.NewPager(client, url, createPageFn)
+	})
 }
 
 // CreateOptsBuilder describes struct types that can be accepted by the Create call.
@@ -189,7 +182,7 @@
 
 // ToServerCreateMap assembles a request body based on the contents of a CreateOpts.
 func (opts CreateOpts) ToServerCreateMap() (map[string]interface{}, error) {
-	b, err := gophercloud.BuildRequestBody(opts)
+	b, err := gophercloud.BuildRequestBody(opts, "")
 	if err != nil {
 		return nil, err
 	}
@@ -228,13 +221,11 @@
 	if opts.ImageRef == "" {
 		if opts.ImageName == "" {
 			err := ErrNeitherImageIDNorImageNameProvided{}
-			err.Function = "servers.CreateOpts.ToServerCreateMap"
 			err.Argument = "ImageRef/ImageName"
 			return nil, err
 		}
 		if opts.ServiceClient == nil {
 			err := ErrNoClientProvidedForIDByName{}
-			err.Function = "servers.CreateOpts.ToServerCreateMap"
 			err.Argument = "ServiceClient"
 			return nil, err
 		}
@@ -249,14 +240,12 @@
 	if opts.FlavorRef == "" {
 		if opts.FlavorName == "" {
 			err := ErrNeitherFlavorIDNorFlavorNameProvided{}
-			err.Function = "servers.CreateOpts.ToServerCreateMap"
 			err.Argument = "FlavorRef/FlavorName"
 			return nil, err
 		}
 		if opts.ServiceClient == nil {
 			err := ErrNoClientProvidedForIDByName{}
 			err.Argument = "ServiceClient"
-			err.Function = "servers.CreateOpts.ToServerCreateMap"
 			return nil, err
 		}
 		flavorID, err := flavors.IDFromName(opts.ServiceClient, opts.FlavorName)
@@ -272,13 +261,11 @@
 // Create requests a server to be provisioned to the user in the current tenant.
 func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
 	var r CreateResult
-
 	reqBody, err := opts.ToServerCreateMap()
 	if err != nil {
 		r.Err = err
 		return r
 	}
-
 	_, r.Err = client.Post(listURL(client), reqBody, &r.Body, nil)
 	return r
 }
@@ -308,42 +295,36 @@
 
 // UpdateOptsBuilder allows extensions to add additional attributes to the Update request.
 type UpdateOptsBuilder interface {
-	ToServerUpdateMap() map[string]interface{}
+	ToServerUpdateMap() (map[string]interface{}, error)
 }
 
 // UpdateOpts specifies the base attributes that may be updated on an existing server.
 type UpdateOpts struct {
-	// Name [optional] changes the displayed name of the server.
+	// Name changes the displayed name of the server.
 	// The server host name will *not* change.
 	// Server names are not constrained to be unique, even within the same tenant.
-	Name string
+	Name string `json:"name,omitempty"`
 
-	// AccessIPv4 [optional] provides a new IPv4 address for the instance.
-	AccessIPv4 string
+	// AccessIPv4 provides a new IPv4 address for the instance.
+	AccessIPv4 string `json:"accessIPv4,omitempty"`
 
-	// AccessIPv6 [optional] provides a new IPv6 address for the instance.
-	AccessIPv6 string
+	// AccessIPv6 provides a new IPv6 address for the instance.
+	AccessIPv6 string `json:"accessIPv6,omitempty"`
 }
 
 // ToServerUpdateMap formats an UpdateOpts structure into a request body.
-func (opts UpdateOpts) ToServerUpdateMap() map[string]interface{} {
-	server := make(map[string]string)
-	if opts.Name != "" {
-		server["name"] = opts.Name
-	}
-	if opts.AccessIPv4 != "" {
-		server["accessIPv4"] = opts.AccessIPv4
-	}
-	if opts.AccessIPv6 != "" {
-		server["accessIPv6"] = opts.AccessIPv6
-	}
-	return map[string]interface{}{"server": server}
+func (opts UpdateOpts) ToServerUpdateMap() (map[string]interface{}, error) {
+	return gophercloud.BuildRequestBody(opts, "server")
 }
 
 // Update requests that various attributes of the indicated server be changed.
 func Update(client *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) UpdateResult {
 	var r UpdateResult
-	b := opts.ToServerUpdateMap()
+	b, err := opts.ToServerUpdateMap()
+	if err != nil {
+		r.Err = err
+		return r
+	}
 	_, r.Err = client.Put(updateURL(client, id), b, &r.Body, &gophercloud.RequestOpts{
 		OkCodes: []int{200},
 	})
@@ -352,16 +333,13 @@
 
 // ChangeAdminPassword alters the administrator or root password for a specified server.
 func ChangeAdminPassword(client *gophercloud.ServiceClient, id, newPassword string) ActionResult {
-	var req struct {
-		ChangePassword struct {
-			AdminPass string `json:"adminPass"`
-		} `json:"changePassword"`
-	}
-
-	req.ChangePassword.AdminPass = newPassword
-
 	var r ActionResult
-	_, r.Err = client.Post(actionURL(client, id), req, nil, nil)
+	b := map[string]interface{}{
+		"changePassword": map[string]string{
+			"adminPass": newPassword,
+		},
+	}
+	_, r.Err = client.Post(actionURL(client, id), b, nil, nil)
 	return r
 }
 
@@ -377,36 +355,27 @@
 	PowerCycle              = HardReboot
 )
 
+// RebootOptsBuilder is an interface that options must satisfy in order to be
+// used when rebooting a server instance
 type RebootOptsBuilder interface {
 	ToServerRebootMap() (map[string]interface{}, error)
 }
 
+// RebootOpts satisfies the RebootOptsBuilder interface
 type RebootOpts struct {
-	Type RebootMethod
+	Type RebootMethod `json:"type" required:"true"`
 }
 
+// ToServerRebootMap allows RebootOpts to satisfiy the RebootOptsBuilder
+// interface
 func (opts *RebootOpts) ToServerRebootMap() (map[string]interface{}, error) {
-	if (opts.Type != SoftReboot) && (opts.Type != HardReboot) {
-		err := &gophercloud.ErrInvalidInput{}
-		err.Argument = "servers.RebootOpts.Type"
-		err.Value = opts.Type
-		err.Function = "servers.Reboot"
-		return nil, err
-	}
-
-	reqBody := map[string]interface{}{
-		"reboot": map[string]interface{}{
-			"type": string(opts.Type),
-		},
-	}
-
-	return reqBody, nil
+	return gophercloud.BuildRequestBody(opts, "reboot")
 }
 
 // Reboot requests that a given server reboot.
 // Two methods exist for rebooting a server:
 //
-// HardReboot (aka PowerCycle) rtarts the server instance by physically cutting power to the machine, or if a VM,
+// HardReboot (aka PowerCycle) starts the server instance by physically cutting power to the machine, or if a VM,
 // terminating it at the hypervisor level.
 // It's done. Caput. Full stop.
 // Then, after a brief while, power is rtored or the VM instance rtarted.
@@ -415,14 +384,12 @@
 // E.g., in Linux, asking it to enter runlevel 6, or executing "sudo shutdown -r now", or by asking Windows to rtart the machine.
 func Reboot(client *gophercloud.ServiceClient, id string, opts RebootOptsBuilder) ActionResult {
 	var r ActionResult
-
-	reqBody, err := opts.ToServerRebootMap()
+	b, err := opts.ToServerRebootMap()
 	if err != nil {
 		r.Err = err
 		return r
 	}
-
-	_, r.Err = client.Post(actionURL(client, id), reqBody, nil, nil)
+	_, r.Err = client.Post(actionURL(client, id), b, nil, nil)
 	return r
 }
 
@@ -435,97 +402,64 @@
 // RebuildOpts represents the configuration options used in a server rebuild
 // operation
 type RebuildOpts struct {
-	// Required. The ID of the image you want your server to be provisioned on
-	ImageID string
-
+	// The server's admin password
+	AdminPass string `json:"adminPass" required:"true"`
+	// The ID of the image you want your server to be provisioned on
+	ImageID   string `json:"imageRef"`
+	ImageName string `json:"-"`
+	//ImageName string `json:"-"`
 	// Name to set the server to
-	Name string
-
-	// Required. The server's admin password
-	AdminPass string
-
+	Name string `json:"name,omitempty"`
 	// AccessIPv4 [optional] provides a new IPv4 address for the instance.
-	AccessIPv4 string
-
+	AccessIPv4 string `json:"accessIPv4,omitempty"`
 	// AccessIPv6 [optional] provides a new IPv6 address for the instance.
-	AccessIPv6 string
-
+	AccessIPv6 string `json:"accessIPv6,omitempty"`
 	// Metadata [optional] contains key-value pairs (up to 255 bytes each) to attach to the server.
-	Metadata map[string]string
-
+	Metadata map[string]string `json:"metadata,omitempty"`
 	// Personality [optional] includes files to inject into the server at launch.
 	// Rebuild will base64-encode file contents for you.
-	Personality Personality
+	Personality   Personality                `json:"personality,omitempty"`
+	ServiceClient *gophercloud.ServiceClient `json:"-"`
 }
 
 // ToServerRebuildMap formats a RebuildOpts struct into a map for use in JSON
 func (opts RebuildOpts) ToServerRebuildMap() (map[string]interface{}, error) {
-	var err error
-	server := make(map[string]interface{})
-
-	if opts.AdminPass == "" {
-		err := ErrNoAdminPassProvided{}
-		err.Function = "servers.ToServerRebuildMap"
-		err.Argument = "AdminPass"
-		return nil, err
-	}
-
-	if opts.ImageID == "" {
-		err := ErrNoImageIDProvided{}
-		err.Function = "servers.ToServerRebuildMap"
-		err.Argument = "ImageID"
-		return nil, err
-	}
-
+	b, err := gophercloud.BuildRequestBody(opts, "")
 	if err != nil {
-		return server, err
+		return nil, err
 	}
 
-	server["adminPass"] = opts.AdminPass
-	server["imageRef"] = opts.ImageID
-
-	if opts.Name != "" {
-		server["name"] = opts.Name
+	// If ImageRef isn't provided, use ImageName to ascertain the image ID.
+	if opts.ImageID == "" {
+		if opts.ImageName == "" {
+			err := ErrNeitherImageIDNorImageNameProvided{}
+			err.Argument = "ImageRef/ImageName"
+			return nil, err
+		}
+		if opts.ServiceClient == nil {
+			err := ErrNoClientProvidedForIDByName{}
+			err.Argument = "ServiceClient"
+			return nil, err
+		}
+		imageID, err := images.IDFromName(opts.ServiceClient, opts.ImageName)
+		if err != nil {
+			return nil, err
+		}
+		b["imageRef"] = imageID
 	}
 
-	if opts.AccessIPv4 != "" {
-		server["accessIPv4"] = opts.AccessIPv4
-	}
-
-	if opts.AccessIPv6 != "" {
-		server["accessIPv6"] = opts.AccessIPv6
-	}
-
-	if opts.Metadata != nil {
-		server["metadata"] = opts.Metadata
-	}
-
-	if len(opts.Personality) > 0 {
-		server["personality"] = opts.Personality
-	}
-
-	return map[string]interface{}{"rebuild": server}, nil
+	return map[string]interface{}{"rebuild": b}, nil
 }
 
 // Rebuild will reprovision the server according to the configuration options
 // provided in the RebuildOpts struct.
 func Rebuild(client *gophercloud.ServiceClient, id string, opts RebuildOptsBuilder) RebuildResult {
 	var r RebuildResult
-
-	if id == "" {
-		err := ErrNoIDProvided{}
-		err.Function = "servers.Rebuild"
-		err.Argument = "id"
-		r.Err = err
-		return r
-	}
-
 	b, err := opts.ToServerRebuildMap()
 	if err != nil {
 		r.Err = err
 		return r
 	}
-
 	_, r.Err = client.Post(actionURL(client, id), b, &r.Body, nil)
 	return r
 }
@@ -539,17 +473,13 @@
 // ResizeOpts represents the configuration options used to control a Resize operation.
 type ResizeOpts struct {
 	// FlavorRef is the ID of the flavor you wish your server to become.
-	FlavorRef string
+	FlavorRef string `json:"flavorRef" required:"true"`
 }
 
 // ToServerResizeMap formats a ResizeOpts as a map that can be used as a JSON request body for the
 // Resize request.
 func (opts ResizeOpts) ToServerResizeMap() (map[string]interface{}, error) {
-	resize := map[string]interface{}{
-		"flavorRef": opts.FlavorRef,
-	}
-
-	return map[string]interface{}{"resize": resize}, nil
+	return gophercloud.BuildRequestBody(opts, "resize")
 }
 
 // Resize instructs the provider to change the flavor of the server.
@@ -561,21 +491,11 @@
 // Otherwise, call RevertResize() to rtore the old configuration.
 func Resize(client *gophercloud.ServiceClient, id string, opts ResizeOptsBuilder) ActionResult {
 	var r ActionResult
-
-	if id == "" {
-		err := ErrNoIDProvided{}
-		err.Function = "servers.Resize"
-		err.Argument = "id"
-		r.Err = err
-		return r
-	}
-
 	b, err := opts.ToServerResizeMap()
 	if err != nil {
 		r.Err = err
 		return r
 	}
-
 	_, r.Err = client.Post(actionURL(client, id), b, nil, nil)
 	return r
 }
@@ -584,17 +504,7 @@
 // See Resize() for more details.
 func ConfirmResize(client *gophercloud.ServiceClient, id string) ActionResult {
 	var r ActionResult
-
-	if id == "" {
-		err := ErrNoIDProvided{}
-		err.Function = "servers.ConfirmResize"
-		err.Argument = "id"
-		r.Err = err
-		return r
-	}
-
-	b := map[string]interface{}{"confirmResize": nil}
-	_, r.Err = client.Post(actionURL(client, id), b, nil, &gophercloud.RequestOpts{
+	_, r.Err = client.Post(actionURL(client, id), map[string]interface{}{"confirmResize": nil}, nil, &gophercloud.RequestOpts{
 		OkCodes: []int{201, 202, 204},
 	})
 	return r
@@ -604,17 +514,7 @@
 // See Resize() for more details.
 func RevertResize(client *gophercloud.ServiceClient, id string) ActionResult {
 	var r ActionResult
-
-	if id == "" {
-		err := ErrNoIDProvided{}
-		err.Function = "servers.RevertResize"
-		err.Argument = "id"
-		r.Err = err
-		return r
-	}
-
-	b := map[string]interface{}{"revertResize": nil}
-	_, r.Err = client.Post(actionURL(client, id), b, nil, nil)
+	_, r.Err = client.Post(actionURL(client, id), map[string]interface{}{"revertResize": nil}, nil, nil)
 	return r
 }
 
@@ -629,41 +529,26 @@
 type RescueOpts struct {
 	// AdminPass is the desired administrative password for the instance in
 	// RESCUE mode. If it's left blank, the server will generate a password.
-	AdminPass string
+	AdminPass string `json:"adminPass,omitempty"`
 }
 
 // ToServerRescueMap formats a RescueOpts as a map that can be used as a JSON
 // request body for the Rescue request.
 func (opts RescueOpts) ToServerRescueMap() (map[string]interface{}, error) {
-	server := make(map[string]interface{})
-	if opts.AdminPass != "" {
-		server["adminPass"] = opts.AdminPass
-	}
-	return map[string]interface{}{"rescue": server}, nil
+	return gophercloud.BuildRequestBody(opts, "rescue")
 }
 
 // Rescue instructs the provider to place the server into RESCUE mode.
 func Rescue(client *gophercloud.ServiceClient, id string, opts RescueOptsBuilder) RescueResult {
 	var r RescueResult
-
-	if id == "" {
-		err := ErrNoIDProvided{}
-		err.Function = "servers.Rebuild"
-		err.Argument = "id"
-		r.Err = err
-		return r
-	}
-
 	b, err := opts.ToServerRescueMap()
 	if err != nil {
 		r.Err = err
 		return r
 	}
-
 	_, r.Err = client.Post(actionURL(client, id), b, &r.Body, &gophercloud.RequestOpts{
 		OkCodes: []int{200},
 	})
-
 	return r
 }
 
@@ -692,12 +577,12 @@
 // UpdateMetadatas or UpdateMetadata function.
 func ResetMetadata(client *gophercloud.ServiceClient, id string, opts ResetMetadataOptsBuilder) ResetMetadataResult {
 	var r ResetMetadataResult
-	metadata, err := opts.ToMetadataResetMap()
+	b, err := opts.ToMetadataResetMap()
 	if err != nil {
 		r.Err = err
 		return r
 	}
-	_, r.Err = client.Put(metadataURL(client, id), metadata, &r.Body, &gophercloud.RequestOpts{
+	_, r.Err = client.Put(metadataURL(client, id), b, &r.Body, &gophercloud.RequestOpts{
 		OkCodes: []int{200},
 	})
 	return r
@@ -721,12 +606,12 @@
 // by opts.
 func UpdateMetadata(client *gophercloud.ServiceClient, id string, opts UpdateMetadataOptsBuilder) UpdateMetadataResult {
 	var r UpdateMetadataResult
-	metadata, err := opts.ToMetadataUpdateMap()
+	b, err := opts.ToMetadataUpdateMap()
 	if err != nil {
 		r.Err = err
 		return r
 	}
-	_, r.Err = client.Post(metadataURL(client, id), metadata, &r.Body, &gophercloud.RequestOpts{
+	_, r.Err = client.Post(metadataURL(client, id), b, &r.Body, &gophercloud.RequestOpts{
 		OkCodes: []int{200},
 	})
 	return r
@@ -760,13 +645,12 @@
 // CreateMetadatum will create or update the key-value pair with the given key for the given server ID.
 func CreateMetadatum(client *gophercloud.ServiceClient, id string, opts MetadatumOptsBuilder) CreateMetadatumResult {
 	var r CreateMetadatumResult
-	metadatum, key, err := opts.ToMetadatumCreateMap()
+	b, key, err := opts.ToMetadatumCreateMap()
 	if err != nil {
 		r.Err = err
 		return r
 	}
-
-	_, r.Err = client.Put(metadatumURL(client, id, key), metadatum, &r.Body, &gophercloud.RequestOpts{
+	_, r.Err = client.Put(metadatumURL(client, id, key), b, &r.Body, &gophercloud.RequestOpts{
 		OkCodes: []int{200},
 	})
 	return r
@@ -775,9 +659,7 @@
 // Metadatum requests the key-value pair with the given key for the given server ID.
 func Metadatum(client *gophercloud.ServiceClient, id, key string) GetMetadatumResult {
 	var r GetMetadatumResult
-	_, r.Err = client.Request("GET", metadatumURL(client, id, key), &gophercloud.RequestOpts{
-		JSONResponse: &r.Body,
-	})
+	_, r.Err = client.Get(metadatumURL(client, id, key), &r.Body, nil)
 	return r
 }
 
@@ -790,60 +672,47 @@
 
 // ListAddresses makes a request against the API to list the servers IP addresses.
 func ListAddresses(client *gophercloud.ServiceClient, id string) pagination.Pager {
-	createPageFn := func(r pagination.PageResult) pagination.Page {
+	return pagination.NewPager(client, listAddressesURL(client, id), func(r pagination.PageResult) pagination.Page {
 		return AddressPage{pagination.SinglePageBase(r)}
-	}
-	return pagination.NewPager(client, listAddressesURL(client, id), createPageFn)
+	})
 }
 
 // ListAddressesByNetwork makes a request against the API to list the servers IP addresses
 // for the given network.
 func ListAddressesByNetwork(client *gophercloud.ServiceClient, id, network string) pagination.Pager {
-	createPageFn := func(r pagination.PageResult) pagination.Page {
+	return pagination.NewPager(client, listAddressesByNetworkURL(client, id, network), func(r pagination.PageResult) pagination.Page {
 		return NetworkAddressPage{pagination.SinglePageBase(r)}
-	}
-	return pagination.NewPager(client, listAddressesByNetworkURL(client, id, network), createPageFn)
+	})
 }
 
-type CreateImageOpts struct {
-	// Name [required] of the image/snapshot
-	Name string
-	// Metadata [optional] contains key-value pairs (up to 255 bytes each) to attach to the created image.
-	Metadata map[string]string
-}
-
+// CreateImageOptsBuilder is the interface types must satisfy in order to be
+// used as CreateImage options
 type CreateImageOptsBuilder interface {
 	ToServerCreateImageMap() (map[string]interface{}, error)
 }
 
+// CreateImageOpts satisfies the CreateImageOptsBuilder
+type CreateImageOpts struct {
+	// Name of the image/snapshot
+	Name string `json:"name" required:"true"`
+	// Metadata contains key-value pairs (up to 255 bytes each) to attach to the created image.
+	Metadata map[string]string `json:"metadata,omitempty"`
+}
+
 // ToServerCreateImageMap formats a CreateImageOpts structure into a request body.
 func (opts CreateImageOpts) ToServerCreateImageMap() (map[string]interface{}, error) {
-	var err error
-	img := make(map[string]interface{})
-	if opts.Name == "" {
-		err := gophercloud.ErrMissingInput{}
-		err.Function = "servers.CreateImageOpts.ToServerCreateImageMap"
-		err.Argument = "CreateImageOpts.Name"
-		return nil, err
-	}
-	img["name"] = opts.Name
-	if opts.Metadata != nil {
-		img["metadata"] = opts.Metadata
-	}
-	createImage := make(map[string]interface{})
-	createImage["createImage"] = img
-	return createImage, err
+	return gophercloud.BuildRequestBody(opts, "createImage")
 }
 
 // CreateImage makes a request against the nova API to schedule an image to be created of the server
-func CreateImage(client *gophercloud.ServiceClient, serverID string, opts CreateImageOptsBuilder) CreateImageResult {
+func CreateImage(client *gophercloud.ServiceClient, id string, opts CreateImageOptsBuilder) CreateImageResult {
 	var r CreateImageResult
 	b, err := opts.ToServerCreateImageMap()
 	if err != nil {
 		r.Err = err
 		return r
 	}
-	resp, err := client.Post(actionURL(client, serverID), b, nil, &gophercloud.RequestOpts{
+	resp, err := client.Post(actionURL(client, id), b, nil, &gophercloud.RequestOpts{
 		OkCodes: []int{202},
 	})
 	r.Err = err
@@ -855,13 +724,6 @@
 func IDFromName(client *gophercloud.ServiceClient, name string) (string, error) {
 	count := 0
 	id := ""
-	if name == "" {
-		err := &gophercloud.ErrMissingInput{}
-		err.Function = "servers.IDFromName"
-		err.Argument = "name"
-		return "", err
-	}
-
 	allPages, err := List(client, nil).AllPages()
 	if err != nil {
 		return "", err
@@ -881,19 +743,10 @@
 
 	switch count {
 	case 0:
-		err := &gophercloud.ErrResourceNotFound{}
-		err.Function = "servers.IDFromName"
-		err.ResourceType = "server"
-		err.Name = name
-		return "", err
+		return "", gophercloud.ErrResourceNotFound{Name: name, ResourceType: "server"}
 	case 1:
 		return id, nil
 	default:
-		err := &gophercloud.ErrMultipleResourcesFound{}
-		err.Function = "servers.IDFromName"
-		err.ResourceType = "server"
-		err.Name = name
-		err.Count = count
-		return "", err
+		return "", gophercloud.ErrMultipleResourcesFound{Name: name, Count: count, ResourceType: "server"}
 	}
 }