dsl struct tags; wip
diff --git a/openstack/blockstorage/v1/apiversions/requests.go b/openstack/blockstorage/v1/apiversions/requests.go
index 0c05558..4e9df04 100644
--- a/openstack/blockstorage/v1/apiversions/requests.go
+++ b/openstack/blockstorage/v1/apiversions/requests.go
@@ -15,7 +15,7 @@
 // Get will retrieve the volume type with the provided ID. To extract the volume
 // type from the result, call the Extract method on the GetResult.
 func Get(client *gophercloud.ServiceClient, v string) GetResult {
-	var res GetResult
-	_, res.Err = client.Get(getURL(client, v), &res.Body, nil)
-	return res
+	var r GetResult
+	_, r.Err = client.Get(getURL(client, v), &r.Body, nil)
+	return r
 }
diff --git a/openstack/blockstorage/v1/snapshots/requests.go b/openstack/blockstorage/v1/snapshots/requests.go
index 504ce6e..e8583cb 100644
--- a/openstack/blockstorage/v1/snapshots/requests.go
+++ b/openstack/blockstorage/v1/snapshots/requests.go
@@ -15,78 +15,48 @@
 // the snapshots.Create function. For more information about these parameters,
 // see the Snapshot object.
 type CreateOpts struct {
-	// OPTIONAL
-	Description string
-	// OPTIONAL
-	Force bool
-	// OPTIONAL
-	Metadata map[string]interface{}
-	// OPTIONAL
-	Name string
-	// REQUIRED
-	VolumeID string
+	VolumeID    string                 `json:"volume_id" required:"true"`
+	Description string                 `json:"display_description,omitempty"`
+	Force       bool                   `json:"force,omitempty"`
+	Metadata    map[string]interface{} `json:"metadata,omitempty"`
+	Name        string                 `json:"display_name,omitempty"`
 }
 
 // ToSnapshotCreateMap assembles a request body based on the contents of a
 // CreateOpts.
 func (opts CreateOpts) ToSnapshotCreateMap() (map[string]interface{}, error) {
-	s := make(map[string]interface{})
-
-	if opts.VolumeID == "" {
-		err := &gophercloud.ErrMissingInput{}
-		err.Argument = "CreateOpts.VolumeID"
-		err.Function = "snapshots.ToSnapshotCreateMap"
-		return nil, err
-	}
-	s["volume_id"] = opts.VolumeID
-
-	if opts.Description != "" {
-		s["display_description"] = opts.Description
-	}
-	if opts.Force == true {
-		s["force"] = opts.Force
-	}
-	if opts.Metadata != nil {
-		s["metadata"] = opts.Metadata
-	}
-	if opts.Name != "" {
-		s["display_name"] = opts.Name
-	}
-
-	return map[string]interface{}{"snapshot": s}, nil
+	return gophercloud.BuildRequestBody(opts, "snapshot")
 }
 
 // Create will create a new Snapshot based on the values in CreateOpts. To
 // extract the Snapshot object from the response, call the Extract method on the
 // CreateResult.
 func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
-	var res CreateResult
-
-	reqBody, err := opts.ToSnapshotCreateMap()
+	var r CreateResult
+	b, err := opts.ToSnapshotCreateMap()
 	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, 201},
 	})
-	return res
+	return r
 }
 
 // Delete will delete the existing Snapshot with the provided ID.
 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
 }
 
 // Get retrieves the Snapshot with the provided ID. To extract the Snapshot
 // object from the response, call the Extract method on the GetResult.
 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
 }
 
 // ListOptsBuilder allows extensions to add additional parameters to the List
@@ -106,10 +76,7 @@
 // ToSnapshotListQuery formats a ListOpts into a query string.
 func (opts ListOpts) ToSnapshotListQuery() (string, error) {
 	q, err := gophercloud.BuildQueryString(opts)
-	if err != nil {
-		return "", err
-	}
-	return q.String(), nil
+	return q.String(), err
 }
 
 // List returns Snapshots optionally limited by the conditions provided in
@@ -123,11 +90,9 @@
 		}
 		url += query
 	}
-
-	createPage := func(r pagination.PageResult) pagination.Page {
+	return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page {
 		return SnapshotPage{pagination.SinglePageBase(r)}
-	}
-	return pagination.NewPager(client, url, createPage)
+	})
 }
 
 // UpdateMetadataOptsBuilder allows extensions to add additional parameters to
