remove mapstructure from blockstorage,cdn,compute,db pkgs
diff --git a/openstack/blockstorage/v1/apiversions/requests_test.go b/openstack/blockstorage/v1/apiversions/requests_test.go
index 15a7660..3a14c99 100644
--- a/openstack/blockstorage/v1/apiversions/requests_test.go
+++ b/openstack/blockstorage/v1/apiversions/requests_test.go
@@ -54,10 +54,7 @@
 	List(client.ServiceClient()).EachPage(func(page pagination.Page) (bool, error) {
 		count++
 		actual, err := ExtractAPIVersions(page)
-		if err != nil {
-			t.Errorf("Failed to extract API versions: %v", err)
-			return false, err
-		}
+		th.AssertNoErr(t, err)
 
 		expected := []APIVersion{
 			APIVersion{
@@ -77,9 +74,7 @@
 		return true, nil
 	})
 
-	if count != 1 {
-		t.Errorf("Expected 1 page, got %d", count)
-	}
+	th.AssertEquals(t, 1, count)
 }
 
 func TestAPIInfo(t *testing.T) {
@@ -129,9 +124,7 @@
 	})
 
 	actual, err := Get(client.ServiceClient(), "v1").Extract()
-	if err != nil {
-		t.Errorf("Failed to extract version: %v", err)
-	}
+	th.AssertNoErr(t, err)
 
 	expected := APIVersion{
 		ID:      "v1.0",
diff --git a/openstack/blockstorage/v1/apiversions/results.go b/openstack/blockstorage/v1/apiversions/results.go
index 854f8dd..79a89de 100644
--- a/openstack/blockstorage/v1/apiversions/results.go
+++ b/openstack/blockstorage/v1/apiversions/results.go
@@ -3,15 +3,13 @@
 import (
 	"github.com/gophercloud/gophercloud"
 	"github.com/gophercloud/gophercloud/pagination"
-
-	"github.com/mitchellh/mapstructure"
 )
 
 // APIVersion represents an API version for Cinder.
 type APIVersion struct {
-	ID      string `json:"id" mapstructure:"id"`           // unique identifier
-	Status  string `json:"status" mapstructure:"status"`   // current status
-	Updated string `json:"updated" mapstructure:"updated"` // date last updated
+	ID      string `json:"id"`      // unique identifier
+	Status  string `json:"status"`  // current status
+	Updated string `json:"updated"` // date last updated
 }
 
 // APIVersionPage is the page returned by a pager when traversing over a
@@ -23,22 +21,18 @@
 // IsEmpty checks whether an APIVersionPage struct is empty.
 func (r APIVersionPage) IsEmpty() (bool, error) {
 	is, err := ExtractAPIVersions(r)
-	if err != nil {
-		return true, err
-	}
-	return len(is) == 0, nil
+	return len(is) == 0, err
 }
 
 // ExtractAPIVersions takes a collection page, extracts all of the elements,
 // and returns them a slice of APIVersion structs. It is effectively a cast.
 func ExtractAPIVersions(page pagination.Page) ([]APIVersion, error) {
-	var resp struct {
-		Versions []APIVersion `mapstructure:"versions"`
+	r := page.(APIVersionPage)
+	var s struct {
+		Versions []APIVersion `json:"versions"`
 	}
-
-	err := mapstructure.Decode(page.(APIVersionPage).Body, &resp)
-
-	return resp.Versions, err
+	err := r.ExtractInto(&s)
+	return s.Versions, err
 }
 
 // GetResult represents the result of a get operation.
@@ -48,11 +42,9 @@
 
 // Extract is a function that accepts a result and extracts an API version resource.
 func (r GetResult) Extract() (*APIVersion, error) {
-	var resp struct {
-		Version *APIVersion `mapstructure:"version"`
+	var s struct {
+		Version *APIVersion `json:"version"`
 	}
-
-	err := mapstructure.Decode(r.Body, &resp)
-
-	return resp.Version, err
+	err := r.ExtractInto(&s)
+	return s.Version, err
 }
diff --git a/openstack/blockstorage/v1/snapshots/requests.go b/openstack/blockstorage/v1/snapshots/requests.go
index 5e9f55c..b3b3cff 100644
--- a/openstack/blockstorage/v1/snapshots/requests.go
+++ b/openstack/blockstorage/v1/snapshots/requests.go
@@ -124,7 +124,7 @@
 	}
 
 	createPage := func(r pagination.PageResult) pagination.Page {
-		return ListResult{pagination.SinglePageBase(r)}
+		return SnapshotPage{pagination.SinglePageBase(r)}
 	}
 	return pagination.NewPager(client, url, createPage)
 }
diff --git a/openstack/blockstorage/v1/snapshots/results.go b/openstack/blockstorage/v1/snapshots/results.go
index 71d1489..f0f8864 100644
--- a/openstack/blockstorage/v1/snapshots/results.go
+++ b/openstack/blockstorage/v1/snapshots/results.go
@@ -3,50 +3,48 @@
 import (
 	"github.com/gophercloud/gophercloud"
 	"github.com/gophercloud/gophercloud/pagination"
-
-	"github.com/mitchellh/mapstructure"
 )
 
 // Snapshot contains all the information associated with an OpenStack Snapshot.
 type Snapshot struct {
 	// Currect status of the Snapshot.
-	Status string `mapstructure:"status"`
+	Status string `json:"status"`
 
 	// Display name.
-	Name string `mapstructure:"display_name"`
+	Name string `json:"display_name"`
 
 	// Instances onto which the Snapshot is attached.
-	Attachments []string `mapstructure:"attachments"`
+	Attachments []string `json:"attachments"`
 
 	// Logical group.
-	AvailabilityZone string `mapstructure:"availability_zone"`
+	AvailabilityZone string `json:"availability_zone"`
 
 	// Is the Snapshot bootable?
-	Bootable string `mapstructure:"bootable"`
+	Bootable string `json:"bootable"`
 
 	// Date created.
-	CreatedAt string `mapstructure:"created_at"`
+	CreatedAt gophercloud.JSONRFC3339Milli `json:"created_at"`
 
 	// Display description.
-	Description string `mapstructure:"display_discription"`
+	Description string `json:"display_discription"`
 
 	// See VolumeType object for more information.
-	VolumeType string `mapstructure:"volume_type"`
+	VolumeType string `json:"volume_type"`
 
 	// ID of the Snapshot from which this Snapshot was created.
-	SnapshotID string `mapstructure:"snapshot_id"`
+	SnapshotID string `json:"snapshot_id"`
 
 	// ID of the Volume from which this Snapshot was created.
-	VolumeID string `mapstructure:"volume_id"`
+	VolumeID string `json:"volume_id"`
 
 	// User-defined key-value pairs.
-	Metadata map[string]string `mapstructure:"metadata"`
+	Metadata map[string]string `json:"metadata"`
 
 	// Unique identifier.
-	ID string `mapstructure:"id"`
+	ID string `json:"id"`
 
 	// Size of the Snapshot, in GB.
-	Size int `mapstructure:"size"`
+	Size int `json:"size"`
 }
 
 // CreateResult contains the response body and error from a Create request.
@@ -64,28 +62,25 @@
 	gophercloud.ErrResult
 }
 