@@ -140,50 +105,35 @@
 // object is passed to the snapshots.Update function. For more information
 // about the parameters, see the Snapshot object.
 type UpdateMetadataOpts struct {
-	Metadata map[string]interface{}
+	Metadata map[string]interface{} `json:"metadata,omitempty"`
 }
 
 // ToSnapshotUpdateMetadataMap assembles a request body based on the contents of
 // an UpdateMetadataOpts.
 func (opts UpdateMetadataOpts) ToSnapshotUpdateMetadataMap() (map[string]interface{}, error) {
-	v := make(map[string]interface{})
-
-	if opts.Metadata != nil {
-		v["metadata"] = opts.Metadata
-	}
-
-	return v, nil
+	return gophercloud.BuildRequestBody(opts, "")
 }
 
 // UpdateMetadata will update the Snapshot with provided information. To
 // extract the updated Snapshot from the response, call the ExtractMetadata
 // method on the UpdateMetadataResult.
 func UpdateMetadata(client *gophercloud.ServiceClient, id string, opts UpdateMetadataOptsBuilder) UpdateMetadataResult {
-	var res UpdateMetadataResult
-
-	reqBody, err := opts.ToSnapshotUpdateMetadataMap()
+	var r UpdateMetadataResult
+	b, err := opts.ToSnapshotUpdateMetadataMap()
 	if err != nil {
-		res.Err = err
-		return res
+		r.Err = err
+		return r
 	}
-
-	_, res.Err = client.Put(updateMetadataURL(client, id), reqBody, &res.Body, &gophercloud.RequestOpts{
+	_, r.Err = client.Put(updateMetadataURL(client, id), b, &r.Body, &gophercloud.RequestOpts{
 		OkCodes: []int{200},
 	})
-	return res
+	return r
 }
 
 // IDFromName is a convienience function that returns a snapshot's ID given its name.
 func IDFromName(client *gophercloud.ServiceClient, name string) (string, error) {
 	count := 0
 	id := ""
-	if name == "" {
-		err := &gophercloud.ErrMissingInput{}
-		err.Function = "snapshots.IDFromName"
-		err.Argument = "name"
-		return "", err
-	}
-
 	pages, err := List(client, nil).AllPages()
 	if err != nil {
 		return "", err
@@ -203,19 +153,10 @@
 
 	switch count {
 	case 0:
-		err := &gophercloud.ErrResourceNotFound{}
-		err.Name = name
-		err.ResourceType = "snapshot"
-		err.Function = "snapshots.IDFromName"
-		return "", err
+		return "", gophercloud.ErrResourceNotFound{Name: name, ResourceType: "snapshot"}
 	case 1:
 		return id, nil
 	default:
-		err := &gophercloud.ErrMultipleResourcesFound{}
-		err.Count = count
-		err.Name = name
-		err.ResourceType = "snapshot"
-		err.Function = "snapshots.IDFromName"
-		return "", err
+		return "", gophercloud.ErrMultipleResourcesFound{Name: name, Count: count, ResourceType: "snapshot"}
 	}
 }
diff --git a/openstack/blockstorage/v1/volumes/requests.go b/openstack/blockstorage/v1/volumes/requests.go
index 1c6b635..7c063b2 100644
--- a/openstack/blockstorage/v1/volumes/requests.go
+++ b/openstack/blockstorage/v1/volumes/requests.go
@@ -15,94 +15,52 @@
 // the volumes.Create function. For more information about these parameters,
 // see the Volume object.
 type CreateOpts struct {
-	// OPTIONAL
-	Availability string
-	// OPTIONAL
-	Description string
-	// OPTIONAL
-	Metadata map[string]string
-	// OPTIONAL
-	Name string
-	// REQUIRED
-	Size int
-	// OPTIONAL
-	SnapshotID, SourceVolID, ImageID string
-	// OPTIONAL
-	VolumeType string
+	Size         int               `json:"size" required:"true"`
+	Availability string            `json:"availability,omitempty"`
+	Description  string            `json:"description,omitempty"`
+	Metadata     map[string]string `json:"metadata,omitempty"`
+	Name         string            `json:"name,omitempty"`
+	SnapshotID   string            `json:"snapshot_id,omitempty"`
+	SourceVolID  string            `json:"source_volid,omitempty"`
+	ImageID      string            `json:"imageRef,omitempty"`
+	VolumeType   string            `json:"volume_type,omitempty"`
 }
 
 // ToVolumeCreateMap assembles a request body based on the contents of a
 // CreateOpts.
 func (opts CreateOpts) ToVolumeCreateMap() (map[string]interface{}, error) {
-	v := make(map[string]interface{})
-
-	if opts.Size == 0 {
-		err := &gophercloud.ErrMissingInput{}
-		err.Argument = "CreateOpts.Size"
-		err.Function = "volumes.ToVolumeCreateMap"
-		return nil, err
-	}
-	v["size"] = opts.Size
-
-	if opts.Availability != "" {
-		v["availability_zone"] = opts.Availability
-	}
-	if opts.Description != "" {
-		v["display_description"] = opts.Description
-	}
-	if opts.ImageID != "" {
-		v["imageRef"] = opts.ImageID
-	}
-	if opts.Metadata != nil {
-		v["metadata"] = opts.Metadata
-	}
-	if opts.Name != "" {
-		v["display_name"] = opts.Name
-	}
-	if opts.SourceVolID != "" {
-		v["source_volid"] = opts.SourceVolID
-	}
-	if opts.SnapshotID != "" {
-		v["snapshot_id"] = opts.SnapshotID
-	}
-	if opts.VolumeType != "" {
-		v["volume_type"] = opts.VolumeType
-	}
-
-	return map[string]interface{}{"volume": v}, nil
+	return gophercloud.BuildRequestBody(opts, "volume")
 }
 
 // Create will create a new Volume based on the values in CreateOpts. To extract
 // the Volume object from the response, call the Extract method on the
 // CreateResult.
 func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
-	var res CreateResult
-
-	reqBody, err := opts.ToVolumeCreateMap()
+	var r CreateResult
+	b, err := opts.ToVolumeCreateMap()
 	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, 201},
 	})