-// ListResult is a pagination.Pager that is returned from a call to the List function.
-type ListResult struct {
+// SnapshotPage is a pagination.Pager that is returned from a call to the List function.
+type SnapshotPage struct {
 	pagination.SinglePageBase
 }
 
-// IsEmpty returns true if a ListResult contains no Snapshots.
-func (r ListResult) IsEmpty() (bool, error) {
+// IsEmpty returns true if a SnapshotPage contains no Snapshots.
+func (r SnapshotPage) IsEmpty() (bool, error) {
 	volumes, err := ExtractSnapshots(r)
-	if err != nil {
-		return true, err
-	}
-	return len(volumes) == 0, nil
+	return len(volumes) == 0, err
 }
 
 // ExtractSnapshots extracts and returns Snapshots. It is used while iterating over a snapshots.List call.
 func ExtractSnapshots(page pagination.Page) ([]Snapshot, error) {
-	var response struct {
+	r := page.(SnapshotPage)
+	var s struct {
 		Snapshots []Snapshot `json:"snapshots"`
 	}
-
-	err := mapstructure.Decode(page.(ListResult).Body, &response)
-	return response.Snapshots, err
+	err := r.ExtractInto(&s)
+	return s.Snapshots, err
 }
 
 // UpdateMetadataResult contains the response body and error from an UpdateMetadata request.
@@ -109,15 +104,9 @@
 
 // Extract will get the Snapshot object out of the commonResult object.
 func (r commonResult) Extract() (*Snapshot, error) {
-	if r.Err != nil {
-		return nil, r.Err
-	}
-
-	var res struct {
+	var s struct {
 		Snapshot *Snapshot `json:"snapshot"`
 	}
-
-	err := mapstructure.Decode(r.Body, &res)
-
-	return res.Snapshot, err
+	err := r.ExtractInto(&s)
+	return s.Snapshot, err
 }
diff --git a/openstack/blockstorage/v1/volumes/requests.go b/openstack/blockstorage/v1/volumes/requests.go
index 96da8f4..6525d8b 100644
--- a/openstack/blockstorage/v1/volumes/requests.go
+++ b/openstack/blockstorage/v1/volumes/requests.go
@@ -143,7 +143,7 @@
 		url += query
 	}
 	createPage := func(r pagination.PageResult) pagination.Page {
-		return ListResult{pagination.SinglePageBase(r)}
+		return VolumePage{pagination.SinglePageBase(r)}
 	}
 
 	return pagination.NewPager(client, url, createPage)
diff --git a/openstack/blockstorage/v1/volumes/requests_test.go b/openstack/blockstorage/v1/volumes/requests_test.go
index 56139dd..436cfdc 100644
--- a/openstack/blockstorage/v1/volumes/requests_test.go
+++ b/openstack/blockstorage/v1/volumes/requests_test.go
@@ -2,7 +2,9 @@
 
 import (
 	"testing"
+	"time"
 
+	"github.com/gophercloud/gophercloud"
 	fixtures "github.com/gophercloud/gophercloud/openstack/blockstorage/v1/volumes/testing"
 	"github.com/gophercloud/gophercloud/pagination"
 	th "github.com/gophercloud/gophercloud/testhelper"
@@ -78,12 +80,37 @@
 
 	fixtures.MockGetResponse(t)
 
-	v, err := Get(client.ServiceClient(), "d32019d3-bc6e-4319-9c1d-6722fc136a22").Extract()
+	actual, err := Get(client.ServiceClient(), "d32019d3-bc6e-4319-9c1d-6722fc136a22").Extract()
 	th.AssertNoErr(t, err)
 
-	th.AssertEquals(t, v.Name, "vol-001")
-	th.AssertEquals(t, v.ID, "d32019d3-bc6e-4319-9c1d-6722fc136a22")
-	th.AssertEquals(t, v.Attachments[0]["device"], "/dev/vde")
+	expected := &Volume{
+		Status: "active",
+		Name:   "vol-001",
+		Attachments: []map[string]interface{}{
+			{
+				"attachment_id": "03987cd1-0ad5-40d1-9b2a-7cc48295d4fa",
+				"id":            "47e9ecc5-4045-4ee3-9a4b-d859d546a0cf",
+				"volume_id":     "6c80f8ac-e3e2-480c-8e6e-f1db92fe4bfe",
+				"server_id":     "d1c4788b-9435-42e2-9b81-29f3be1cd01f",
+				"host_name":     "mitaka",
+				"device":        "/",
+			},
+		},
+		AvailabilityZone: "us-east1",
+		Bootable:         "false",
+		CreatedAt:        gophercloud.JSONRFC3339Milli(time.Date(2012, 2, 14, 20, 53, 07, 0, time.UTC)),
+		Description:      "Another volume.",
+		VolumeType:       "289da7f8-6440-407c-9fb4-7db01ec49164",
+		SnapshotID:       "",
+		SourceVolID:      "",
+		Metadata: map[string]string{
+			"contents": "junk",
+		},
+		ID:   "521752a6-acf6-4b2d-bc7a-119f9148cd8c",
+		Size: 30,
+	}
+
+	th.AssertDeepEquals(t, expected, actual)
 }
 
 func TestCreate(t *testing.T) {
diff --git a/openstack/blockstorage/v1/volumes/results.go b/openstack/blockstorage/v1/volumes/results.go
index ee584d3..6371840 100644
--- a/openstack/blockstorage/v1/volumes/results.go
+++ b/openstack/blockstorage/v1/volumes/results.go
@@ -3,50 +3,48 @@
 import (
 	"github.com/gophercloud/gophercloud"
 	"github.com/gophercloud/gophercloud/pagination"
-
-	"github.com/mitchellh/mapstructure"
 )
 
 // Volume contains all the information associated with an OpenStack Volume.
 type Volume struct {
 	// Current status of the volume.
-	Status string `mapstructure:"status"`
+	Status string `json:"status"`
 
 	// Human-readable display name for the volume.
-	Name string `mapstructure:"display_name"`
+	Name string `json:"display_name"`
 
 	// Instances onto which the volume is attached.
-	Attachments []map[string]interface{} `mapstructure:"attachments"`
+	Attachments []map[string]interface{} `json:"attachments"`
 
 	// This parameter is no longer used.
-	AvailabilityZone string `mapstructure:"availability_zone"`
+	AvailabilityZone string `json:"availability_zone"`
 
 	// Indicates whether this is a bootable volume.
-	Bootable string `mapstructure:"bootable"`
+	Bootable string `json:"bootable"`
 
 	// The date when this volume was created.
-	CreatedAt string `mapstructure:"created_at"`
+	CreatedAt gophercloud.JSONRFC3339Milli `json:"created_at"`
 
 	// Human-readable description for the volume.
-	Description string `mapstructure:"display_description"`
+	Description string `json:"display_description"`
 
 	// The type of volume to create, either SATA or SSD.
-	VolumeType string `mapstructure:"volume_type"`
+	VolumeType string `json:"volume_type"`
 
 	// The ID of the snapshot from which the volume was created
-	SnapshotID string `mapstructure:"snapshot_id"`
+	SnapshotID string `json:"snapshot_id"`
 
 	// The ID of another block storage volume from which the current volume was created
-	SourceVolID string `mapstructure:"source_volid"`
+	SourceVolID string `json:"source_volid"`
 
 	// Arbitrary key-value pairs defined by the user.
-	Metadata map[string]string `mapstructure:"metadata"`
+	Metadata map[string]string `json:"metadata"`
 
 	// Unique identifier for the volume.
-	ID string `mapstructure:"id"`
+	ID string `json:"id"`
 
 	// Size of the volume in GB.
-	Size int `mapstructure:"size"`
+	Size int `json:"size"`
 }
 
 // CreateResult contains the response body and error from a Create request.
@@ -64,28 +62,25 @@
 	gophercloud.ErrResult
 }
 
-// ListResult is a pagination.pager that is returned from a call to the List function.
-type ListResult struct {
+// VolumePage is a pagination.pager that is returned from a call to the List function.
+type VolumePage struct {
 	pagination.SinglePageBase
 }
 
-// IsEmpty returns true if a ListResult contains no Volumes.
-func (r ListResult) IsEmpty() (bool, error) {
+// IsEmpty returns true if a VolumePage contains no Volumes.
+func (r VolumePage) IsEmpty() (bool, error) {
 	volumes, err := ExtractVolumes(r)
-	if err != nil {
-		return true, err
-	}
-	return len(volumes) == 0, nil
+	return len(volumes) == 0, err
 }
 
 // ExtractVolumes extracts and returns Volumes. It is used while iterating over a volumes.List call.
 func ExtractVolumes(page pagination.Page) ([]Volume, error) {
-	var response struct {
+	r := page.(VolumePage)
+	var s struct {
 		Volumes []Volume `json:"volumes"`
 	}
-
-	err := mapstructure.Decode(page.(ListResult).Body, &response)
-	return response.Volumes, err
+	err := r.ExtractInto(&s)
+	return s.Volumes, err
 }
 
 // UpdateResult contains the response body and error from an Update request.
@@ -99,15 +94,9 @@
 
 // Extract will get the Volume object out of the commonResult object.
 func (r commonResult) Extract() (*Volume, error) {
-	if r.Err != nil {
-		return nil, r.Err
-	}
-
-	var res struct {
+	var s struct {
 		Volume *Volume `json:"volume"`
 	}
-
-	err := mapstructure.Decode(r.Body, &res)
-
-	return res.Volume, err
+	err := r.ExtractInto(&s)
+	return s.Volume, err
 }
diff --git a/openstack/blockstorage/v1/volumes/testing/fixtures.go b/openstack/blockstorage/v1/volumes/testing/fixtures.go
index b72fed0..421cbf4 100644
--- a/openstack/blockstorage/v1/volumes/testing/fixtures.go
+++ b/openstack/blockstorage/v1/volumes/testing/fixtures.go
@@ -42,20 +42,33 @@
 		w.Header().Add("Content-Type", "application/json")
 		w.WriteHeader(http.StatusOK)
 		fmt.Fprintf(w, `
-{
-    "volume": {
-        "display_name": "vol-001",
-        "id": "d32019d3-bc6e-4319-9c1d-6722fc136a22",
- 	"attachments": [
-	  {
-            "device": "/dev/vde",
-            "server_id": "a740d24b-dc5b-4d59-ac75-53971c2920ba",
-            "id": "d6da11e5-2ed3-413e-88d8-b772ba62193d",
-            "volume_id": "d6da11e5-2ed3-413e-88d8-b772ba62193d"
-          }
-        ]
-   }
-}
+			{
+			    "volume": {
+			        "id": "521752a6-acf6-4b2d-bc7a-119f9148cd8c",
+			        "display_name": "vol-001",
+			        "display_description": "Another volume.",
+			        "status": "active",
+			        "size": 30,
+			        "volume_type": "289da7f8-6440-407c-9fb4-7db01ec49164",
+			        "metadata": {
+			            "contents": "junk"
+			        },
+			        "availability_zone": "us-east1",
+			        "bootable": "false",
+			        "snapshot_id": null,
+			        "attachments": [
+			            {
+			                "attachment_id": "03987cd1-0ad5-40d1-9b2a-7cc48295d4fa",
+			                "id": "47e9ecc5-4045-4ee3-9a4b-d859d546a0cf",
+			                "volume_id": "6c80f8ac-e3e2-480c-8e6e-f1db92fe4bfe",
+			                "server_id": "d1c4788b-9435-42e2-9b81-29f3be1cd01f",
+			                "host_name": "mitaka",
+			                "device": "/"
+			            }
+			        ],
+			        "created_at": "2012-02-14T20:53:07Z"
+			    }
+			}
       `)
 	})
 }
diff --git a/openstack/blockstorage/v1/volumetypes/requests.go b/openstack/blockstorage/v1/volumetypes/requests.go
index 50ace44..24e50ad 100644
--- a/openstack/blockstorage/v1/volumetypes/requests.go
+++ b/openstack/blockstorage/v1/volumetypes/requests.go
@@ -69,7 +69,7 @@
 // List returns all volume types.
 func List(client *gophercloud.ServiceClient) pagination.Pager {
 	createPage := func(r pagination.PageResult) pagination.Page {
-		return ListResult{pagination.SinglePageBase(r)}
+		return VolumeTypePage{pagination.SinglePageBase(r)}
 	}
 
 	return pagination.NewPager(client, listURL(client), createPage)
diff --git a/openstack/blockstorage/v1/volumetypes/results.go b/openstack/blockstorage/v1/volumetypes/results.go
index 5948e8f..74e193f 100644
--- a/openstack/blockstorage/v1/volumetypes/results.go
+++ b/openstack/blockstorage/v1/volumetypes/results.go
@@ -1,16 +1,15 @@
 package volumetypes
 
 import (
-	"github.com/mitchellh/mapstructure"
 	"github.com/gophercloud/gophercloud"
 	"github.com/gophercloud/gophercloud/pagination"
 )
 
 // VolumeType contains all information associated with an OpenStack Volume Type.
 type VolumeType struct {
-	ExtraSpecs map[string]interface{} `json:"extra_specs" mapstructure:"extra_specs"` // user-defined metadata
-	ID         string                 `json:"id" mapstructure:"id"`                   // unique identifier
-	Name       string                 `json:"name" mapstructure:"name"`               // display name
+	ExtraSpecs map[string]interface{} `json:"extra_specs"` // user-defined metadata
+	ID         string                 `json:"id"`          // unique identifier
+	Name       string                 `json:"name"`        // display name
 }
 
 // CreateResult contains the response body and error from a Create request.
@@ -28,28 +27,25 @@
 	gophercloud.ErrResult
 }
 
-// ListResult is a pagination.Pager that is returned from a call to the List function.
-type ListResult struct {
+// VolumeTypePage is a pagination.Pager that is returned from a call to the List function.
+type VolumeTypePage struct {
 	pagination.SinglePageBase
 }
 
-// IsEmpty returns true if a ListResult contains no Volume Types.
-func (r ListResult) IsEmpty() (bool, error) {
+// IsEmpty returns true if a VolumeTypePage contains no Volume Types.
+func (r VolumeTypePage) IsEmpty() (bool, error) {
 	volumeTypes, err := ExtractVolumeTypes(r)
-	if err != nil {
-		return true, err
-	}
-	return len(volumeTypes) == 0, nil
+	return len(volumeTypes) == 0, err
 }
 
 // ExtractVolumeTypes extracts and returns Volume Types.
 func ExtractVolumeTypes(page pagination.Page) ([]VolumeType, error) {
-	var response struct {
-		VolumeTypes []VolumeType `mapstructure:"volume_types"`
+	r := page.(VolumeTypePage)
+	var s struct {
+		VolumeTypes []VolumeType `json:"volume_types"`
 	}
-
-	err := mapstructure.Decode(page.(ListResult).Body, &response)
-	return response.VolumeTypes, err
+	err := r.ExtractInto(&s)
+	return s.VolumeTypes, err
 }
 
 type commonResult struct {
@@ -58,15 +54,9 @@
 
 // Extract will get the Volume Type object out of the commonResult object.
 func (r commonResult) Extract() (*VolumeType, error) {
-	if r.Err != nil {
-		return nil, r.Err
+	var s struct {
+		VolumeType *VolumeType `json:"volume_type"`
 	}
-
-	var res struct {
-		VolumeType *VolumeType `json:"volume_type" mapstructure:"volume_type"`
-	}
-
-	err := mapstructure.Decode(r.Body, &res)
-
-	return res.VolumeType, err
+	err := r.ExtractInto(&s)
+	return s.VolumeType, err
 }
diff --git a/openstack/cdn/v1/base/results.go b/openstack/cdn/v1/base/results.go
index 4e1b524..2dfde7d 100644
--- a/openstack/cdn/v1/base/results.go
+++ b/openstack/cdn/v1/base/results.go
@@ -1,10 +1,6 @@
 package base
 
-import (
-	"errors"
-
-	"github.com/gophercloud/gophercloud"
-)
+import "github.com/gophercloud/gophercloud"
 
 // HomeDocument is a resource that contains all the resources for the CDN API.
 type HomeDocument map[string]interface{}
@@ -16,17 +12,9 @@
 
 // Extract is a function that accepts a result and extracts a home document resource.
 func (r GetResult) Extract() (*HomeDocument, error) {
-	if r.Err != nil {
-		return nil, r.Err
-	}
-
-	submap, ok := r.Body.(map[string]interface{})["resources"]
-	if !ok {
-		return nil, errors.New("Unexpected HomeDocument structure")
-	}
-	casted := HomeDocument(submap.(map[string]interface{}))
-
-	return &casted, nil
+	var s HomeDocument
+	err := r.ExtractInto(&s)
+	return &s, err
 }
 
 // PingResult represents the result of a Ping operation.
diff --git a/openstack/cdn/v1/flavors/results.go b/openstack/cdn/v1/flavors/results.go
index 45308bc..1b15dbc 100644
--- a/openstack/cdn/v1/flavors/results.go
+++ b/openstack/cdn/v1/flavors/results.go
@@ -1,7 +1,6 @@
 package flavors
 
 import (
-	"github.com/mitchellh/mapstructure"
 	"github.com/gophercloud/gophercloud"
 	"github.com/gophercloud/gophercloud/pagination"
 )
@@ -10,20 +9,20 @@
 type Provider struct {
 	// Specifies the name of the provider. The name must not exceed 64 bytes in
 	// length and is limited to unicode, digits, underscores, and hyphens.
-	Provider string `mapstructure:"provider"`
+	Provider string `json:"provider"`
 	// Specifies a list with an href where rel is provider_url.
-	Links []gophercloud.Link `mapstructure:"links"`
+	Links []gophercloud.Link `json:"links"`
 }
 
 // Flavor represents a mapping configuration to a CDN provider.
 type Flavor struct {
 	// Specifies the name of the flavor. The name must not exceed 64 bytes in
 	// length and is limited to unicode, digits, underscores, and hyphens.
-	ID string `mapstructure:"id"`
+	ID string `json:"id"`
 	// Specifies the list of providers mapped to this flavor.
-	Providers []Provider `mapstructure:"providers"`
+	Providers []Provider `json:"providers"`
 	// Specifies the self-navigating JSON document paths.
-	Links []gophercloud.Link `mapstructure:"links"`
+	Links []gophercloud.Link `json:"links"`
 }
 
 // FlavorPage is the page returned by a pager when traversing over a
@@ -44,12 +43,12 @@
 // ExtractFlavors extracts and returns Flavors. It is used while iterating over
 // a flavors.List call.
 func ExtractFlavors(page pagination.Page) ([]Flavor, error) {
-	var response struct {
+	r := page.(FlavorPage)
+	var s struct {
 		Flavors []Flavor `json:"flavors"`
 	}
-
-	err := mapstructure.Decode(page.(FlavorPage).Body, &response)
-	return response.Flavors, err
+	err := r.ExtractInto(&s)
+	return s.Flavors, err
 }
 
 // GetResult represents the result of a get operation.
@@ -59,13 +58,7 @@
 
 // Extract is a function that extracts a flavor from a GetResult.
 func (r GetResult) Extract() (*Flavor, error) {
-	if r.Err != nil {
-		return nil, r.Err
-	}
-
-	var res Flavor
-
-	err := mapstructure.Decode(r.Body, &res)
-
-	return &res, err
+	var s Flavor
+	err := r.ExtractInto(&s)
+	return &s, err
 }
diff --git a/openstack/cdn/v1/services/results.go b/openstack/cdn/v1/services/results.go
index a214944..e37fafa 100644
--- a/openstack/cdn/v1/services/results.go
+++ b/openstack/cdn/v1/services/results.go
@@ -3,18 +3,16 @@
 import (
 	"github.com/gophercloud/gophercloud"
 	"github.com/gophercloud/gophercloud/pagination"
-
-	"github.com/mitchellh/mapstructure"
 )
 
 // Domain represents a domain used by users to access their website.
 type Domain struct {
 	// Specifies the domain used to access the assets on their website, for which
 	// a CNAME is given to the CDN provider.
-	Domain string `mapstructure:"domain" json:"domain"`
+	Domain string `json:"domain"`
 	// Specifies the protocol used to access the assets on this domain. Only "http"
 	// or "https" are currently allowed. The default is "http".
-	Protocol string `mapstructure:"protocol" json:"protocol,omitempty"`
+	Protocol string `json:"protocol,omitempty"`
 }
 
 func (d Domain) toPatchValue() interface{} {
@@ -56,23 +54,23 @@
 // OriginRule represents a rule that defines when an origin should be accessed.
 type OriginRule struct {
 	// Specifies the name of this rule.
-	Name string `mapstructure:"name" json:"name"`
+	Name string `json:"name"`
 	// Specifies the request URL this rule should match for this origin to be used. Regex is supported.
-	RequestURL string `mapstructure:"request_url" json:"request_url"`
+	RequestURL string `json:"request_url"`
 }
 
 // Origin specifies a list of origin domains or IP addresses where the original assets are stored.
 type Origin struct {
 	// Specifies the URL or IP address to pull origin content from.
-	Origin string `mapstructure:"origin" json:"origin"`
+	Origin string `json:"origin"`
 	// Specifies the port used to access the origin. The default is port 80.
-	Port int `mapstructure:"port" json:"port,omitempty"`
+	Port int `json:"port"`
 	// Specifies whether or not to use HTTPS to access the origin. The default
 	// is false.
-	SSL bool `mapstructure:"ssl" json:"ssl"`
+	SSL bool `json:"ssl"`
 	// Specifies a collection of rules that define the conditions when this origin
 	// should be accessed. If there is more than one origin, the rules parameter is required.
-	Rules []OriginRule `mapstructure:"rules" json:"rules,omitempty"`
+	Rules []OriginRule `json:"rules,omitempty"`
 }
 
 func (o Origin) toPatchValue() interface{} {
@@ -121,19 +119,19 @@
 // TTLRule specifies a rule that determines if a TTL should be applied to an asset.
 type TTLRule struct {
 	// Specifies the name of this rule.
-	Name string `mapstructure:"name" json:"name"`
+	Name string `json:"name"`
 	// Specifies the request URL this rule should match for this TTL to be used. Regex is supported.
-	RequestURL string `mapstructure:"request_url" json:"request_url"`
+	RequestURL string `json:"request_url"`
 }
 
 // CacheRule specifies the TTL rules for the assets under this service.
 type CacheRule struct {
 	// Specifies the name of this caching rule. Note: 'default' is a reserved name used for the default TTL setting.
-	Name string `mapstructure:"name" json:"name"`
+	Name string `json:"name"`
 	// Specifies the TTL to apply.
-	TTL int `mapstructure:"ttl" json:"ttl"`
+	TTL int `json:"ttl"`
 	// Specifies a collection of rules that determine if this TTL should be applied to an asset.
-	Rules []TTLRule `mapstructure:"rules" json:"rules,omitempty"`
+	Rules []TTLRule `json:"rules,omitempty"`
 }
 
 func (c CacheRule) toPatchValue() interface{} {
@@ -179,48 +177,48 @@
 // RestrictionRule specifies a rule that determines if this restriction should be applied to an asset.
 type RestrictionRule struct {
 	// Specifies the name of this rule.
-	Name string `mapstructure:"name" json:"name"`
+	Name string `json:"name"`
 	// Specifies the http host that requests must come from.
-	Referrer string `mapstructure:"referrer" json:"referrer,omitempty"`
+	Referrer string `json:"referrer"`
 }
 
 // Restriction specifies a restriction that defines who can access assets (content from the CDN cache).
 type Restriction struct {
 	// Specifies the name of this restriction.
-	Name string `mapstructure:"name" json:"name"`
+	Name string `json:"name"`
 	// Specifies a collection of rules that determine if this TTL should be applied to an asset.
-	Rules []RestrictionRule `mapstructure:"rules" json:"rules"`
+	Rules []RestrictionRule `json:"rules"`
 }
 
 // Error specifies an error that occurred during the previous service action.
 type Error struct {
 	// Specifies an error message detailing why there is an error.
-	Message string `mapstructure:"message"`
+	Message string `json:"message"`
 }
 
 // Service represents a CDN service resource.
 type Service struct {
 	// Specifies the service ID that represents distributed content. The value is
 	// a UUID, such as 96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0, that is generated by the server.
-	ID string `mapstructure:"id"`
+	ID string `json:"id"`
 	// Specifies the name of the service.
-	Name string `mapstructure:"name"`
+	Name string `json:"name"`
 	// Specifies a list of domains used by users to access their website.
-	Domains []Domain `mapstructure:"domains"`
+	Domains []Domain `json:"domains"`
 	// Specifies a list of origin domains or IP addresses where the original assets are stored.
-	Origins []Origin `mapstructure:"origins"`
+	Origins []Origin `json:"origins"`
 	// Specifies the TTL rules for the assets under this service. Supports wildcards for fine grained control.
-	Caching []CacheRule `mapstructure:"caching"`
+	Caching []CacheRule `json:"caching"`
 	// Specifies the restrictions that define who can access assets (content from the CDN cache).
-	Restrictions []Restriction `mapstructure:"restrictions" json:"restrictions,omitempty"`
+	Restrictions []Restriction `json:"restrictions"`
 	// Specifies the CDN provider flavor ID to use. For a list of flavors, see the operation to list the available flavors.
-	FlavorID string `mapstructure:"flavor_id"`
+	FlavorID string `json:"flavor_id"`
 	// Specifies the current status of the service.
-	Status string `mapstructure:"status"`
+	Status string `json:"status"`
 	// Specifies the list of errors that occurred during the previous service action.
-	Errors []Error `mapstructure:"errors"`
+	Errors []Error `json:"errors"`
 	// Specifies the self-navigating JSON document paths.
-	Links []gophercloud.Link `mapstructure:"links"`
+	Links []gophercloud.Link `json:"links"`
 }
 
 // ServicePage is the page returned by a pager when traversing over a
@@ -252,12 +250,12 @@
 
 // ExtractServices is a function that takes a ListResult and returns the services' information.
 func ExtractServices(page pagination.Page) ([]Service, error) {
-	var response struct {
-		Services []Service `mapstructure:"services"`
+	r := page.(ServicePage)
+	var s struct {
+		Services []Service `json:"services"`
 	}
-
-	err := mapstructure.Decode(page.(ServicePage).Body, &response)
-	return response.Services, err
+	err := r.ExtractInto(&s)
+	return s.Services, err
 }
 
 // CreateResult represents the result of a Create operation.
@@ -283,15 +281,9 @@
 
 // Extract is a function that extracts a service from a GetResult.
 func (r GetResult) Extract() (*Service, error) {
-	if r.Err != nil {
-		return nil, r.Err
-	}
-
-	var res Service
-
-	err := mapstructure.Decode(r.Body, &res)
-
-	return &res, err
+	var s Service
+	err := r.ExtractInto(&s)
+	return &s, err
 }
 
 // UpdateResult represents the result of a Update operation.
diff --git a/openstack/common/extensions/results.go b/openstack/common/extensions/results.go
index 02b3c80..05de97e 100755
--- a/openstack/common/extensions/results.go
+++ b/openstack/common/extensions/results.go
@@ -1,7 +1,6 @@
 package extensions
 
 import (
-	"github.com/mitchellh/mapstructure"
 	"github.com/gophercloud/gophercloud"
 	"github.com/gophercloud/gophercloud/pagination"
 )
@@ -14,27 +13,21 @@
 
 // Extract interprets a GetResult as an Extension.
 func (r GetResult) Extract() (*Extension, error) {
-	if r.Err != nil {
-		return nil, r.Err
-	}
-
-	var res struct {
+	var s struct {
 		Extension *Extension `json:"extension"`
 	}
-
-	err := mapstructure.Decode(r.Body, &res)
-
-	return res.Extension, err
+	err := r.ExtractInto(&s)
+	return s.Extension, err
 }
 
 // Extension is a struct that represents an OpenStack extension.
 type Extension struct {
-	Updated     string        `json:"updated" mapstructure:"updated"`
-	Name        string        `json:"name" mapstructure:"name"`
-	Links       []interface{} `json:"links" mapstructure:"links"`
-	Namespace   string        `json:"namespace" mapstructure:"namespace"`
-	Alias       string        `json:"alias" mapstructure:"alias"`
-	Description string        `json:"description" mapstructure:"description"`
+	Updated     string        `json:"updated"`
+	Name        string        `json:"name"`
+	Links       []interface{} `json:"links"`
+	Namespace   string        `json:"namespace"`
+	Alias       string        `json:"alias"`
+	Description string        `json:"description"`
 }
 
 // ExtensionPage is the page returned by a pager when traversing over a collection of extensions.
@@ -55,11 +48,10 @@
 // elements into a slice of Extension structs.
 // In other words, a generic collection is mapped into a relevant slice.
 func ExtractExtensions(page pagination.Page) ([]Extension, error) {
-	var resp struct {
-		Extensions []Extension `mapstructure:"extensions"`
+	r := page.(ExtensionPage)
+	var s struct {
+		Extensions []Extension `json:"extensions"`
 	}
-
-	err := mapstructure.Decode(page.(ExtensionPage).Body, &resp)
-
-	return resp.Extensions, err
+	err := r.ExtractInto(&s)
+	return s.Extensions, err
 }
diff --git a/openstack/compute/v2/extensions/bootfromvolume/requests_test.go b/openstack/compute/v2/extensions/bootfromvolume/requests_test.go
index 1c096a9..2359a77 100644
--- a/openstack/compute/v2/extensions/bootfromvolume/requests_test.go
+++ b/openstack/compute/v2/extensions/bootfromvolume/requests_test.go
@@ -32,8 +32,6 @@
         "name": "createdserver",
         "imageRef": "asdfasdfasdf",
         "flavorRef": "performance1-1",
-        "flavorName": "",
-        "imageName": "",
         "block_device_mapping_v2":[
           {
             "uuid":"123456",
@@ -94,8 +92,6 @@
         "name": "createdserver",
         "imageRef": "asdfasdfasdf",
         "flavorRef": "performance1-1",
-        "flavorName": "",
-        "imageName": "",
         "block_device_mapping_v2":[
           {
             "boot_index": "0",
diff --git a/openstack/compute/v2/extensions/defsecrules/results.go b/openstack/compute/v2/extensions/defsecrules/results.go
index 4adfa91..00d0bb5 100644
--- a/openstack/compute/v2/extensions/defsecrules/results.go
+++ b/openstack/compute/v2/extensions/defsecrules/results.go
@@ -1,8 +1,6 @@
 package defsecrules
 
 import (
-	"github.com/mitchellh/mapstructure"
-
 	"github.com/gophercloud/gophercloud"
 	"github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/secgroups"
 	"github.com/gophercloud/gophercloud/pagination"
@@ -29,14 +27,12 @@
 // ExtractDefaultRules returns a slice of DefaultRules contained in a single
 // page of results.
 func ExtractDefaultRules(page pagination.Page) ([]DefaultRule, error) {
-	casted := page.(DefaultRulePage).Body
-	var response struct {
-		Rules []DefaultRule `mapstructure:"security_group_default_rules"`
+	r := page.(DefaultRulePage)
+	var s struct {
+		DefaultRules []DefaultRule `json:"security_group_default_rules"`
 	}
-
-	err := mapstructure.WeakDecode(casted, &response)
-
-	return response.Rules, err
+	err := r.ExtractInto(&s)
+	return s.DefaultRules, err
 }
 
 type commonResult struct {
@@ -55,15 +51,9 @@
 
 // Extract will extract a DefaultRule struct from most responses.
 func (r commonResult) Extract() (*DefaultRule, error) {
-	if r.Err != nil {
-		return nil, r.Err
+	var s struct {
+		DefaultRule DefaultRule `json:"security_group_default_rule"`
 	}
-
-	var response struct {
-		Rule DefaultRule `mapstructure:"security_group_default_rule"`
-	}
-
-	err := mapstructure.WeakDecode(r.Body, &response)
-
-	return &response.Rule, err
+	err := r.ExtractInto(&s)
+	return &s.DefaultRule, err
 }
diff --git a/openstack/compute/v2/extensions/diskconfig/requests_test.go b/openstack/compute/v2/extensions/diskconfig/requests_test.go
index 61057d4..2e3ae18 100644
--- a/openstack/compute/v2/extensions/diskconfig/requests_test.go
+++ b/openstack/compute/v2/extensions/diskconfig/requests_test.go
@@ -25,8 +25,6 @@
 				"name": "createdserver",
 				"imageRef": "asdfasdfasdf",
 				"flavorRef": "performance1-1",
-				"flavorName": "",
-				"imageName": "",
 				"OS-DCF:diskConfig": "MANUAL"
 			}
 		}
diff --git a/openstack/compute/v2/extensions/diskconfig/results.go b/openstack/compute/v2/extensions/diskconfig/results.go
index b05c5b5..1957e12 100644
--- a/openstack/compute/v2/extensions/diskconfig/results.go
+++ b/openstack/compute/v2/extensions/diskconfig/results.go
@@ -1,60 +1,8 @@
 package diskconfig
 
-import (
-	"github.com/mitchellh/mapstructure"
-	"github.com/gophercloud/gophercloud"
-	"github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
-	"github.com/gophercloud/gophercloud/pagination"
-)
+import "github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
 
-func commonExtract(result gophercloud.Result) (*DiskConfig, error) {
-	var resp struct {
-		Server struct {
-			DiskConfig string `mapstructure:"OS-DCF:diskConfig"`
-		} `mapstructure:"server"`
-	}
-
-	err := mapstructure.Decode(result.Body, &resp)
-	if err != nil {
-		return nil, err
-	}
-
-	config := DiskConfig(resp.Server.DiskConfig)
-	return &config, nil
-}
-
-// ExtractGet returns the disk configuration from a servers.Get call.
-func ExtractGet(result servers.GetResult) (*DiskConfig, error) {
-	return commonExtract(result.Result)
-}
-
-// ExtractUpdate returns the disk configuration from a servers.Update call.
-func ExtractUpdate(result servers.UpdateResult) (*DiskConfig, error) {
-	return commonExtract(result.Result)
-}
-
-// ExtractRebuild returns the disk configuration from a servers.Rebuild call.
-func ExtractRebuild(result servers.RebuildResult) (*DiskConfig, error) {
-	return commonExtract(result.Result)
-}
-
-// ExtractDiskConfig returns the DiskConfig setting for a specific server acquired from an
-// servers.ExtractServers call, while iterating through a Pager.
-func ExtractDiskConfig(page pagination.Page, index int) (*DiskConfig, error) {
-	casted := page.(servers.ServerPage).Body
-
-	type server struct {
-		DiskConfig string `mapstructure:"OS-DCF:diskConfig"`
-	}
-	var response struct {
-		Servers []server `mapstructure:"servers"`
-	}
-
-	err := mapstructure.Decode(casted, &response)
-	if err != nil {
-		return nil, err
-	}
-
-	config := DiskConfig(response.Servers[index].DiskConfig)
-	return &config, nil
+type ServerWithDiskConfig struct {
+	servers.Server
+	DiskConfig DiskConfig `json:"OS-DCF:diskConfig"`
 }
diff --git a/openstack/compute/v2/extensions/diskconfig/results_test.go b/openstack/compute/v2/extensions/diskconfig/results_test.go
deleted file mode 100644
index 7c5b6c9..0000000
--- a/openstack/compute/v2/extensions/diskconfig/results_test.go
+++ /dev/null
@@ -1,68 +0,0 @@
-package diskconfig
-
-import (
-	"testing"
-
-	"github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
-	"github.com/gophercloud/gophercloud/pagination"
-	th "github.com/gophercloud/gophercloud/testhelper"
-	"github.com/gophercloud/gophercloud/testhelper/client"
-)
-
-func TestExtractGet(t *testing.T) {
-	th.SetupHTTP()
-	defer th.TeardownHTTP()
-	servers.HandleServerGetSuccessfully(t)
-
-	config, err := ExtractGet(servers.Get(client.ServiceClient(), "1234asdf"))
-	th.AssertNoErr(t, err)
-	th.CheckEquals(t, Manual, *config)
-}
-
-func TestExtractUpdate(t *testing.T) {
-	th.SetupHTTP()
-	defer th.TeardownHTTP()
-	servers.HandleServerUpdateSuccessfully(t)
-
-	r := servers.Update(client.ServiceClient(), "1234asdf", servers.UpdateOpts{
-		Name: "new-name",
-	})
-	config, err := ExtractUpdate(r)
-	th.AssertNoErr(t, err)
-	th.CheckEquals(t, Manual, *config)
-}
-
-func TestExtractRebuild(t *testing.T) {
-	th.SetupHTTP()
-	defer th.TeardownHTTP()
-	servers.HandleRebuildSuccessfully(t, servers.SingleServerBody)
-
-	r := servers.Rebuild(client.ServiceClient(), "1234asdf", servers.RebuildOpts{
-		Name:       "new-name",
-		AdminPass:  "swordfish",
-		ImageID:    "http://104.130.131.164:8774/fcad67a6189847c4aecfa3c81a05783b/images/f90f6034-2570-4974-8351-6b49732ef2eb",
-		AccessIPv4: "1.2.3.4",
-	})
-	config, err := ExtractRebuild(r)
-	th.AssertNoErr(t, err)
-	th.CheckEquals(t, Manual, *config)
-}
-
-func TestExtractList(t *testing.T) {
-	th.SetupHTTP()
-	defer th.TeardownHTTP()
-	servers.HandleServerListSuccessfully(t)
-
-	pages := 0
-	err := servers.List(client.ServiceClient(), nil).EachPage(func(page pagination.Page) (bool, error) {
-		pages++
-
-		config, err := ExtractDiskConfig(page, 0)
-		th.AssertNoErr(t, err)
-		th.CheckEquals(t, Manual, *config)
-
-		return true, nil
-	})
-	th.AssertNoErr(t, err)
-	th.CheckEquals(t, pages, 1)
-}
diff --git a/openstack/compute/v2/extensions/floatingip/doc.go b/openstack/compute/v2/extensions/floatingip/doc.go
deleted file mode 100644
index f74f58c..0000000
--- a/openstack/compute/v2/extensions/floatingip/doc.go
+++ /dev/null
@@ -1,3 +0,0 @@
-// Package floatingip provides the ability to manage floating ips through
-// nova-network
-package floatingip
diff --git a/openstack/compute/v2/extensions/floatingips/doc.go b/openstack/compute/v2/extensions/floatingips/doc.go
new file mode 100644
index 0000000..6682fa6
--- /dev/null
+++ b/openstack/compute/v2/extensions/floatingips/doc.go
@@ -0,0 +1,3 @@
+// Package floatingips provides the ability to manage floating ips through
+// nova-network
+package floatingips
diff --git a/openstack/compute/v2/extensions/floatingip/fixtures.go b/openstack/compute/v2/extensions/floatingips/fixtures.go
similarity index 97%
rename from openstack/compute/v2/extensions/floatingip/fixtures.go
rename to openstack/compute/v2/extensions/floatingips/fixtures.go
index a75e051..b369ea2 100644
--- a/openstack/compute/v2/extensions/floatingip/fixtures.go
+++ b/openstack/compute/v2/extensions/floatingips/fixtures.go
@@ -1,6 +1,6 @@
 // +build fixtures
 
-package floatingip
+package floatingips
 
 import (
 	"fmt"
@@ -17,14 +17,14 @@
     "floating_ips": [
         {
             "fixed_ip": null,
-            "id": 1,
+            "id": "1",
             "instance_id": null,
             "ip": "10.10.10.1",
             "pool": "nova"
         },
         {
             "fixed_ip": "166.78.185.201",
-            "id": 2,
+            "id": "2",
             "instance_id": "4d8c3732-a248-40ed-bebc-539a6ffd25c0",
             "ip": "10.10.10.2",
             "pool": "nova"
@@ -38,7 +38,7 @@
 {
     "floating_ip": {
         "fixed_ip": "166.78.185.201",
-        "id": 2,
+        "id": "2",
         "instance_id": "4d8c3732-a248-40ed-bebc-539a6ffd25c0",
         "ip": "10.10.10.2",
         "pool": "nova"
@@ -51,7 +51,7 @@
 {
     "floating_ip": {
         "fixed_ip": null,
-        "id": 1,
+        "id": "1",
         "instance_id": null,
         "ip": "10.10.10.1",
         "pool": "nova"
diff --git a/openstack/compute/v2/extensions/floatingip/requests.go b/openstack/compute/v2/extensions/floatingips/requests.go
similarity index 98%
rename from openstack/compute/v2/extensions/floatingip/requests.go
rename to openstack/compute/v2/extensions/floatingips/requests.go
index c6c0ea9..d99033e 100644
--- a/openstack/compute/v2/extensions/floatingip/requests.go
+++ b/openstack/compute/v2/extensions/floatingips/requests.go
@@ -1,4 +1,4 @@
-package floatingip
+package floatingips
 
 import (
 	"errors"
@@ -10,7 +10,7 @@
 // List returns a Pager that allows you to iterate over a collection of FloatingIPs.
 func List(client *gophercloud.ServiceClient) pagination.Pager {
 	return pagination.NewPager(client, listURL(client), func(r pagination.PageResult) pagination.Page {
-		return FloatingIPsPage{pagination.SinglePageBase(r)}
+		return FloatingIPPage{pagination.SinglePageBase(r)}
 	})
 }
 
diff --git a/openstack/compute/v2/extensions/floatingip/requests_test.go b/openstack/compute/v2/extensions/floatingips/requests_test.go
similarity index 99%
rename from openstack/compute/v2/extensions/floatingip/requests_test.go
rename to openstack/compute/v2/extensions/floatingips/requests_test.go
index df979f8..705c92f 100644
--- a/openstack/compute/v2/extensions/floatingip/requests_test.go
+++ b/openstack/compute/v2/extensions/floatingips/requests_test.go
@@ -1,4 +1,4 @@
-package floatingip
+package floatingips
 
 import (
 	"testing"
diff --git a/openstack/compute/v2/extensions/floatingip/results.go b/openstack/compute/v2/extensions/floatingips/results.go
similarity index 70%
rename from openstack/compute/v2/extensions/floatingip/results.go
rename to openstack/compute/v2/extensions/floatingips/results.go
index 1e115f4..c77ed77 100644
--- a/openstack/compute/v2/extensions/floatingip/results.go
+++ b/openstack/compute/v2/extensions/floatingips/results.go
@@ -1,7 +1,6 @@
-package floatingip
+package floatingips
 
 import (
-	"github.com/mitchellh/mapstructure"
 	"github.com/gophercloud/gophercloud"
 	"github.com/gophercloud/gophercloud/pagination"
 )
@@ -9,29 +8,29 @@
 // A FloatingIP is an IP that can be associated with an instance
 type FloatingIP struct {
 	// ID is a unique ID of the Floating IP
-	ID string `mapstructure:"id"`
+	ID string `json:"id"`
 
 	// FixedIP is the IP of the instance related to the Floating IP
-	FixedIP string `mapstructure:"fixed_ip,omitempty"`
+	FixedIP string `json:"fixed_ip,omitempty"`
 
 	// InstanceID is the ID of the instance that is using the Floating IP
-	InstanceID string `mapstructure:"instance_id"`
+	InstanceID string `json:"instance_id"`
 
 	// IP is the actual Floating IP
-	IP string `mapstructure:"ip"`
+	IP string `json:"ip"`
 
 	// Pool is the pool of floating IPs that this floating IP belongs to
-	Pool string `mapstructure:"pool"`
+	Pool string `json:"pool"`
 }
 
-// FloatingIPsPage stores a single, only page of FloatingIPs
+// FloatingIPPage stores a single, only page of FloatingIPs
 // results from a List call.
-type FloatingIPsPage struct {
+type FloatingIPPage struct {
 	pagination.SinglePageBase
 }
 
 // IsEmpty determines whether or not a FloatingIPsPage is empty.
-func (page FloatingIPsPage) IsEmpty() (bool, error) {
+func (page FloatingIPPage) IsEmpty() (bool, error) {
 	va, err := ExtractFloatingIPs(page)
 	return len(va) == 0, err
 }
@@ -39,16 +38,15 @@
 // ExtractFloatingIPs interprets a page of results as a slice of
 // FloatingIPs.
 func ExtractFloatingIPs(page pagination.Page) ([]FloatingIP, error) {
-	casted := page.(FloatingIPsPage).Body
-	var response struct {
-		FloatingIPs []FloatingIP `mapstructure:"floating_ips"`
+	r := page.(FloatingIPPage)
+	var s struct {
+		FloatingIPs []FloatingIP `json:"floating_ips"`
 	}
-
-	err := mapstructure.WeakDecode(casted, &response)
-
-	return response.FloatingIPs, err
+	err := r.ExtractInto(&s)
+	return s.FloatingIPs, err
 }
 
+// FloatingIPResult is the raw result from a FloatingIP request.
 type FloatingIPResult struct {
 	gophercloud.Result
 }
@@ -56,16 +54,11 @@
 // Extract is a method that attempts to interpret any FloatingIP resource
 // response as a FloatingIP struct.
 func (r FloatingIPResult) Extract() (*FloatingIP, error) {
-	if r.Err != nil {
-		return nil, r.Err
+	var s struct {
+		FloatingIP *FloatingIP `json:"floating_ip"`
 	}
-
-	var res struct {
-		FloatingIP *FloatingIP `json:"floating_ip" mapstructure:"floating_ip"`
-	}
-
-	err := mapstructure.WeakDecode(r.Body, &res)
-	return res.FloatingIP, err
+	err := r.ExtractInto(&s)
+	return s.FloatingIP, err
 }
 
 // CreateResult is the response from a Create operation. Call its Extract method to interpret it
diff --git a/openstack/compute/v2/extensions/floatingip/urls.go b/openstack/compute/v2/extensions/floatingips/urls.go
similarity index 97%
rename from openstack/compute/v2/extensions/floatingip/urls.go
rename to openstack/compute/v2/extensions/floatingips/urls.go
index 0d02413..f8181da 100644
--- a/openstack/compute/v2/extensions/floatingip/urls.go
+++ b/openstack/compute/v2/extensions/floatingips/urls.go
@@ -1,4 +1,4 @@
-package floatingip
+package floatingips
 
 import "github.com/gophercloud/gophercloud"
 
diff --git a/openstack/compute/v2/extensions/floatingip/urls_test.go b/openstack/compute/v2/extensions/floatingips/urls_test.go
similarity index 98%
rename from openstack/compute/v2/extensions/floatingip/urls_test.go
rename to openstack/compute/v2/extensions/floatingips/urls_test.go
index 5c62a80..ff1489e 100644
--- a/openstack/compute/v2/extensions/floatingip/urls_test.go
+++ b/openstack/compute/v2/extensions/floatingips/urls_test.go
@@ -1,4 +1,4 @@
-package floatingip
+package floatingips
 
 import (
 	"testing"
diff --git a/openstack/compute/v2/extensions/keypairs/results.go b/openstack/compute/v2/extensions/keypairs/results.go
index 58a51d2..2b40943 100644
--- a/openstack/compute/v2/extensions/keypairs/results.go
+++ b/openstack/compute/v2/extensions/keypairs/results.go
@@ -1,7 +1,6 @@
 package keypairs
 
 import (
-	"github.com/mitchellh/mapstructure"
 	"github.com/gophercloud/gophercloud"
 	"github.com/gophercloud/gophercloud/pagination"
 )
@@ -10,22 +9,22 @@
 // servers.
 type KeyPair struct {
 	// Name is used to refer to this keypair from other services within this region.
-	Name string `mapstructure:"name"`
+	Name string `json:"name"`
 
 	// Fingerprint is a short sequence of bytes that can be used to authenticate or validate a longer
 	// public key.
-	Fingerprint string `mapstructure:"fingerprint"`
+	Fingerprint string `json:"fingerprint"`
 
 	// PublicKey is the public key from this pair, in OpenSSH format. "ssh-rsa AAAAB3Nz..."
-	PublicKey string `mapstructure:"public_key"`
+	PublicKey string `json:"public_key"`
 
 	// PrivateKey is the private key from this pair, in PEM format.
 	// "-----BEGIN RSA PRIVATE KEY-----\nMIICXA..." It is only present if this keypair was just
 	// returned from a Create call
-	PrivateKey string `mapstructure:"private_key"`
+	PrivateKey string `json:"private_key"`
 
 	// UserID is the user who owns this keypair.
-	UserID string `mapstructure:"user_id"`
+	UserID string `json:"user_id"`
 }
 
 // KeyPairPage stores a single, only page of KeyPair results from a List call.
@@ -41,17 +40,16 @@
 
 // ExtractKeyPairs interprets a page of results as a slice of KeyPairs.
 func ExtractKeyPairs(page pagination.Page) ([]KeyPair, error) {
+	r := page.(KeyPairPage)
 	type pair struct {
-		KeyPair KeyPair `mapstructure:"keypair"`
+		KeyPair KeyPair `json:"keypair"`
 	}
-
-	var resp struct {
-		KeyPairs []pair `mapstructure:"keypairs"`
+	var s struct {
+		KeyPairs []pair `json:"keypairs"`
 	}
-
-	err := mapstructure.Decode(page.(KeyPairPage).Body, &resp)
-	results := make([]KeyPair, len(resp.KeyPairs))
-	for i, pair := range resp.KeyPairs {
+	err := r.ExtractInto(&s)
+	results := make([]KeyPair, len(s.KeyPairs))
+	for i, pair := range s.KeyPairs {
 		results[i] = pair.KeyPair
 	}
 	return results, err
@@ -63,16 +61,11 @@
 
 // Extract is a method that attempts to interpret any KeyPair resource response as a KeyPair struct.
 func (r keyPairResult) Extract() (*KeyPair, error) {
-	if r.Err != nil {
-		return nil, r.Err
+	var s struct {
+		KeyPair *KeyPair `json:"keypair"`
 	}
-
-	var res struct {
-		KeyPair *KeyPair `json:"keypair" mapstructure:"keypair"`
-	}
-
-	err := mapstructure.Decode(r.Body, &res)
-	return res.KeyPair, err
+	err := r.ExtractInto(&s)
+	return s.KeyPair, err
 }
 
 // CreateResult is the response from a Create operation. Call its Extract method to interpret it
diff --git a/openstack/compute/v2/extensions/networks/fixtures.go b/openstack/compute/v2/extensions/networks/fixtures.go
index f94f331..ffa4282 100644
--- a/openstack/compute/v2/extensions/networks/fixtures.go
+++ b/openstack/compute/v2/extensions/networks/fixtures.go
@@ -8,6 +8,7 @@
 	"testing"
 	"time"
 
+	"github.com/gophercloud/gophercloud"
 	th "github.com/gophercloud/gophercloud/testhelper"
 	"github.com/gophercloud/gophercloud/testhelper/client"
 )
@@ -22,9 +23,8 @@
             "broadcast": "10.0.0.7",
             "cidr": "10.0.0.0/29",
             "cidr_v6": null,
-            "created_at": "2011-08-15 06:19:19.387525",
+            "created_at": "2011-08-15T06:19:19.387525",
             "deleted": false,
-            "deleted_at": null,
             "dhcp_start": "10.0.0.3",
             "dns1": null,
             "dns2": null,
@@ -40,7 +40,7 @@
             "priority": null,
             "project_id": "1234",
             "rxtx_base": null,
-            "updated_at": "2011-08-16 09:26:13.048257",
+            "updated_at": "2011-08-16T09:26:13.048257",
             "vlan": 100,
             "vpn_private_address": "10.0.0.2",
             "vpn_public_address": "127.0.0.1",
@@ -52,9 +52,8 @@
             "broadcast": "10.0.0.15",
             "cidr": "10.0.0.10/29",
             "cidr_v6": null,
-            "created_at": "2011-08-15 06:19:19.885495",
+            "created_at": "2011-08-15T06:19:19.387525",
             "deleted": false,
-            "deleted_at": null,
             "dhcp_start": "10.0.0.11",
             "dns1": null,
             "dns2": null,
@@ -70,7 +69,6 @@
             "priority": null,
             "project_id": null,
             "rxtx_base": null,
-            "updated_at": null,
             "vlan": 101,
             "vpn_private_address": "10.0.0.10",
             "vpn_public_address": null,
@@ -89,9 +87,8 @@
 			"broadcast": "10.0.0.15",
 			"cidr": "10.0.0.10/29",
 			"cidr_v6": null,
-			"created_at": "2011-08-15 06:19:19.885495",
+			"created_at": "2011-08-15T06:19:19.387525",
 			"deleted": false,
-			"deleted_at": null,
 			"dhcp_start": "10.0.0.11",
 			"dns1": null,
 			"dns2": null,
@@ -107,7 +104,6 @@
 			"priority": null,
 			"project_id": null,
 			"rxtx_base": null,
-			"updated_at": null,
 			"vlan": 101,
 			"vpn_private_address": "10.0.0.10",
 			"vpn_public_address": null,
@@ -124,9 +120,9 @@
 	Broadcast:         "10.0.0.7",
 	CIDR:              "10.0.0.0/29",
 	CIDRv6:            "",
-	CreatedAt:         time.Date(2011, 8, 15, 6, 19, 19, 387525000, time.UTC),
+	CreatedAt:         gophercloud.JSONRFC3339MilliNoZ(time.Date(2011, 8, 15, 6, 19, 19, 387525000, time.UTC)),
 	Deleted:           false,
-	DeletedAt:         nilTime,
+	DeletedAt:         gophercloud.JSONRFC3339MilliNoZ(nilTime),
 	DHCPStart:         "10.0.0.3",
 	DNS1:              "",
 	DNS2:              "",
@@ -142,7 +138,7 @@
 	Priority:          0,
 	ProjectID:         "1234",
 	RXTXBase:          0,
-	UpdatedAt:         time.Date(2011, 8, 16, 9, 26, 13, 48257000, time.UTC),
+	UpdatedAt:         gophercloud.JSONRFC3339MilliNoZ(time.Date(2011, 8, 16, 9, 26, 13, 48257000, time.UTC)),
 	VLAN:              100,
 	VPNPrivateAddress: "10.0.0.2",
 	VPNPublicAddress:  "127.0.0.1",
@@ -156,9 +152,9 @@
 	Broadcast:         "10.0.0.15",
 	CIDR:              "10.0.0.10/29",
 	CIDRv6:            "",
-	CreatedAt:         time.Date(2011, 8, 15, 6, 19, 19, 885495000, time.UTC),
+	CreatedAt:         gophercloud.JSONRFC3339MilliNoZ(time.Date(2011, 8, 15, 6, 19, 19, 387525000, time.UTC)),
 	Deleted:           false,
-	DeletedAt:         nilTime,
+	DeletedAt:         gophercloud.JSONRFC3339MilliNoZ(nilTime),
 	DHCPStart:         "10.0.0.11",
 	DNS1:              "",
 	DNS2:              "",
@@ -174,7 +170,7 @@
 	Priority:          0,
 	ProjectID:         "",
 	RXTXBase:          0,
-	UpdatedAt:         nilTime,
+	UpdatedAt:         gophercloud.JSONRFC3339MilliNoZ(nilTime),
 	VLAN:              101,
 	VPNPrivateAddress: "10.0.0.10",
 	VPNPublicAddress:  "",
diff --git a/openstack/compute/v2/extensions/networks/results.go b/openstack/compute/v2/extensions/networks/results.go
index 3ed7c68..d9b746e 100644
--- a/openstack/compute/v2/extensions/networks/results.go
+++ b/openstack/compute/v2/extensions/networks/results.go
@@ -1,10 +1,6 @@
 package networks
 
 import (
-	"fmt"
-	"time"
-
-	"github.com/mitchellh/mapstructure"
 	"github.com/gophercloud/gophercloud"
 	"github.com/gophercloud/gophercloud/pagination"
 )
@@ -12,88 +8,88 @@
 // A Network represents a nova-network that an instance communicates on
 type Network struct {
 	// The Bridge that VIFs on this network are connected to
-	Bridge string `mapstructure:"bridge"`
+	Bridge string `json:"bridge"`
 
 	// BridgeInterface is what interface is connected to the Bridge
-	BridgeInterface string `mapstructure:"bridge_interface"`
+	BridgeInterface string `json:"bridge_interface"`
 
 	// The Broadcast address of the network.
-	Broadcast string `mapstructure:"broadcast"`
+	Broadcast string `json:"broadcast"`
 
 	// CIDR is the IPv4 subnet.
-	CIDR string `mapstructure:"cidr"`
+	CIDR string `json:"cidr"`
 
 	// CIDRv6 is the IPv6 subnet.
-	CIDRv6 string `mapstructure:"cidr_v6"`
+	CIDRv6 string `json:"cidr_v6"`
 
 	// CreatedAt is when the network was created..
-	CreatedAt time.Time `mapstructure:"-"`
+	CreatedAt gophercloud.JSONRFC3339MilliNoZ `json:"created_at,omitempty"`
 
 	// Deleted shows if the network has been deleted.
-	Deleted bool `mapstructure:"deleted"`
+	Deleted bool `json:"deleted"`
 
 	// DeletedAt is the time when the network was deleted.
-	DeletedAt time.Time `mapstructure:"-"`
+	DeletedAt gophercloud.JSONRFC3339MilliNoZ `json:"deleted_at,omitempty"`
 
 	// DHCPStart is the start of the DHCP address range.
-	DHCPStart string `mapstructure:"dhcp_start"`
+	DHCPStart string `json:"dhcp_start"`
 
 	// DNS1 is the first DNS server to use through DHCP.
-	DNS1 string `mapstructure:"dns_1"`
+	DNS1 string `json:"dns_1"`
 
 	// DNS2 is the first DNS server to use through DHCP.
-	DNS2 string `mapstructure:"dns_2"`
+	DNS2 string `json:"dns_2"`
 
 	// Gateway is the network gateway.
-	Gateway string `mapstructure:"gateway"`
+	Gateway string `json:"gateway"`
 
 	// Gatewayv6 is the IPv6 network gateway.
-	Gatewayv6 string `mapstructure:"gateway_v6"`
+	Gatewayv6 string `json:"gateway_v6"`
 
 	// Host is the host that the network service is running on.
-	Host string `mapstructure:"host"`
+	Host string `json:"host"`
 
 	// ID is the UUID of the network.
-	ID string `mapstructure:"id"`
+	ID string `json:"id"`
 
 	// Injected determines if network information is injected into the host.
-	Injected bool `mapstructure:"injected"`
+	Injected bool `json:"injected"`
 
 	// Label is the common name that the network has..
-	Label string `mapstructure:"label"`
+	Label string `json:"label"`
 
 	// MultiHost is if multi-host networking is enablec..
-	MultiHost bool `mapstructure:"multi_host"`
+	MultiHost bool `json:"multi_host"`
 
 	// Netmask is the network netmask.
-	Netmask string `mapstructure:"netmask"`
+	Netmask string `json:"netmask"`
 
 	// Netmaskv6 is the IPv6 netmask.
-	Netmaskv6 string `mapstructure:"netmask_v6"`
+	Netmaskv6 string `json:"netmask_v6"`
 
 	// Priority is the network interface priority.
-	Priority int `mapstructure:"priority"`
+	Priority int `json:"priority"`
 
 	// ProjectID is the project associated with this network.
-	ProjectID string `mapstructure:"project_id"`
+	ProjectID string `json:"project_id"`
 
 	// RXTXBase configures bandwidth entitlement.
-	RXTXBase int `mapstructure:"rxtx_base"`
+	RXTXBase int `json:"rxtx_base"`
 
 	// UpdatedAt is the time when the network was last updated.
-	UpdatedAt time.Time `mapstructure:"-"`
+	UpdatedAt gophercloud.JSONRFC3339MilliNoZ `json:"updated_at,omitempty"`
 
 	// VLAN is the vlan this network runs on.
-	VLAN int `mapstructure:"vlan"`
+	VLAN int `json:"vlan"`
 
 	// VPNPrivateAddress is the private address of the CloudPipe VPN.
-	VPNPrivateAddress string `mapstructure:"vpn_private_address"`
+	VPNPrivateAddress string `json:"vpn_private_address"`
 
 	// VPNPublicAddress is the public address of the CloudPipe VPN.
-	VPNPublicAddress string `mapstructure:"vpn_public_address"`
+	VPNPublicAddress string `json:"vpn_public_address"`
 
 	// VPNPublicPort is the port of the CloudPipe VPN.
-	VPNPublicPort int `mapstructure:"vpn_public_port"`
+	VPNPublicPort int `json:"vpn_public_port"`
 }
 
 // NetworkPage stores a single, only page of Networks
@@ -110,51 +106,12 @@
 
 // ExtractNetworks interprets a page of results as a slice of Networks
 func ExtractNetworks(page pagination.Page) ([]Network, error) {
-	var res struct {
-		Networks []Network `mapstructure:"networks"`
+	r := page.(NetworkPage)
+	var s struct {
+		Networks []Network `json:"networks"`
 	}
-
-	err := mapstructure.Decode(page.(NetworkPage).Body, &res)
-
-	var rawNetworks []interface{}
-	body := page.(NetworkPage).Body
-	switch body.(type) {
-	case map[string]interface{}:
-		rawNetworks = body.(map[string]interface{})["networks"].([]interface{})
-	case map[string][]interface{}:
-		rawNetworks = body.(map[string][]interface{})["networks"]
-	default:
-		return res.Networks, fmt.Errorf("Unknown type")
-	}
-
-	for i := range rawNetworks {
-		thisNetwork := rawNetworks[i].(map[string]interface{})
-		if t, ok := thisNetwork["created_at"].(string); ok && t != "" {
-			createdAt, err := time.Parse("2006-01-02 15:04:05.000000", t)
-			if err != nil {
-				return res.Networks, err
-			}
-			res.Networks[i].CreatedAt = createdAt
-		}
-
-		if t, ok := thisNetwork["updated_at"].(string); ok && t != "" {
-			updatedAt, err := time.Parse("2006-01-02 15:04:05.000000", t)
-			if err != nil {
-				return res.Networks, err
-			}
-			res.Networks[i].UpdatedAt = updatedAt
-		}
-
-		if t, ok := thisNetwork["deleted_at"].(string); ok && t != "" {
-			deletedAt, err := time.Parse("2006-01-02 15:04:05.000000", t)
-			if err != nil {
-				return res.Networks, err
-			}
-			res.Networks[i].DeletedAt = deletedAt
-		}
-	}
-
-	return res.Networks, err
+	err := r.ExtractInto(&s)
+	return s.Networks, err
 }
 
 type NetworkResult struct {
@@ -164,55 +121,11 @@
 // Extract is a method that attempts to interpret any Network resource
 // response as a Network struct.
 func (r NetworkResult) Extract() (*Network, error) {
-	if r.Err != nil {
-		return nil, r.Err
+	var s struct {
+		Network *Network `json:"network"`
 	}
-
-	var res struct {
-		Network *Network `json:"network" mapstructure:"network"`
-	}
-
-	config := &mapstructure.DecoderConfig{
-		Result:           &res,
-		WeaklyTypedInput: true,
-	}
-	decoder, err := mapstructure.NewDecoder(config)
-	if err != nil {
-		return nil, err
-	}
-
-	if err := decoder.Decode(r.Body); err != nil {
-		return nil, err
-	}
-
-	b := r.Body.(map[string]interface{})["network"].(map[string]interface{})
-
-	if t, ok := b["created_at"].(string); ok && t != "" {
-		createdAt, err := time.Parse("2006-01-02 15:04:05.000000", t)
-		if err != nil {
-			return res.Network, err
-		}
-		res.Network.CreatedAt = createdAt
-	}
-
-	if t, ok := b["updated_at"].(string); ok && t != "" {
-		updatedAt, err := time.Parse("2006-01-02 15:04:05.000000", t)
-		if err != nil {
-			return res.Network, err
-		}
-		res.Network.UpdatedAt = updatedAt
-	}
-
-	if t, ok := b["deleted_at"].(string); ok && t != "" {
-		deletedAt, err := time.Parse("2006-01-02 15:04:05.000000", t)
-		if err != nil {
-			return res.Network, err
-		}
-		res.Network.DeletedAt = deletedAt
-	}
-
-	return res.Network, err
-
+	err := r.ExtractInto(&s)
+	return s.Network, err
 }
 
 // GetResult is the response from a Get operation. Call its Extract method to interpret it
diff --git a/openstack/compute/v2/extensions/schedulerhints/requests_test.go b/openstack/compute/v2/extensions/schedulerhints/requests_test.go
index 4e7c190..605b72b 100644
--- a/openstack/compute/v2/extensions/schedulerhints/requests_test.go
+++ b/openstack/compute/v2/extensions/schedulerhints/requests_test.go
@@ -39,9 +39,7 @@
 			"server": {
 				"name": "createdserver",
 				"imageRef": "asdfasdfasdf",
-				"flavorRef": "performance1-1",
-				"flavorName": "",
-				"imageName": ""
+				"flavorRef": "performance1-1"
 			},
 			"os:scheduler_hints": {
 				"group": "101aed42-22d9-4a3e-9ba1-21103b0d1aba",
@@ -99,9 +97,7 @@
 			"server": {
 				"name": "createdserver",
 				"imageRef": "asdfasdfasdf",
-				"flavorRef": "performance1-1",
-				"flavorName": "",
-				"imageName": ""
+				"flavorRef": "performance1-1"
 			},
 			"os:scheduler_hints": {
 				"group": "101aed42-22d9-4a3e-9ba1-21103b0d1aba",
diff --git a/openstack/compute/v2/extensions/secgroups/fixtures.go b/openstack/compute/v2/extensions/secgroups/fixtures.go
index 0667b00..0f97ac8 100644
--- a/openstack/compute/v2/extensions/secgroups/fixtures.go
+++ b/openstack/compute/v2/extensions/secgroups/fixtures.go
@@ -163,7 +163,7 @@
 		fmt.Fprintf(w, `
 {
 	"security_group": {
-		"id": 12345
+		"id": "12345"
 	}
 }
 			`)
diff --git a/openstack/compute/v2/extensions/secgroups/results.go b/openstack/compute/v2/extensions/secgroups/results.go
index d7d0936..5e18c0b 100644
--- a/openstack/compute/v2/extensions/secgroups/results.go
+++ b/openstack/compute/v2/extensions/secgroups/results.go
@@ -1,8 +1,6 @@
 package secgroups
 
 import (
-	"github.com/mitchellh/mapstructure"
-
 	"github.com/gophercloud/gophercloud"
 	"github.com/gophercloud/gophercloud/pagination"
 )
@@ -24,7 +22,7 @@
 	Rules []Rule
 
 	// The ID of the tenant to which this security group belongs.
-	TenantID string `mapstructure:"tenant_id"`
+	TenantID string `json:"tenant_id"`
 }
 
 // Rule represents a security group rule, a policy which determines how a
@@ -36,19 +34,19 @@
 	ID string
 
 	// The lower bound of the port range which this security group should open up
-	FromPort int `mapstructure:"from_port"`
+	FromPort int `json:"from_port"`
 
 	// The upper bound of the port range which this security group should open up
-	ToPort int `mapstructure:"to_port"`
+	ToPort int `json:"to_port"`
 
 	// The IP protocol (e.g. TCP) which the security group accepts
-	IPProtocol string `mapstructure:"ip_protocol"`
+	IPProtocol string `json:"ip_protocol"`
 
 	// The CIDR IP range whose traffic can be received
-	IPRange IPRange `mapstructure:"ip_range"`
+	IPRange IPRange `json:"ip_range"`
 
 	// The security group ID to which this rule belongs
-	ParentGroupID string `mapstructure:"parent_group_id"`
+	ParentGroupID string `json:"parent_group_id"`
 
 	// Not documented.
 	Group Group
@@ -62,7 +60,7 @@
 
 // Group represents a group.
 type Group struct {
-	TenantID string `mapstructure:"tenant_id"`
+	TenantID string `json:"tenant_id"`
 	Name     string
 }
 
@@ -74,22 +72,17 @@
 // IsEmpty determines whether or not a page of Security Groups contains any results.
 func (page SecurityGroupPage) IsEmpty() (bool, error) {
 	users, err := ExtractSecurityGroups(page)
-	if err != nil {
-		return false, err
-	}
-	return len(users) == 0, nil
+	return len(users) == 0, err
 }
 
 // ExtractSecurityGroups returns a slice of SecurityGroups contained in a single page of results.
 func ExtractSecurityGroups(page pagination.Page) ([]SecurityGroup, error) {
-	casted := page.(SecurityGroupPage).Body
-	var response struct {
-		SecurityGroups []SecurityGroup `mapstructure:"security_groups"`
+	r := page.(SecurityGroupPage)
+	var s struct {
+		SecurityGroups []SecurityGroup `json:"security_groups"`
 	}
-
-	err := mapstructure.WeakDecode(casted, &response)
-
-	return response.SecurityGroups, err
+	err := r.ExtractInto(&s)
+	return s.SecurityGroups, err
 }
 
 type commonResult struct {
@@ -113,17 +106,11 @@
 
 // Extract will extract a SecurityGroup struct from most responses.
 func (r commonResult) Extract() (*SecurityGroup, error) {
-	if r.Err != nil {
-		return nil, r.Err
+	var s struct {
+		SecurityGroup *SecurityGroup `json:"security_group"`
 	}
-
-	var response struct {
-		SecurityGroup SecurityGroup `mapstructure:"security_group"`
-	}
-
-	err := mapstructure.WeakDecode(r.Body, &response)
-
-	return &response.SecurityGroup, err
+	err := r.ExtractInto(&s)
+	return s.SecurityGroup, err
 }
 
 // CreateRuleResult represents the result when adding rules to a security group.
@@ -133,15 +120,9 @@
 
 // Extract will extract a Rule struct from a CreateRuleResult.
 func (r CreateRuleResult) Extract() (*Rule, error) {
-	if r.Err != nil {
-		return nil, r.Err
+	var s struct {
+		Rule *Rule `json:"security_group_rule"`
 	}
-
-	var response struct {
-		Rule Rule `mapstructure:"security_group_rule"`
-	}
-
-	err := mapstructure.WeakDecode(r.Body, &response)
-
-	return &response.Rule, err
+	err := r.ExtractInto(&s)
+	return s.Rule, err
 }
diff --git a/openstack/compute/v2/extensions/servergroups/requests.go b/openstack/compute/v2/extensions/servergroups/requests.go
index 02e6de2..e3b2493 100644
--- a/openstack/compute/v2/extensions/servergroups/requests.go
+++ b/openstack/compute/v2/extensions/servergroups/requests.go
@@ -10,7 +10,7 @@
 // List returns a Pager that allows you to iterate over a collection of ServerGroups.
 func List(client *gophercloud.ServiceClient) pagination.Pager {
 	return pagination.NewPager(client, listURL(client), func(r pagination.PageResult) pagination.Page {
-		return ServerGroupsPage{pagination.SinglePageBase(r)}
+		return ServerGroupPage{pagination.SinglePageBase(r)}
 	})
 }
 
diff --git a/openstack/compute/v2/extensions/servergroups/results.go b/openstack/compute/v2/extensions/servergroups/results.go
index 2b59551..ff64a7e 100644
--- a/openstack/compute/v2/extensions/servergroups/results.go
+++ b/openstack/compute/v2/extensions/servergroups/results.go
@@ -1,7 +1,6 @@
 package servergroups
 
 import (
-	"github.com/mitchellh/mapstructure"
 	"github.com/gophercloud/gophercloud"
 	"github.com/gophercloud/gophercloud/pagination"
 )
@@ -9,29 +8,29 @@
 // A ServerGroup creates a policy for instance placement in the cloud
 type ServerGroup struct {
 	// ID is the unique ID of the Server Group.
-	ID string `mapstructure:"id"`
+	ID string `json:"id"`
 
 	// Name is the common name of the server group.
-	Name string `mapstructure:"name"`
+	Name string `json:"name"`
 
 	// Polices are the group policies.
-	Policies []string `mapstructure:"policies"`
+	Policies []string `json:"policies"`
 
 	// Members are the members of the server group.
-	Members []string `mapstructure:"members"`
+	Members []string `json:"members"`
 
 	// Metadata includes a list of all user-specified key-value pairs attached to the Server Group.
 	Metadata map[string]interface{}
 }
 
-// ServerGroupsPage stores a single, only page of ServerGroups
+// ServerGroupPage stores a single, only page of ServerGroups
 // results from a List call.
-type ServerGroupsPage struct {
+type ServerGroupPage struct {
 	pagination.SinglePageBase
 }
 
 // IsEmpty determines whether or not a ServerGroupsPage is empty.
-func (page ServerGroupsPage) IsEmpty() (bool, error) {
+func (page ServerGroupPage) IsEmpty() (bool, error) {
 	va, err := ExtractServerGroups(page)
 	return len(va) == 0, err
 }
@@ -39,14 +38,12 @@
 // ExtractServerGroups interprets a page of results as a slice of
 // ServerGroups.
 func ExtractServerGroups(page pagination.Page) ([]ServerGroup, error) {
-	casted := page.(ServerGroupsPage).Body
-	var response struct {
-		ServerGroups []ServerGroup `mapstructure:"server_groups"`
+	r := page.(ServerGroupPage)
+	var s struct {
+		ServerGroups []ServerGroup `json:"server_groups"`
 	}
-
-	err := mapstructure.WeakDecode(casted, &response)
-
-	return response.ServerGroups, err
+	err := r.ExtractInto(&s)
+	return s.ServerGroups, err
 }
 
 type ServerGroupResult struct {
@@ -56,16 +53,11 @@
 // Extract is a method that attempts to interpret any Server Group resource
 // response as a ServerGroup struct.
 func (r ServerGroupResult) Extract() (*ServerGroup, error) {
-	if r.Err != nil {
-		return nil, r.Err
+	var s struct {
+		ServerGroup *ServerGroup `json:"server_group"`
 	}
-
-	var res struct {
-		ServerGroup *ServerGroup `json:"server_group" mapstructure:"server_group"`
-	}
-
-	err := mapstructure.WeakDecode(r.Body, &res)
-	return res.ServerGroup, err
+	err := r.ExtractInto(&s)
+	return s.ServerGroup, err
 }
 
 // CreateResult is the response from a Create operation. Call its Extract method to interpret it
diff --git a/openstack/compute/v2/extensions/tenantnetworks/results.go b/openstack/compute/v2/extensions/tenantnetworks/results.go
index f55a27e..5db5cbd 100644
--- a/openstack/compute/v2/extensions/tenantnetworks/results.go
+++ b/openstack/compute/v2/extensions/tenantnetworks/results.go
@@ -1,7 +1,6 @@
 package tenantnetworks
 
 import (
-	"github.com/mitchellh/mapstructure"
 	"github.com/gophercloud/gophercloud"
 	"github.com/gophercloud/gophercloud/pagination"
 )
@@ -9,13 +8,13 @@
 // A Network represents a nova-network that an instance communicates on
 type Network struct {
 	// CIDR is the IPv4 subnet.
-	CIDR string `mapstructure:"cidr"`
+	CIDR string `json:"cidr"`
 
 	// ID is the UUID of the network.
-	ID string `mapstructure:"id"`
+	ID string `json:"id"`
 
 	// Name is the common name that the network has.
-	Name string `mapstructure:"label"`
+	Name string `json:"label"`
 }
 
 // NetworkPage stores a single, only page of Networks
@@ -32,14 +31,12 @@
 
 // ExtractNetworks interprets a page of results as a slice of Networks
 func ExtractNetworks(page pagination.Page) ([]Network, error) {
-	networks := page.(NetworkPage).Body
-	var res struct {
-		Networks []Network `mapstructure:"networks"`
+	r := page.(NetworkPage)
+	var s struct {
+		Networks []Network `json:"networks"`
 	}
-
-	err := mapstructure.WeakDecode(networks, &res)
-
-	return res.Networks, err
+	err := r.ExtractInto(&s)
+	return s.Networks, err
 }
 
 type NetworkResult struct {
@@ -49,16 +46,11 @@
 // Extract is a method that attempts to interpret any Network resource
 // response as a Network struct.
 func (r NetworkResult) Extract() (*Network, error) {
-	if r.Err != nil {
-		return nil, r.Err
+	var s struct {
+		Network *Network `json:"network"`
 	}
-
-	var res struct {
-		Network *Network `json:"network" mapstructure:"network"`
-	}
-
-	err := mapstructure.Decode(r.Body, &res)
-	return res.Network, err
+	err := r.ExtractInto(&s)
+	return s.Network, err
 }
 
 // GetResult is the response from a Get operation. Call its Extract method to interpret it
diff --git a/openstack/compute/v2/extensions/volumeattach/results.go b/openstack/compute/v2/extensions/volumeattach/results.go
index 76aeee7..62e7398 100644
--- a/openstack/compute/v2/extensions/volumeattach/results.go
+++ b/openstack/compute/v2/extensions/volumeattach/results.go
@@ -1,24 +1,23 @@
 package volumeattach
 
 import (
-	"github.com/mitchellh/mapstructure"
 	"github.com/gophercloud/gophercloud"
 	"github.com/gophercloud/gophercloud/pagination"
 )
 
-// VolumeAttach controls the attachment of a volume to an instance.
+// VolumeAttachment controls the attachment of a volume to an instance.
 type VolumeAttachment struct {
 	// ID is a unique id of the attachment
-	ID string `mapstructure:"id"`
+	ID string `json:"id"`
 
 	// Device is what device the volume is attached as
-	Device string `mapstructure:"device"`
+	Device string `json:"device"`
 
 	// VolumeID is the ID of the attached volume
-	VolumeID string `mapstructure:"volumeId"`
+	VolumeID string `json:"volumeId"`
 
 	// ServerID is the ID of the instance that has the volume attached
-	ServerID string `mapstructure:"serverId"`
+	ServerID string `json:"serverId"`
 }
 
 // VolumeAttachmentsPage stores a single, only page of VolumeAttachments
@@ -36,14 +35,12 @@
 // ExtractVolumeAttachments interprets a page of results as a slice of
 // VolumeAttachments.
 func ExtractVolumeAttachments(page pagination.Page) ([]VolumeAttachment, error) {
-	casted := page.(VolumeAttachmentsPage).Body
-	var response struct {
-		VolumeAttachments []VolumeAttachment `mapstructure:"volumeAttachments"`
+	r := page.(VolumeAttachmentsPage)
+	var s struct {
+		VolumeAttachments []VolumeAttachment `json:"volumeAttachments"`
 	}
-
-	err := mapstructure.WeakDecode(casted, &response)
-
-	return response.VolumeAttachments, err
+	err := r.ExtractInto(&s)
+	return s.VolumeAttachments, err
 }
 
 type VolumeAttachmentResult struct {
@@ -53,16 +50,11 @@
 // Extract is a method that attempts to interpret any VolumeAttachment resource
 // response as a VolumeAttachment struct.
 func (r VolumeAttachmentResult) Extract() (*VolumeAttachment, error) {
-	if r.Err != nil {
-		return nil, r.Err
+	var s struct {
+		VolumeAttachment *VolumeAttachment `json:"volumeAttachment"`
 	}
-
-	var res struct {
-		VolumeAttachment *VolumeAttachment `json:"volumeAttachment" mapstructure:"volumeAttachment"`
-	}
-
-	err := mapstructure.Decode(r.Body, &res)
-	return res.VolumeAttachment, err
+	err := r.ExtractInto(&s)
+	return s.VolumeAttachment, err
 }
 
 // CreateResult is the response from a Create operation. Call its Extract method to interpret it
diff --git a/openstack/compute/v2/flavors/results.go b/openstack/compute/v2/flavors/results.go
index 785cbe2..3f14e76 100644
--- a/openstack/compute/v2/flavors/results.go
+++ b/openstack/compute/v2/flavors/results.go
@@ -2,9 +2,7 @@
 
 import (
 	"errors"
-	"reflect"
 
-	"github.com/mitchellh/mapstructure"
 	"github.com/gophercloud/gophercloud"
 	"github.com/gophercloud/gophercloud/pagination"
 )
@@ -18,48 +16,35 @@
 }
 
 // Extract provides access to the individual Flavor returned by the Get function.
-func (gr GetResult) Extract() (*Flavor, error) {
-	if gr.Err != nil {
-		return nil, gr.Err
+func (r GetResult) Extract() (*Flavor, error) {
+	var s struct {
+		Flavor *Flavor `json:"flavor"`
 	}
-
-	var result struct {
-		Flavor Flavor `mapstructure:"flavor"`
-	}
-
-	cfg := &mapstructure.DecoderConfig{
-		DecodeHook: defaulter,
-		Result:     &result,
-	}
-	decoder, err := mapstructure.NewDecoder(cfg)
-	if err != nil {
-		return nil, err
-	}
-	err = decoder.Decode(gr.Body)
-	return &result.Flavor, err
+	err := r.ExtractInto(&s)
+	return s.Flavor, err
 }
 
 // Flavor records represent (virtual) hardware configurations for server resources in a region.
 type Flavor struct {
 	// The Id field contains the flavor's unique identifier.
 	// For example, this identifier will be useful when specifying which hardware configuration to use for a new server instance.
-	ID string `mapstructure:"id"`
+	ID string `json:"id"`
 
 	// The Disk and RA< fields provide a measure of storage space offered by the flavor, in GB and MB, respectively.
-	Disk int `mapstructure:"disk"`
-	RAM  int `mapstructure:"ram"`
+	Disk int `json:"disk"`
+	RAM  int `json:"ram"`
 
 	// The Name field provides a human-readable moniker for the flavor.
-	Name string `mapstructure:"name"`
+	Name string `json:"name"`
 
-	RxTxFactor float64 `mapstructure:"rxtx_factor"`
+	RxTxFactor float64 `json:"rxtx_factor"`
 
 	// Swap indicates how much space is reserved for swap.
 	// If not provided, this field will be set to 0.
-	Swap int `mapstructure:"swap"`
+	Swap int `json:"swap"`
 
 	// VCPUs indicates how many (virtual) CPUs are available for this flavor.
-	VCPUs int `mapstructure:"vcpus"`
+	VCPUs int `json:"vcpus"`
 }
 
 // FlavorPage contains a single page of the response from a List call.
@@ -68,55 +53,29 @@
 }
 
 // IsEmpty determines if a page contains any results.
-func (p FlavorPage) IsEmpty() (bool, error) {
-	flavors, err := ExtractFlavors(p)
-	if err != nil {
-		return true, err
-	}
-	return len(flavors) == 0, nil
+func (page FlavorPage) IsEmpty() (bool, error) {
+	flavors, err := ExtractFlavors(page)
+	return len(flavors) == 0, err
 }
 
 // NextPageURL uses the response's embedded link reference to navigate to the next page of results.
-func (p FlavorPage) NextPageURL() (string, error) {
-	type resp struct {
-		Links []gophercloud.Link `mapstructure:"flavors_links"`
+func (page FlavorPage) NextPageURL() (string, error) {
+	var s struct {
+		Links []gophercloud.Link `json:"flavors_links"`
 	}
-
-	var r resp
-	err := mapstructure.Decode(p.Body, &r)
+	err := page.ExtractInto(&s)
 	if err != nil {
 		return "", err
 	}
-
-	return gophercloud.ExtractNextURL(r.Links)
-}
-
-func defaulter(from, to reflect.Kind, v interface{}) (interface{}, error) {
-	if (from == reflect.String) && (to == reflect.Int) {
-		return 0, nil
-	}
-	return v, nil
+	return gophercloud.ExtractNextURL(s.Links)
 }
 
 // ExtractFlavors provides access to the list of flavors in a page acquired from the List operation.
 func ExtractFlavors(page pagination.Page) ([]Flavor, error) {
-	casted := page.(FlavorPage).Body
-	var container struct {
-		Flavors []Flavor `mapstructure:"flavors"`
+	r := page.(FlavorPage)
+	var s struct {
+		Flavors []Flavor `json:"flavors"`
 	}
-
-	cfg := &mapstructure.DecoderConfig{
-		DecodeHook: defaulter,
-		Result:     &container,
-	}
-	decoder, err := mapstructure.NewDecoder(cfg)
-	if err != nil {
-		return container.Flavors, err
-	}
-	err = decoder.Decode(casted)
-	if err != nil {
-		return container.Flavors, err
-	}
-
-	return container.Flavors, nil
+	err := r.ExtractInto(&s)
+	return s.Flavors, err
 }
diff --git a/openstack/compute/v2/images/results.go b/openstack/compute/v2/images/results.go
index beee0dc..c9832d4 100644
--- a/openstack/compute/v2/images/results.go
+++ b/openstack/compute/v2/images/results.go
@@ -1,7 +1,6 @@
 package images
 
 import (
-	"github.com/mitchellh/mapstructure"
 	"github.com/gophercloud/gophercloud"
 	"github.com/gophercloud/gophercloud/pagination"
 )
@@ -17,17 +16,12 @@
 }
 
 // Extract interprets a GetResult as an Image.
-func (gr GetResult) Extract() (*Image, error) {
-	if gr.Err != nil {
-		return nil, gr.Err
+func (r GetResult) Extract() (*Image, error) {
+	var s struct {
+		Image *Image `json:"image"`
 	}
-
-	var decoded struct {
-		Image Image `mapstructure:"image"`
-	}
-
-	err := mapstructure.Decode(gr.Body, &decoded)
-	return &decoded.Image, err
+	err := r.ExtractInto(&s)
+	return s.Image, err
 }
 
 // Image is used for JSON (un)marshalling.
@@ -62,34 +56,27 @@
 // IsEmpty returns true if a page contains no Image results.
 func (page ImagePage) IsEmpty() (bool, error) {
 	images, err := ExtractImages(page)
-	if err != nil {
-		return true, err
-	}
-	return len(images) == 0, nil
+	return len(images) == 0, err
 }
 
 // NextPageURL uses the response's embedded link reference to navigate to the next page of results.
 func (page ImagePage) NextPageURL() (string, error) {
-	type resp struct {
-		Links []gophercloud.Link `mapstructure:"images_links"`
+	var s struct {
+		Links []gophercloud.Link `json:"images_links"`
 	}
-
-	var r resp
-	err := mapstructure.Decode(page.Body, &r)
+	err := page.ExtractInto(&s)
 	if err != nil {
 		return "", err
 	}
-
-	return gophercloud.ExtractNextURL(r.Links)
+	return gophercloud.ExtractNextURL(s.Links)
 }
 
 // ExtractImages converts a page of List results into a slice of usable Image structs.
 func ExtractImages(page pagination.Page) ([]Image, error) {
-	casted := page.(ImagePage).Body
-	var results struct {
-		Images []Image `mapstructure:"images"`
+	r := page.(ImagePage)
+	var s struct {
+		Images []Image `json:"images"`
 	}
-
-	err := mapstructure.Decode(casted, &results)
-	return results.Images, err
+	err := r.ExtractInto(&s)
+	return s.Images, err
 }
diff --git a/openstack/compute/v2/servers/requests.go b/openstack/compute/v2/servers/requests.go
index 7c964d2..06db312 100644
--- a/openstack/compute/v2/servers/requests.go
+++ b/openstack/compute/v2/servers/requests.go
@@ -195,9 +195,7 @@
 
 	server["name"] = opts.Name
 	server["imageRef"] = opts.ImageRef
-	server["imageName"] = opts.ImageName
 	server["flavorRef"] = opts.FlavorRef
-	server["flavorName"] = opts.FlavorName
 
 	if opts.UserData != nil {
 		encoded := base64.StdEncoding.EncodeToString(opts.UserData)
@@ -503,10 +501,13 @@
 		return server, err
 	}
 
-	server["name"] = opts.Name
 	server["adminPass"] = opts.AdminPass
 	server["imageRef"] = opts.ImageID
 
+	if opts.Name != "" {
+		server["name"] = opts.Name
+	}
+
 	if opts.AccessIPv4 != "" {
 		server["accessIPv4"] = opts.AccessIPv4
 	}
diff --git a/openstack/compute/v2/servers/results.go b/openstack/compute/v2/servers/results.go
index 665b8c8..2517e65 100644
--- a/openstack/compute/v2/servers/results.go
+++ b/openstack/compute/v2/servers/results.go
@@ -1,12 +1,10 @@
 package servers
 
 import (
-	"reflect"
 	"fmt"
-	"path"
 	"net/url"
+	"path"
 
-	"github.com/mitchellh/mapstructure"
 	"github.com/gophercloud/gophercloud"
 	"github.com/gophercloud/gophercloud/pagination"
 )
@@ -17,29 +15,11 @@
 
 // Extract interprets any serverResult as a Server, if possible.
 func (r serverResult) Extract() (*Server, error) {
-	if r.Err != nil {
-		return nil, r.Err
+	var s struct {
+		Server *Server `json:"server"`
 	}
-
-	var response struct {
-		Server Server `mapstructure:"server"`
-	}
-
-	config := &mapstructure.DecoderConfig{
-		DecodeHook: toMapFromString,
-		Result:     &response,
-	}
-	decoder, err := mapstructure.NewDecoder(config)
-	if err != nil {
-		return nil, err
-	}
-
-	err = decoder.Decode(r.Body)
-	if err != nil {
-		return nil, err
-	}
-
-	return &response.Server, nil
+	err := r.ExtractInto(&s)
+	return s.Server, err
 }
 
 // CreateResult temporarily contains the response from a Create call.
@@ -92,40 +72,35 @@
 	if err != nil {
 		return "", fmt.Errorf("Failed to parse the image id: %s", err.Error())
 	}
-	imageId := path.Base(u.Path)
-	if imageId == "." || imageId == "/" {
+	imageID := path.Base(u.Path)
+	if imageID == "." || imageID == "/" {
 		return "", fmt.Errorf("Failed to parse the ID of newly created image: %s", u)
 	}
-	return imageId, nil
+	return imageID, nil
 }
 
 // Extract interprets any RescueResult as an AdminPass, if possible.
 func (r RescueResult) Extract() (string, error) {
-	if r.Err != nil {
-		return "", r.Err
+	var s struct {
+		AdminPass string `json:"adminPass"`
 	}
-
-	var response struct {
-		AdminPass string `mapstructure:"adminPass"`
-	}
-
-	err := mapstructure.Decode(r.Body, &response)
-	return response.AdminPass, err
+	err := r.ExtractInto(&s)
+	return s.AdminPass, err
 }
 
 // Server exposes only the standard OpenStack fields corresponding to a given server on the user's account.
 type Server struct {
 	// ID uniquely identifies this server amongst all other servers, including those not accessible to the current tenant.
-	ID string
+	ID string `json:"id"`
 
 	// TenantID identifies the tenant owning this server resource.
-	TenantID string `mapstructure:"tenant_id"`
+	TenantID string `json:"tenant_id"`
 
 	// UserID uniquely identifies the user account owning the tenant.
-	UserID string `mapstructure:"user_id"`
+	UserID string `json:"user_id"`
 
 	// Name contains the human-readable name for the server.
-	Name string
+	Name string `json:"name"`
 
 	// Updated and Created contain ISO-8601 timestamps of when the state of the server last changed, and when it was created.
 	Updated string
@@ -159,14 +134,14 @@
 	Links []interface{}
 
 	// KeyName indicates which public key was injected into the server on launch.
-	KeyName string `json:"key_name" mapstructure:"key_name"`
+	KeyName string `json:"key_name"`
 
 	// AdminPass will generally be empty ("").  However, it will contain the administrative password chosen when provisioning a new server without a set AdminPass setting in the first place.
 	// Note that this is the ONLY time this field will be valid.
-	AdminPass string `json:"adminPass" mapstructure:"adminPass"`
+	AdminPass string `json:"adminPass"`
 
 	// SecurityGroups includes the security groups that this instance has applied to it
-	SecurityGroups []map[string]interface{} `json:"security_groups" mapstructure:"security_groups"`
+	SecurityGroups []map[string]interface{} `json:"security_groups"`
 }
 
 // ServerPage abstracts the raw results of making a List() request against the API.
@@ -179,47 +154,29 @@
 // IsEmpty returns true if a page contains no Server results.
 func (page ServerPage) IsEmpty() (bool, error) {
 	servers, err := ExtractServers(page)
-	if err != nil {
-		return true, err
-	}
-	return len(servers) == 0, nil
+	return len(servers) == 0, err
 }
 
 // NextPageURL uses the response's embedded link reference to navigate to the next page of results.
 func (page ServerPage) NextPageURL() (string, error) {
-	type resp struct {
-		Links []gophercloud.Link `mapstructure:"servers_links"`
+	var s struct {
+		Links []gophercloud.Link `json:"servers_links"`
 	}
-
-	var r resp
-	err := mapstructure.Decode(page.Body, &r)
+	err := page.ExtractInto(&s)
 	if err != nil {
 		return "", err
 	}
-
-	return gophercloud.ExtractNextURL(r.Links)
+	return gophercloud.ExtractNextURL(s.Links)
 }
 
 // ExtractServers interprets the results of a single page from a List() call, producing a slice of Server entities.
 func ExtractServers(page pagination.Page) ([]Server, error) {
-	casted := page.(ServerPage).Body
-
-	var response struct {
-		Servers []Server `mapstructure:"servers"`
+	r := page.(ServerPage)
+	var s struct {
+		Servers []Server `json:"servers"`
 	}
-
-	config := &mapstructure.DecoderConfig{
-		DecodeHook: toMapFromString,
-		Result:     &response,
-	}
-	decoder, err := mapstructure.NewDecoder(config)
-	if err != nil {
-		return nil, err
-	}
-
-	err = decoder.Decode(casted)
-
-	return response.Servers, err
+	err := r.ExtractInto(&s)
+	return s.Servers, err
 }
 
 // MetadataResult contains the result of a call for (potentially) multiple key-value pairs.
@@ -264,43 +221,26 @@
 
 // Extract interprets any MetadataResult as a Metadata, if possible.
 func (r MetadataResult) Extract() (map[string]string, error) {
-	if r.Err != nil {
-		return nil, r.Err
+	var s struct {
+		Metadata map[string]string `json:"metadata"`
 	}
-
-	var response struct {
-		Metadata map[string]string `mapstructure:"metadata"`
-	}
-
-	err := mapstructure.Decode(r.Body, &response)
-	return response.Metadata, err
+	err := r.ExtractInto(&s)
+	return s.Metadata, err
 }
 
 // Extract interprets any MetadatumResult as a Metadatum, if possible.
 func (r MetadatumResult) Extract() (map[string]string, error) {
-	if r.Err != nil {
-		return nil, r.Err
+	var s struct {
+		Metadatum map[string]string `json:"meta"`
 	}
-
-	var response struct {
-		Metadatum map[string]string `mapstructure:"meta"`
-	}
-
-	err := mapstructure.Decode(r.Body, &response)
-	return response.Metadatum, err
-}
-
-func toMapFromString(from reflect.Kind, to reflect.Kind, data interface{}) (interface{}, error) {
-	if (from == reflect.String) && (to == reflect.Map) {
-		return map[string]interface{}{}, nil
-	}
-	return data, nil
+	err := r.ExtractInto(&s)
+	return s.Metadatum, err
 }
 
 // Address represents an IP address.
 type Address struct {
-	Version int    `mapstructure:"version"`
-	Address string `mapstructure:"addr"`
+	Version int    `json:"version"`
+	Address string `json:"addr"`
 }
 
 // AddressPage abstracts the raw results of making a ListAddresses() request against the API.
@@ -313,27 +253,18 @@
 // IsEmpty returns true if an AddressPage contains no networks.
 func (r AddressPage) IsEmpty() (bool, error) {
 	addresses, err := ExtractAddresses(r)
-	if err != nil {
-		return true, err
-	}
-	return len(addresses) == 0, nil
+	return len(addresses) == 0, err
 }
 
 // ExtractAddresses interprets the results of a single page from a ListAddresses() call,
 // producing a map of addresses.
 func ExtractAddresses(page pagination.Page) (map[string][]Address, error) {
-	casted := page.(AddressPage).Body
-
-	var response struct {
-		Addresses map[string][]Address `mapstructure:"addresses"`
+	r := page.(AddressPage)
+	var s struct {
+		Addresses map[string][]Address `json:"addresses"`
 	}
-
-	err := mapstructure.Decode(casted, &response)
-	if err != nil {
-		return nil, err
-	}
-
-	return response.Addresses, err
+	err := r.ExtractInto(&s)
+	return s.Addresses, err
 }
 
 // NetworkAddressPage abstracts the raw results of making a ListAddressesByNetwork() request against the API.
@@ -346,27 +277,23 @@
 // IsEmpty returns true if a NetworkAddressPage contains no addresses.
 func (r NetworkAddressPage) IsEmpty() (bool, error) {
 	addresses, err := ExtractNetworkAddresses(r)
-	if err != nil {
-		return true, err
-	}
-	return len(addresses) == 0, nil
+	return len(addresses) == 0, err
 }
 
 // ExtractNetworkAddresses interprets the results of a single page from a ListAddressesByNetwork() call,
 // producing a slice of addresses.
 func ExtractNetworkAddresses(page pagination.Page) ([]Address, error) {
-	casted := page.(NetworkAddressPage).Body
-
-	var response map[string][]Address
-	err := mapstructure.Decode(casted, &response)
+	r := page.(NetworkAddressPage)
+	var s map[string][]Address
+	err := r.ExtractInto(&s)
 	if err != nil {
 		return nil, err
 	}
 
 	var key string
-	for k := range response {
+	for k := range s {
 		key = k
 	}
 
-	return response[key], err
+	return s[key], err
 }
diff --git a/openstack/db/v1/configurations/results.go b/openstack/db/v1/configurations/results.go
index 5128b01..a708abd 100644
--- a/openstack/db/v1/configurations/results.go
+++ b/openstack/db/v1/configurations/results.go
@@ -1,22 +1,19 @@
 package configurations
 
 import (
-	"fmt"
-	"reflect"
 	"time"
 
-	"github.com/mitchellh/mapstructure"
 	"github.com/gophercloud/gophercloud"
 	"github.com/gophercloud/gophercloud/pagination"
 )
 
 // Config represents a configuration group API resource.
 type Config struct {
-	Created              time.Time `mapstructure:"-"`
-	Updated              time.Time `mapstructure:"-"`
-	DatastoreName        string    `mapstructure:"datastore_name"`
-	DatastoreVersionID   string    `mapstructure:"datastore_version_id"`
-	DatastoreVersionName string    `mapstructure:"datastore_version_name"`
+	Created              time.Time `json:"created"`
+	Updated              time.Time `json:"updated"`
+	DatastoreName        string    `json:"datastore_name"`
+	DatastoreVersionID   string    `json:"datastore_version_id"`
+	DatastoreVersionName string    `json:"datastore_version_name"`
 	Description          string
 	ID                   string
 	Name                 string
@@ -31,55 +28,17 @@
 // IsEmpty indicates whether a ConfigPage is empty.
 func (r ConfigPage) IsEmpty() (bool, error) {
 	is, err := ExtractConfigs(r)
-	if err != nil {
-		return true, err
-	}
-	return len(is) == 0, nil
+	return len(is) == 0, err
 }
 
 // ExtractConfigs will retrieve a slice of Config structs from a page.
 func ExtractConfigs(page pagination.Page) ([]Config, error) {
-	casted := page.(ConfigPage).Body
-
-	var resp struct {
-		Configs []Config `mapstructure:"configurations" json:"configurations"`
+	r := page.(ConfigPage)
+	var s struct {
+		Configs []Config `json:"configurations"`
 	}
-
-	if err := mapstructure.Decode(casted, &resp); err != nil {
-		return nil, err
-	}
-
-	var vals []interface{}
-	switch casted.(type) {
-	case map[string]interface{}:
-		vals = casted.(map[string]interface{})["configurations"].([]interface{})
-	case map[string][]interface{}:
-		vals = casted.(map[string][]interface{})["configurations"]
-	default:
-		return resp.Configs, fmt.Errorf("Unknown type: %v", reflect.TypeOf(casted))
-	}
-
-	for i, v := range vals {
-		val := v.(map[string]interface{})
-
-		if t, ok := val["created"].(string); ok && t != "" {
-			creationTime, err := time.Parse(time.RFC3339, t)
-			if err != nil {
-				return resp.Configs, err
-			}
-			resp.Configs[i].Created = creationTime
-		}
-
-		if t, ok := val["updated"].(string); ok && t != "" {
-			updatedTime, err := time.Parse(time.RFC3339, t)
-			if err != nil {
-				return resp.Configs, err
-			}
-			resp.Configs[i].Updated = updatedTime
-		}
-	}
-
-	return resp.Configs, nil
+	err := r.ExtractInto(&s)
+	return s.Configs, err
 }
 
 type commonResult struct {
@@ -88,34 +47,11 @@
 
 // Extract will retrieve a Config resource from an operation result.
 func (r commonResult) Extract() (*Config, error) {
-	if r.Err != nil {
-		return nil, r.Err
+	var s struct {
+		Config *Config `json:"configuration"`
 	}
-
-	var response struct {
-		Config Config `mapstructure:"configuration"`
-	}
-
-	err := mapstructure.Decode(r.Body, &response)
-	val := r.Body.(map[string]interface{})["configuration"].(map[string]interface{})
-
-	if t, ok := val["created"].(string); ok && t != "" {
-		creationTime, err := time.Parse(time.RFC3339, t)
-		if err != nil {
-			return &response.Config, err
-		}
-		response.Config.Created = creationTime
-	}
-
-	if t, ok := val["updated"].(string); ok && t != "" {
-		updatedTime, err := time.Parse(time.RFC3339, t)
-		if err != nil {
-			return &response.Config, err
-		}
-		response.Config.Updated = updatedTime
-	}
-
-	return &response.Config, err
+	err := r.ExtractInto(&s)
+	return s.Config, err
 }
 
 // GetResult represents the result of a Get operation.
@@ -145,10 +81,10 @@
 
 // Param represents a configuration parameter API resource.
 type Param struct {
-	Max             int
-	Min             int
+	Max             float64
+	Min             float64
 	Name            string
-	RestartRequired bool `mapstructure:"restart_required" json:"restart_required"`
+	RestartRequired bool `json:"restart_required"`
 	Type            string
 }
 
@@ -160,22 +96,17 @@
 // IsEmpty indicates whether a ParamPage is empty.
 func (r ParamPage) IsEmpty() (bool, error) {
 	is, err := ExtractParams(r)
-	if err != nil {
-		return true, err
-	}
-	return len(is) == 0, nil
+	return len(is) == 0, err
 }
 
 // ExtractParams will retrieve a slice of Param structs from a page.
 func ExtractParams(page pagination.Page) ([]Param, error) {
-	casted := page.(ParamPage).Body
-
-	var resp struct {
-		Params []Param `mapstructure:"configuration-parameters" json:"configuration-parameters"`
+	r := page.(ParamPage)
+	var s struct {
+		Params []Param `json:"configuration-parameters"`
 	}
-
-	err := mapstructure.Decode(casted, &resp)
-	return resp.Params, err
+	err := r.ExtractInto(&s)
+	return s.Params, err
 }
 
 // ParamResult represents the result of an operation which retrieves details
@@ -186,12 +117,7 @@
 
 // Extract will retrieve a param from an operation result.
 func (r ParamResult) Extract() (*Param, error) {
-	if r.Err != nil {
-		return nil, r.Err
-	}
-
-	var param Param
-
-	err := mapstructure.Decode(r.Body, &param)
-	return &param, err
+	var s Param
+	err := r.ExtractInto(&s)
+	return &s, err
 }
diff --git a/openstack/db/v1/databases/results.go b/openstack/db/v1/databases/results.go
index 9126329..0479d0e 100644
--- a/openstack/db/v1/databases/results.go
+++ b/openstack/db/v1/databases/results.go
@@ -1,7 +1,6 @@
 package databases
 
 import (
-	"github.com/mitchellh/mapstructure"
 	"github.com/gophercloud/gophercloud"
 	"github.com/gophercloud/gophercloud/pagination"
 )
@@ -37,36 +36,28 @@
 // IsEmpty checks to see whether the collection is empty.
 func (page DBPage) IsEmpty() (bool, error) {
 	dbs, err := ExtractDBs(page)
-	if err != nil {
-		return true, err
-	}
-	return len(dbs) == 0, nil
+	return len(dbs) == 0, err
 }
 
 // NextPageURL will retrieve the next page URL.
 func (page DBPage) NextPageURL() (string, error) {
-	type resp struct {
-		Links []gophercloud.Link `mapstructure:"databases_links"`
+	var s struct {
+		Links []gophercloud.Link `json:"databases_links"`
 	}
-
-	var r resp
-	err := mapstructure.Decode(page.Body, &r)
+	err := page.ExtractInto(&s)
 	if err != nil {
 		return "", err
 	}
-
-	return gophercloud.ExtractNextURL(r.Links)
+	return gophercloud.ExtractNextURL(s.Links)
 }
 
 // ExtractDBs will convert a generic pagination struct into a more
 // relevant slice of DB structs.
 func ExtractDBs(page pagination.Page) ([]Database, error) {
-	casted := page.(DBPage).Body
-
-	var response struct {
-		Databases []Database `mapstructure:"databases"`
+	r := page.(DBPage)
+	var s struct {
+		Databases []Database `json:"databases"`
 	}
-
-	err := mapstructure.Decode(casted, &response)
-	return response.Databases, err
+	err := r.ExtractInto(&s)
+	return s.Databases, err
 }
diff --git a/openstack/db/v1/datastores/results.go b/openstack/db/v1/datastores/results.go
index a0b3ee8..e893884 100644
--- a/openstack/db/v1/datastores/results.go
+++ b/openstack/db/v1/datastores/results.go
@@ -1,7 +1,6 @@
 package datastores
 
 import (
-	"github.com/mitchellh/mapstructure"
 	"github.com/gophercloud/gophercloud"
 	"github.com/gophercloud/gophercloud/pagination"
 )
@@ -15,7 +14,7 @@
 
 // Datastore represents a Datastore API resource.
 type Datastore struct {
-	DefaultVersion string `json:"default_version" mapstructure:"default_version"`
+	DefaultVersion string `json:"default_version"`
 	ID             string
 	Links          []gophercloud.Link
 	Name           string
@@ -28,7 +27,7 @@
 type DatastorePartial struct {
 	Version   string
 	Type      string
-	VersionID string `json:"version_id" mapstructure:"version_id"`
+	VersionID string `json:"version_id"`
 }
 
 // GetResult represents the result of a Get operation.
@@ -49,40 +48,30 @@
 // IsEmpty indicates whether a Datastore collection is empty.
 func (r DatastorePage) IsEmpty() (bool, error) {
 	is, err := ExtractDatastores(r)
-	if err != nil {
-		return true, err
-	}
-	return len(is) == 0, nil
+	return len(is) == 0, err
 }
 
 // ExtractDatastores retrieves a slice of datastore structs from a paginated
 // collection.
 func ExtractDatastores(page pagination.Page) ([]Datastore, error) {
-	casted := page.(DatastorePage).Body
-
-	var resp struct {
-		Datastores []Datastore `mapstructure:"datastores" json:"datastores"`
+	r := page.(DatastorePage)
+	var s struct {
+		Datastores []Datastore `json:"datastores"`
 	}
-
-	err := mapstructure.Decode(casted, &resp)
-	return resp.Datastores, err
+	err := r.ExtractInto(&s)
+	return s.Datastores, err
 }
 
 // Extract retrieves a single Datastore struct from an operation result.
 func (r GetResult) Extract() (*Datastore, error) {
-	if r.Err != nil {
-		return nil, r.Err
+	var s struct {
+		Datastore *Datastore `json:"datastore"`
 	}
-
-	var response struct {
-		Datastore Datastore `mapstructure:"datastore"`
-	}
-
-	err := mapstructure.Decode(r.Body, &response)
-	return &response.Datastore, err
+	err := r.ExtractInto(&s)
+	return s.Datastore, err
 }
 
-// DatastorePage represents a page of version resources.
+// VersionPage represents a page of version resources.
 type VersionPage struct {
 	pagination.SinglePageBase
 }
@@ -90,34 +79,24 @@
 // IsEmpty indicates whether a collection of version resources is empty.
 func (r VersionPage) IsEmpty() (bool, error) {
 	is, err := ExtractVersions(r)
-	if err != nil {
-		return true, err
-	}
-	return len(is) == 0, nil
+	return len(is) == 0, err
 }
 
 // ExtractVersions retrieves a slice of versions from a paginated collection.
 func ExtractVersions(page pagination.Page) ([]Version, error) {
-	casted := page.(VersionPage).Body
-
-	var resp struct {
-		Versions []Version `mapstructure:"versions" json:"versions"`
+	r := page.(VersionPage)
+	var s struct {
+		Versions []Version `json:"versions"`
 	}
-
-	err := mapstructure.Decode(casted, &resp)
-	return resp.Versions, err
+	err := r.ExtractInto(&s)
+	return s.Versions, err
 }
 
 // Extract retrieves a single Version struct from an operation result.
 func (r GetVersionResult) Extract() (*Version, error) {
-	if r.Err != nil {
-		return nil, r.Err
+	var s struct {
+		Version *Version `json:"version"`
 	}
-
-	var response struct {
-		Version Version `mapstructure:"version"`
-	}
-
-	err := mapstructure.Decode(r.Body, &response)
-	return &response.Version, err
+	err := r.ExtractInto(&s)
+	return s.Version, err
 }
diff --git a/openstack/db/v1/flavors/requests_test.go b/openstack/db/v1/flavors/requests_test.go
index 387b076..ce01759 100644
--- a/openstack/db/v1/flavors/requests_test.go
+++ b/openstack/db/v1/flavors/requests_test.go
@@ -25,7 +25,7 @@
 
 		expected := []Flavor{
 			Flavor{
-				ID:   "1",
+				ID:   1,
 				Name: "m1.tiny",
 				RAM:  512,
 				Links: []gophercloud.Link{
@@ -34,7 +34,7 @@
 				},
 			},
 			Flavor{
-				ID:   "2",
+				ID:   2,
 				Name: "m1.small",
 				RAM:  1024,
 				Links: []gophercloud.Link{
@@ -43,7 +43,7 @@
 				},
 			},
 			Flavor{
-				ID:   "3",
+				ID:   3,
 				Name: "m1.medium",
 				RAM:  2048,
 				Links: []gophercloud.Link{
@@ -52,7 +52,7 @@
 				},
 			},
 			Flavor{
-				ID:   "4",
+				ID:   4,
 				Name: "m1.large",
 				RAM:  4096,
 				Links: []gophercloud.Link{
@@ -79,7 +79,7 @@
 	th.AssertNoErr(t, err)
 
 	expected := &Flavor{
-		ID:   "1",
+		ID:   1,
 		Name: "m1.tiny",
 		RAM:  512,
 		Links: []gophercloud.Link{
diff --git a/openstack/db/v1/flavors/results.go b/openstack/db/v1/flavors/results.go
index 508f5a4..d2a5cba 100644
--- a/openstack/db/v1/flavors/results.go
+++ b/openstack/db/v1/flavors/results.go
@@ -1,7 +1,6 @@
 package flavors
 
 import (
-	"github.com/mitchellh/mapstructure"
 	"github.com/gophercloud/gophercloud"
 	"github.com/gophercloud/gophercloud/pagination"
 )
@@ -12,34 +11,24 @@
 }
 
 // Extract provides access to the individual Flavor returned by the Get function.
-func (gr GetResult) Extract() (*Flavor, error) {
-	if gr.Err != nil {
-		return nil, gr.Err
+func (r GetResult) Extract() (*Flavor, error) {
+	var s struct {
+		Flavor *Flavor `json:"flavor"`
 	}
-
-	var result struct {
-		Flavor Flavor `mapstructure:"flavor"`
-	}
-
-	decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
-		WeaklyTypedInput: true,
-		Result:           &result,
-	})
-
-	err = decoder.Decode(gr.Body)
-	return &result.Flavor, err
+	err := r.ExtractInto(&s)
+	return s.Flavor, err
 }
 
 // Flavor records represent (virtual) hardware configurations for server resources in a region.
 type Flavor struct {
 	// The flavor's unique identifier.
-	ID string `mapstructure:"id"`
+	ID int `json:"id"`
 
 	// The RAM capacity for the flavor.
-	RAM int `mapstructure:"ram"`
+	RAM int `json:"ram"`
 
 	// The Name field provides a human-readable moniker for the flavor.
-	Name string `mapstructure:"name"`
+	Name string `json:"name"`
 
 	// Links to access the flavor.
 	Links []gophercloud.Link
@@ -51,42 +40,29 @@
 }
 
 // IsEmpty determines if a page contains any results.
-func (p FlavorPage) IsEmpty() (bool, error) {
-	flavors, err := ExtractFlavors(p)
-	if err != nil {
-		return true, err
-	}
-	return len(flavors) == 0, nil
+func (page FlavorPage) IsEmpty() (bool, error) {
+	flavors, err := ExtractFlavors(page)
+	return len(flavors) == 0, err
 }
 
 // NextPageURL uses the response's embedded link reference to navigate to the next page of results.
-func (p FlavorPage) NextPageURL() (string, error) {
-	type resp struct {
-		Links []gophercloud.Link `mapstructure:"flavors_links"`
+func (page FlavorPage) NextPageURL() (string, error) {
+	var s struct {
+		Links []gophercloud.Link `json:"flavors_links"`
 	}
-
-	var r resp
-	err := mapstructure.Decode(p.Body, &r)
+	err := page.ExtractInto(&s)
 	if err != nil {
 		return "", err
 	}
-
-	return gophercloud.ExtractNextURL(r.Links)
+	return gophercloud.ExtractNextURL(s.Links)
 }
 
 // ExtractFlavors provides access to the list of flavors in a page acquired from the List operation.
 func ExtractFlavors(page pagination.Page) ([]Flavor, error) {
-	casted := page.(FlavorPage).Body
-	var container struct {
-		Flavors []Flavor `mapstructure:"flavors"`
+	r := page.(FlavorPage)
+	var s struct {
+		Flavors []Flavor `json:"flavors"`
 	}
-
-	decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
-		WeaklyTypedInput: true,
-		Result:           &container,
-	})
-
-	err = decoder.Decode(casted)
-
-	return container.Flavors, err
+	err := r.ExtractInto(&s)
+	return s.Flavors, err
 }
diff --git a/openstack/db/v1/instances/fixtures.go b/openstack/db/v1/instances/fixtures.go
index d30d889..d0a3856 100644
--- a/openstack/db/v1/instances/fixtures.go
+++ b/openstack/db/v1/instances/fixtures.go
@@ -24,7 +24,7 @@
     "version": "5.6"
   },
   "flavor": {
-    "id": "1",
+    "id": 1,
     "links": [
       {
         "href": "https://my-openstack.com/v1.0/1234/flavors/1",
@@ -112,7 +112,7 @@
 	Created: timeVal,
 	Updated: timeVal,
 	Flavor: flavors.Flavor{
-		ID: "1",
+		ID: 1,
 		Links: []gophercloud.Link{
 			gophercloud.Link{Href: "https://my-openstack.com/v1.0/1234/flavors/1", Rel: "self"},
 			gophercloud.Link{Href: "https://my-openstack.com/v1.0/1234/flavors/1", Rel: "bookmark"},
diff --git a/openstack/db/v1/instances/results.go b/openstack/db/v1/instances/results.go
index 46731ef..905b32c 100644
--- a/openstack/db/v1/instances/results.go
+++ b/openstack/db/v1/instances/results.go
@@ -1,11 +1,8 @@
 package instances
 
 import (
-	"fmt"
-	"reflect"
 	"time"
 
-	"github.com/mitchellh/mapstructure"
 	"github.com/gophercloud/gophercloud"
 	"github.com/gophercloud/gophercloud/openstack/db/v1/datastores"
 	"github.com/gophercloud/gophercloud/openstack/db/v1/flavors"
@@ -24,10 +21,10 @@
 // Instance represents a remote MySQL instance.
 type Instance struct {
 	// Indicates the datetime that the instance was created
-	Created time.Time `mapstructure:"-"`
+	Created time.Time `json:"created"`
 
 	// Indicates the most recent datetime that the instance was updated.
-	Updated time.Time `mapstructure:"-"`
+	Updated time.Time `json:"updated"`
 
 	// Indicates the hardware flavor the instance uses.
 	Flavor flavors.Flavor
@@ -80,34 +77,11 @@
 
 // Extract will extract an Instance from various result structs.
 func (r commonResult) Extract() (*Instance, error) {
-	if r.Err != nil {
-		return nil, r.Err
+	var s struct {
+		Instance *Instance `json:"instance"`
 	}
-
-	var response struct {
-		Instance Instance `mapstructure:"instance"`
-	}
-
-	err := mapstructure.Decode(r.Body, &response)
-	val := r.Body.(map[string]interface{})["instance"].(map[string]interface{})
-
-	if t, ok := val["created"].(string); ok && t != "" {
-		creationTime, err := time.Parse(time.RFC3339, t)
-		if err != nil {
-			return &response.Instance, err
-		}
-		response.Instance.Created = creationTime
-	}
-
-	if t, ok := val["updated"].(string); ok && t != "" {
-		updatedTime, err := time.Parse(time.RFC3339, t)
-		if err != nil {
-			return &response.Instance, err
-		}
-		response.Instance.Updated = updatedTime
-	}
-
-	return &response.Instance, err
+	err := r.ExtractInto(&s)
+	return s.Instance, err
 }
 
 // InstancePage represents a single page of a paginated instance collection.
@@ -118,71 +92,30 @@
 // IsEmpty checks to see whether the collection is empty.
 func (page InstancePage) IsEmpty() (bool, error) {
 	instances, err := ExtractInstances(page)
-	if err != nil {
-		return true, err
-	}
-	return len(instances) == 0, nil
+	return len(instances) == 0, err
 }
 
 // NextPageURL will retrieve the next page URL.
 func (page InstancePage) NextPageURL() (string, error) {
-	type resp struct {
-		Links []gophercloud.Link `mapstructure:"instances_links"`
+	var s struct {
+		Links []gophercloud.Link `json:"instances_links"`
 	}
-
-	var r resp
-	err := mapstructure.Decode(page.Body, &r)
+	err := page.ExtractInto(&s)
 	if err != nil {
 		return "", err
 	}
-
-	return gophercloud.ExtractNextURL(r.Links)
+	return gophercloud.ExtractNextURL(s.Links)
 }
 
 // ExtractInstances will convert a generic pagination struct into a more
 // relevant slice of Instance structs.
 func ExtractInstances(page pagination.Page) ([]Instance, error) {
-	casted := page.(InstancePage).Body
-
-	var resp struct {
-		Instances []Instance `mapstructure:"instances"`
+	r := page.(InstancePage)
+	var s struct {
+		Instances []Instance `json:"instances"`
 	}
-
-	if err := mapstructure.Decode(casted, &resp); err != nil {
-		return nil, err
-	}
-
-	var vals []interface{}
-	switch casted.(type) {
-	case map[string]interface{}:
-		vals = casted.(map[string]interface{})["instances"].([]interface{})
-	case map[string][]interface{}:
-		vals = casted.(map[string][]interface{})["instances"]
-	default:
-		return resp.Instances, fmt.Errorf("Unknown type: %v", reflect.TypeOf(casted))
-	}
-
-	for i, v := range vals {
-		val := v.(map[string]interface{})
-
-		if t, ok := val["created"].(string); ok && t != "" {
-			creationTime, err := time.Parse(time.RFC3339, t)
-			if err != nil {
-				return resp.Instances, err
-			}
-			resp.Instances[i].Created = creationTime
-		}
-
-		if t, ok := val["updated"].(string); ok && t != "" {
-			updatedTime, err := time.Parse(time.RFC3339, t)
-			if err != nil {
-				return resp.Instances, err
-			}
-			resp.Instances[i].Updated = updatedTime
-		}
-	}
-
-	return resp.Instances, nil
+	err := r.ExtractInto(&s)
+	return s.Instances, err
 }
 
 // UserRootResult represents the result of an operation to enable the root user.
@@ -192,17 +125,11 @@
 
 // Extract will extract root user information from a UserRootResult.
 func (r UserRootResult) Extract() (*users.User, error) {
-	if r.Err != nil {
-		return nil, r.Err
+	var s struct {
+		User *users.User `json:"user"`
 	}
-
-	var response struct {
-		User users.User `mapstructure:"user"`
-	}
-
-	err := mapstructure.Decode(r.Body, &response)
-
-	return &response.User, err
+	err := r.ExtractInto(&s)
+	return s.User, err
 }
 
 // ActionResult represents the result of action requests, such as: restarting
diff --git a/openstack/db/v1/users/results.go b/openstack/db/v1/users/results.go
index a2d1508..018b7c3 100644
--- a/openstack/db/v1/users/results.go
+++ b/openstack/db/v1/users/results.go
@@ -1,7 +1,6 @@
 package users
 
 import (
-	"github.com/mitchellh/mapstructure"
 	"github.com/gophercloud/gophercloud"
 	db "github.com/gophercloud/gophercloud/openstack/db/v1/databases"
 	"github.com/gophercloud/gophercloud/pagination"
@@ -37,37 +36,28 @@
 // IsEmpty checks to see whether the collection is empty.
 func (page UserPage) IsEmpty() (bool, error) {
 	users, err := ExtractUsers(page)
-	if err != nil {
-		return true, err
-	}
-	return len(users) == 0, nil
+	return len(users) == 0, err
 }
 
 // NextPageURL will retrieve the next page URL.
 func (page UserPage) NextPageURL() (string, error) {
-	type resp struct {
-		Links []gophercloud.Link `mapstructure:"users_links"`
+	var s struct {
+		Links []gophercloud.Link `json:"users_links"`
 	}
-
-	var r resp
-	err := mapstructure.Decode(page.Body, &r)
+	err := page.ExtractInto(&s)
 	if err != nil {
 		return "", err
 	}
-
-	return gophercloud.ExtractNextURL(r.Links)
+	return gophercloud.ExtractNextURL(s.Links)
 }
 
 // ExtractUsers will convert a generic pagination struct into a more
 // relevant slice of User structs.
 func ExtractUsers(page pagination.Page) ([]User, error) {
-	casted := page.(UserPage).Body
-
-	var response struct {
-		Users []User `mapstructure:"users"`
+	r := page.(UserPage)
+	var s struct {
+		Users []User `json:"users"`
 	}
-
-	err := mapstructure.Decode(casted, &response)
-
-	return response.Users, err
+	err := r.ExtractInto(&s)
+	return s.Users, err
 }