-	return res
+	return r
 }
 
 // Delete will delete the existing Volume with the provided ID.
 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
 }
 
 // Get retrieves the Volume with the provided ID. To extract the Volume object
 // from the response, call the Extract method on the GetResult.
 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
 }
 
 // ListOptsBuilder allows extensions to add additional parameters to the List
@@ -127,10 +85,7 @@
 // ToVolumeListQuery formats a ListOpts into a query string.
 func (opts ListOpts) ToVolumeListQuery() (string, error) {
 	q, err := gophercloud.BuildQueryString(opts)
-	if err != nil {
-		return "", err
-	}
-	return q.String(), nil
+	return q.String(), err
 }
 
 // List returns Volumes optionally limited by the conditions provided in ListOpts.
@@ -143,11 +98,9 @@
 		}
 		url += query
 	}
-	createPage := func(r pagination.PageResult) pagination.Page {
+	return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page {
 		return VolumePage{pagination.SinglePageBase(r)}
-	}
-
-	return pagination.NewPager(client, url, createPage)
+	})
 }
 
 // UpdateOptsBuilder allows extensions to add additional parameters to the
@@ -161,59 +114,38 @@
 // the Volume object.
 type UpdateOpts struct {
 	// OPTIONAL
-	Name string
+	Name string `json:"name,omitempty"`
 	// OPTIONAL
-	Description string
+	Description string `json:"description,omitempty"`
 	// OPTIONAL
-	Metadata map[string]string
+	Metadata map[string]string `json:"metadata,omitempty"`
 }
 
 // ToVolumeUpdateMap assembles a request body based on the contents of an
 // UpdateOpts.
 func (opts UpdateOpts) ToVolumeUpdateMap() (map[string]interface{}, error) {
-	v := make(map[string]interface{})
-
-	if opts.Description != "" {
-		v["display_description"] = opts.Description
-	}
-	if opts.Metadata != nil {
-		v["metadata"] = opts.Metadata
-	}
-	if opts.Name != "" {
-		v["display_name"] = opts.Name
-	}
-
-	return map[string]interface{}{"volume": v}, nil
+	return gophercloud.BuildRequestBody(opts, "volume")
 }
 
 // Update will update the Volume with provided information. To extract the updated
 // Volume from the response, call the Extract method on the UpdateResult.
 func Update(client *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) UpdateResult {
-	var res UpdateResult
-
-	reqBody, err := opts.ToVolumeUpdateMap()
+	var r UpdateResult
+	b, err := opts.ToVolumeUpdateMap()
 	if err != nil {
-		res.Err = err
-		return res
+		r.Err = err
+		return r
 	}
-
-	_, res.Err = client.Put(updateURL(client, id), reqBody, &res.Body, &gophercloud.RequestOpts{
+	_, r.Err = client.Put(updateURL(client, id), b, &r.Body, &gophercloud.RequestOpts{
 		OkCodes: []int{200},
 	})
-	return res
+	return r
 }
 
 // IDFromName is a convienience function that returns a server's ID given its name.
 func IDFromName(client *gophercloud.ServiceClient, name string) (string, error) {
 	count := 0
 	id := ""
-	if name == "" {
-		err := &gophercloud.ErrMissingInput{}
-		err.Function = "volumes.IDFromName"
-		err.Argument = "name"
-		return "", err
-	}
-
 	pages, err := List(client, nil).AllPages()
 	if err != nil {
 		return "", err
@@ -233,19 +165,10 @@
 
 	switch count {
 	case 0:
-		err := &gophercloud.ErrResourceNotFound{}
-		err.Name = name
-		err.ResourceType = "volume"
-		err.Function = "volumes.IDFromName"
-		return "", err
+		return "", gophercloud.ErrResourceNotFound{Name: name, ResourceType: "volume"}
 	case 1:
 		return id, nil
 	default:
-		err := &gophercloud.ErrMultipleResourcesFound{}
-		err.Count = count
-		err.Name = name
-		err.ResourceType = "volume"
-		err.Function = "volumes.IDFromName"
-		return "", err
+		return "", gophercloud.ErrMultipleResourcesFound{Name: name, Count: count, ResourceType: "volume"}
 	}
 }
diff --git a/openstack/blockstorage/v1/volumetypes/requests.go b/openstack/blockstorage/v1/volumetypes/requests.go
index 24e50ad..b895482 100644
--- a/openstack/blockstorage/v1/volumetypes/requests.go
+++ b/openstack/blockstorage/v1/volumetypes/requests.go
@@ -13,64 +13,50 @@
 
 // CreateOpts are options for creating a volume type.
 type CreateOpts struct {
-	// OPTIONAL. See VolumeType.
-	ExtraSpecs map[string]interface{}
-	// OPTIONAL. See VolumeType.
-	Name string
+	// See VolumeType.
+	ExtraSpecs map[string]interface{} `json:"extra_specs,omitempty"`
+	// See VolumeType.
+	Name string `json:"name,omitempty"`
 }
 
 // ToVolumeTypeCreateMap casts a CreateOpts struct to a map.
 func (opts CreateOpts) ToVolumeTypeCreateMap() (map[string]interface{}, error) {
-	vt := make(map[string]interface{})
-
-	if opts.ExtraSpecs != nil {
-		vt["extra_specs"] = opts.ExtraSpecs
-	}
-	if opts.Name != "" {
-		vt["name"] = opts.Name
-	}
-
-	return map[string]interface{}{"volume_type": vt}, nil
+	return gophercloud.BuildRequestBody(opts, "volume_type")
 }
 
 // Create will create a new volume. To extract the created volume type object,
 // call the Extract method on the CreateResult.
 func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
-	var res CreateResult
-
-	reqBody, err := opts.ToVolumeTypeCreateMap()
+	var r CreateResult
+	b, err := opts.ToVolumeTypeCreateMap()
 	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, 201},
 	})
-	return res
+	return r
 }
 
 // Delete will delete the volume type with the provided ID.
 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
 }
 
 // Get will retrieve the volume type with the provided ID. To extract the volume
 // type from the result, call the Extract method on the GetResult.
 func Get(client *gophercloud.ServiceClient, id string) GetResult {
-	var res GetResult
-	_, err := client.Get(getURL(client, id), &res.Body, nil)
-	res.Err = err
-	return res
+	var r GetResult
+	_, r.Err = client.Get(getURL(client, id), &r.Body, nil)
+	return r
 }
 
 // List returns all volume types.
 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 VolumeTypePage{pagination.SinglePageBase(r)}
-	}
-
-	return pagination.NewPager(client, listURL(client), createPage)
+	})
 }