remove mapstructure from identity,networking,objectstorage,orchestration,pagination
diff --git a/openstack/networking/v2/extensions/external/results.go b/openstack/networking/v2/extensions/external/results.go
index c5d5f14..2c5173a 100644
--- a/openstack/networking/v2/extensions/external/results.go
+++ b/openstack/networking/v2/extensions/external/results.go
@@ -1,7 +1,6 @@
 package external
 
 import (
-	"github.com/mitchellh/mapstructure"
 	"github.com/gophercloud/gophercloud/openstack/networking/v2/networks"
 	"github.com/gophercloud/gophercloud/pagination"
 )
@@ -10,72 +9,69 @@
 // "external-net" extension.
 type NetworkExternal struct {
 	// UUID for the network
-	ID string `mapstructure:"id" json:"id"`
+	ID string `json:"id"`
 
 	// Human-readable name for the network. Might not be unique.
-	Name string `mapstructure:"name" json:"name"`
+	Name string `json:"name"`
 
 	// The administrative state of network. If false (down), the network does not forward packets.
-	AdminStateUp bool `mapstructure:"admin_state_up" json:"admin_state_up"`
+	AdminStateUp bool `json:"admin_state_up"`
 
 	// Indicates whether network is currently operational. Possible values include
 	// `ACTIVE', `DOWN', `BUILD', or `ERROR'. Plug-ins might define additional values.
-	Status string `mapstructure:"status" json:"status"`
+	Status string `json:"status"`
 
 	// Subnets associated with this network.
-	Subnets []string `mapstructure:"subnets" json:"subnets"`
+	Subnets []string `json:"subnets"`
 
 	// Owner of network. Only admin users can specify a tenant_id other than its own.
-	TenantID string `mapstructure:"tenant_id" json:"tenant_id"`
+	TenantID string `json:"tenant_id"`
 
 	// Specifies whether the network resource can be accessed by any tenant or not.
-	Shared bool `mapstructure:"shared" json:"shared"`
+	Shared bool `json:"shared"`
 
 	// Specifies whether the network is an external network or not.
-	External bool `mapstructure:"router:external" json:"router:external"`
-}
-
-func commonExtract(e error, response interface{}) (*NetworkExternal, error) {
-	if e != nil {
-		return nil, e
-	}
-
-	var res struct {
-		Network *NetworkExternal `json:"network"`
-	}
-
-	err := mapstructure.Decode(response, &res)
-
-	return res.Network, err
+	External bool `json:"router:external"`
 }
 
 // ExtractGet decorates a GetResult struct returned from a networks.Get()
 // function with extended attributes.
 func ExtractGet(r networks.GetResult) (*NetworkExternal, error) {
-	return commonExtract(r.Err, r.Body)
+	var s struct {
+		Network *NetworkExternal `json:"network"`
+	}
+	err := r.ExtractInto(&s)
+	return s.Network, err
 }
 
 // ExtractCreate decorates a CreateResult struct returned from a networks.Create()
 // function with extended attributes.
 func ExtractCreate(r networks.CreateResult) (*NetworkExternal, error) {
-	return commonExtract(r.Err, r.Body)
+	var s struct {
+		Network *NetworkExternal `json:"network"`
+	}
+	err := r.ExtractInto(&s)
+	return s.Network, err
 }
 
 // ExtractUpdate decorates a UpdateResult struct returned from a
 // networks.Update() function with extended attributes.
 func ExtractUpdate(r networks.UpdateResult) (*NetworkExternal, error) {
-	return commonExtract(r.Err, r.Body)
+	var s struct {
+		Network *NetworkExternal `json:"network"`
+	}
+	err := r.ExtractInto(&s)
+	return s.Network, err
 }
 
 // ExtractList accepts a Page struct, specifically a NetworkPage struct, and
 // extracts the elements into a slice of NetworkExternal structs. In other
 // words, a generic collection is mapped into a relevant slice.
 func ExtractList(page pagination.Page) ([]NetworkExternal, error) {
-	var resp struct {
-		Networks []NetworkExternal `mapstructure:"networks" json:"networks"`
+	r := page.(networks.NetworkPage)
+	var s struct {
+		Networks []NetworkExternal `json:"networks" json:"networks"`
 	}
-
-	err := mapstructure.Decode(page.(networks.NetworkPage).Body, &resp)
-
-	return resp.Networks, err
+	err := r.ExtractInto(&s)
+	return s.Networks, err
 }
diff --git a/openstack/networking/v2/extensions/fwaas/firewalls/results.go b/openstack/networking/v2/extensions/fwaas/firewalls/results.go
index 5af4b88..2b4338c 100644
--- a/openstack/networking/v2/extensions/fwaas/firewalls/results.go
+++ b/openstack/networking/v2/extensions/fwaas/firewalls/results.go
@@ -1,19 +1,19 @@
 package firewalls
 
 import (
-	"github.com/mitchellh/mapstructure"
 	"github.com/gophercloud/gophercloud"
 	"github.com/gophercloud/gophercloud/pagination"
 )
 
+// Firewall is an OpenStack firewall.
 type Firewall struct {
-	ID           string `json:"id" mapstructure:"id"`
-	Name         string `json:"name" mapstructure:"name"`
-	Description  string `json:"description" mapstructure:"description"`
-	AdminStateUp bool   `json:"admin_state_up" mapstructure:"admin_state_up"`
-	Status       string `json:"status" mapstructure:"status"`
-	PolicyID     string `json:"firewall_policy_id" mapstructure:"firewall_policy_id"`
-	TenantID     string `json:"tenant_id" mapstructure:"tenant_id"`
+	ID           string `json:"id"`
+	Name         string `json:"name"`
+	Description  string `json:"description"`
+	AdminStateUp bool   `json:"admin_state_up"`
+	Status       string `json:"status"`
+	PolicyID     string `json:"firewall_policy_id"`
+	TenantID     string `json:"tenant_id"`
 }
 
 type commonResult struct {
@@ -22,17 +22,11 @@
 
 // Extract is a function that accepts a result and extracts a firewall.
 func (r commonResult) Extract() (*Firewall, error) {
-	if r.Err != nil {
-		return nil, r.Err
-	}
-
-	var res struct {
+	var s struct {
 		Firewall *Firewall `json:"firewall"`
 	}
-
-	err := mapstructure.Decode(r.Body, &res)
-
-	return res.Firewall, err
+	err := r.ExtractInto(&s)
+	return s.Firewall, err
 }
 
 // FirewallPage is the page returned by a pager when traversing over a
@@ -44,40 +38,32 @@
 // NextPageURL is invoked when a paginated collection of firewalls has reached
 // the end of a page and the pager seeks to traverse over a new one. In order
 // to do this, it needs to construct the next page's URL.
-func (p FirewallPage) NextPageURL() (string, error) {
-	type resp struct {
-		Links []gophercloud.Link `mapstructure:"firewalls_links"`
+func (page FirewallPage) NextPageURL() (string, error) {
+	var s struct {
+		Links []gophercloud.Link `json:"firewalls_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)
 }
 
 // IsEmpty checks whether a FirewallPage struct is empty.
-func (p FirewallPage) IsEmpty() (bool, error) {
-	is, err := ExtractFirewalls(p)
-	if err != nil {
-		return true, nil
-	}
-	return len(is) == 0, nil
+func (page FirewallPage) IsEmpty() (bool, error) {
+	is, err := ExtractFirewalls(page)
+	return len(is) == 0, err
 }
 
 // ExtractFirewalls accepts a Page struct, specifically a RouterPage struct,
 // and extracts the elements into a slice of Router structs. In other words,
 // a generic collection is mapped into a relevant slice.
 func ExtractFirewalls(page pagination.Page) ([]Firewall, error) {
-	var resp struct {
-		Firewalls []Firewall `mapstructure:"firewalls" json:"firewalls"`
+	var s struct {
+		Firewalls []Firewall `json:"firewalls" json:"firewalls"`
 	}
-
-	err := mapstructure.Decode(page.(FirewallPage).Body, &resp)
-
-	return resp.Firewalls, err
+	err := (page.(FirewallPage)).ExtractInto(&s)
+	return s.Firewalls, err
 }
 
 // GetResult represents the result of a get operation.
diff --git a/openstack/networking/v2/extensions/fwaas/policies/results.go b/openstack/networking/v2/extensions/fwaas/policies/results.go
index 9a6d563..d23c81d 100644
--- a/openstack/networking/v2/extensions/fwaas/policies/results.go
+++ b/openstack/networking/v2/extensions/fwaas/policies/results.go
@@ -1,19 +1,19 @@
 package policies
 
 import (
-	"github.com/mitchellh/mapstructure"
 	"github.com/gophercloud/gophercloud"
 	"github.com/gophercloud/gophercloud/pagination"
 )
 
+// Policy is a firewall policy.
 type Policy struct {
-	ID          string   `json:"id" mapstructure:"id"`
-	Name        string   `json:"name" mapstructure:"name"`
-	Description string   `json:"description" mapstructure:"description"`
-	TenantID    string   `json:"tenant_id" mapstructure:"tenant_id"`
-	Audited     bool     `json:"audited" mapstructure:"audited"`
-	Shared      bool     `json:"shared" mapstructure:"shared"`
-	Rules       []string `json:"firewall_rules,omitempty" mapstructure:"firewall_rules"`
+	ID          string   `json:"id"`
+	Name        string   `json:"name"`
+	Description string   `json:"description"`
+	TenantID    string   `json:"tenant_id"`
+	Audited     bool     `json:"audited"`
+	Shared      bool     `json:"shared"`
+	Rules       []string `json:"firewall_rules,omitempty"`
 }
 
 type commonResult struct {
@@ -22,17 +22,11 @@
 
 // Extract is a function that accepts a result and extracts a firewall policy.
 func (r commonResult) Extract() (*Policy, error) {
-	if r.Err != nil {
-		return nil, r.Err
+	var s struct {
+		Policy *Policy `json:"firewall_policy"`
 	}
-
-	var res struct {
-		Policy *Policy `json:"firewall_policy" mapstructure:"firewall_policy"`
-	}
-
-	err := mapstructure.Decode(r.Body, &res)
-
-	return res.Policy, err
+	err := r.ExtractInto(&s)
+	return s.Policy, err
 }
 
 // PolicyPage is the page returned by a pager when traversing over a
@@ -44,40 +38,32 @@
 // NextPageURL is invoked when a paginated collection of firewall policies has
 // reached the end of a page and the pager seeks to traverse over a new one.
 // In order to do this, it needs to construct the next page's URL.
-func (p PolicyPage) NextPageURL() (string, error) {
-	type resp struct {
-		Links []gophercloud.Link `mapstructure:"firewall_policies_links"`
+func (page PolicyPage) NextPageURL() (string, error) {
+	var s struct {
+		Links []gophercloud.Link `json:"firewall_policies_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)
 }
 
 // IsEmpty checks whether a PolicyPage struct is empty.
-func (p PolicyPage) IsEmpty() (bool, error) {
-	is, err := ExtractPolicies(p)
-	if err != nil {
-		return true, nil
-	}
-	return len(is) == 0, nil
+func (page PolicyPage) IsEmpty() (bool, error) {
+	is, err := ExtractPolicies(page)
+	return len(is) == 0, err
 }
 
 // ExtractPolicies accepts a Page struct, specifically a RouterPage struct,
 // and extracts the elements into a slice of Router structs. In other words,
 // a generic collection is mapped into a relevant slice.
 func ExtractPolicies(page pagination.Page) ([]Policy, error) {
-	var resp struct {
-		Policies []Policy `mapstructure:"firewall_policies" json:"firewall_policies"`
+	var s struct {
+		Policies []Policy `json:"firewall_policies"`
 	}
-
-	err := mapstructure.Decode(page.(PolicyPage).Body, &resp)
-
-	return resp.Policies, err
+	err := (page.(PolicyPage)).ExtractInto(&s)
+	return s.Policies, err
 }
 
 // GetResult represents the result of a get operation.
diff --git a/openstack/networking/v2/extensions/fwaas/rules/results.go b/openstack/networking/v2/extensions/fwaas/rules/results.go
index 42604f4..4afdf22 100644
--- a/openstack/networking/v2/extensions/fwaas/rules/results.go
+++ b/openstack/networking/v2/extensions/fwaas/rules/results.go
@@ -1,28 +1,27 @@
 package rules
 
 import (
-	"github.com/mitchellh/mapstructure"
 	"github.com/gophercloud/gophercloud"
 	"github.com/gophercloud/gophercloud/pagination"
 )
 
 // Rule represents a firewall rule
 type Rule struct {
-	ID                   string `json:"id" mapstructure:"id"`
-	Name                 string `json:"name,omitempty" mapstructure:"name"`
-	Description          string `json:"description,omitempty" mapstructure:"description"`
-	Protocol             string `json:"protocol" mapstructure:"protocol"`
-	Action               string `json:"action" mapstructure:"action"`
-	IPVersion            int    `json:"ip_version,omitempty" mapstructure:"ip_version"`
-	SourceIPAddress      string `json:"source_ip_address,omitempty" mapstructure:"source_ip_address"`
-	DestinationIPAddress string `json:"destination_ip_address,omitempty" mapstructure:"destination_ip_address"`
-	SourcePort           string `json:"source_port,omitempty" mapstructure:"source_port"`
-	DestinationPort      string `json:"destination_port,omitempty" mapstructure:"destination_port"`
-	Shared               bool   `json:"shared,omitempty" mapstructure:"shared"`
-	Enabled              bool   `json:"enabled,omitempty" mapstructure:"enabled"`
-	PolicyID             string `json:"firewall_policy_id" mapstructure:"firewall_policy_id"`
-	Position             int    `json:"position" mapstructure:"position"`
-	TenantID             string `json:"tenant_id" mapstructure:"tenant_id"`
+	ID                   string `json:"id"`
+	Name                 string `json:"name,omitempty"`
+	Description          string `json:"description,omitempty"`
+	Protocol             string `json:"protocol"`
+	Action               string `json:"action"`
+	IPVersion            int    `json:"ip_version,omitempty"`
+	SourceIPAddress      string `json:"source_ip_address,omitempty"`
+	DestinationIPAddress string `json:"destination_ip_address,omitempty"`
+	SourcePort           string `json:"source_port,omitempty"`
+	DestinationPort      string `json:"destination_port,omitempty"`
+	Shared               bool   `json:"shared,omitempty"`
+	Enabled              bool   `json:"enabled,omitempty"`
+	PolicyID             string `json:"firewall_policy_id"`
+	Position             int    `json:"position"`
+	TenantID             string `json:"tenant_id"`
 }
 
 // RulePage is the page returned by a pager when traversing over a
@@ -34,40 +33,33 @@
 // NextPageURL is invoked when a paginated collection of firewall rules has
 // reached the end of a page and the pager seeks to traverse over a new one.
 // In order to do this, it needs to construct the next page's URL.
-func (p RulePage) NextPageURL() (string, error) {
-	type resp struct {
-		Links []gophercloud.Link `mapstructure:"firewall_rules_links"`
+func (page RulePage) NextPageURL() (string, error) {
+	var s struct {
+		Links []gophercloud.Link `json:"firewall_rules_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)
 }
 
 // IsEmpty checks whether a RulePage struct is empty.
 func (p RulePage) IsEmpty() (bool, error) {
 	is, err := ExtractRules(p)
-	if err != nil {
-		return true, nil
-	}
-	return len(is) == 0, nil
+	return len(is) == 0, err
 }
 
 // ExtractRules accepts a Page struct, specifically a RouterPage struct,
 // and extracts the elements into a slice of Router structs. In other words,
 // a generic collection is mapped into a relevant slice.
 func ExtractRules(page pagination.Page) ([]Rule, error) {
-	var resp struct {
-		Rules []Rule `mapstructure:"firewall_rules" json:"firewall_rules"`
+	r := page.(RulePage)
+	var s struct {
+		Rules []Rule `json:"firewall_rules"`
 	}
-
-	err := mapstructure.Decode(page.(RulePage).Body, &resp)
-
-	return resp.Rules, err
+	err := r.ExtractInto(&s)
+	return s.Rules, err
 }
 
 type commonResult struct {
@@ -76,17 +68,11 @@
 
 // Extract is a function that accepts a result and extracts a firewall rule.
 func (r commonResult) Extract() (*Rule, error) {
-	if r.Err != nil {
-		return nil, r.Err
+	var s struct {
+		Rule *Rule `json:"firewall_rule"`
 	}
-
-	var res struct {
-		Rule *Rule `json:"firewall_rule" mapstructure:"firewall_rule"`
-	}
-
-	err := mapstructure.Decode(r.Body, &res)
-
-	return res.Rule, err
+	err := r.ExtractInto(&s)
+	return s.Rule, err
 }
 
 // GetResult represents the result of a get operation.
diff --git a/openstack/networking/v2/extensions/layer3/floatingips/results.go b/openstack/networking/v2/extensions/layer3/floatingips/results.go
index 264b7a8..c33b139 100644
--- a/openstack/networking/v2/extensions/layer3/floatingips/results.go
+++ b/openstack/networking/v2/extensions/layer3/floatingips/results.go
@@ -1,9 +1,6 @@
 package floatingips
 
 import (
-	"fmt"
-
-	"github.com/mitchellh/mapstructure"
 	"github.com/gophercloud/gophercloud"
 	"github.com/gophercloud/gophercloud/pagination"
 )
@@ -16,27 +13,27 @@
 // attribute (provided by the external network extension) is set to True.
 type FloatingIP struct {
 	// Unique identifier for the floating IP instance.
-	ID string `json:"id" mapstructure:"id"`
+	ID string `json:"id"`
 
 	// UUID of the external network where the floating IP is to be created.
-	FloatingNetworkID string `json:"floating_network_id" mapstructure:"floating_network_id"`
+	FloatingNetworkID string `json:"floating_network_id"`
 
 	// Address of the floating IP on the external network.
-	FloatingIP string `json:"floating_ip_address" mapstructure:"floating_ip_address"`
+	FloatingIP string `json:"floating_ip_address"`
 
 	// UUID of the port on an internal network that is associated with the floating IP.
-	PortID string `json:"port_id" mapstructure:"port_id"`
+	PortID string `json:"port_id"`
 
 	// The specific IP address of the internal port which should be associated
 	// with the floating IP.
-	FixedIP string `json:"fixed_ip_address" mapstructure:"fixed_ip_address"`
+	FixedIP string `json:"fixed_ip_address"`
 
 	// Owner of the floating IP. Only admin users can specify a tenant identifier
 	// other than its own.
-	TenantID string `json:"tenant_id" mapstructure:"tenant_id"`
+	TenantID string `json:"tenant_id"`
 
 	// The condition of the API resource.
-	Status string `json:"status" mapstructure:"status"`
+	Status string `json:"status"`
 }
 
 type commonResult struct {
@@ -45,20 +42,11 @@
 
 // Extract a result and extracts a FloatingIP resource.
 func (r commonResult) Extract() (*FloatingIP, error) {
-	if r.Err != nil {
-		return nil, r.Err
-	}
-
-	var res struct {
+	var s struct {
 		FloatingIP *FloatingIP `json:"floatingip"`
 	}
-
-	err := mapstructure.Decode(r.Body, &res)
-	if err != nil {
-		return nil, fmt.Errorf("Error decoding Neutron floating IP: %v", err)
-	}
-
-	return res.FloatingIP, nil
+	err := r.ExtractInto(&s)
+	return s.FloatingIP, err
 }
 
 // CreateResult represents the result of a create operation.
@@ -90,38 +78,31 @@
 // NextPageURL is invoked when a paginated collection of floating IPs has reached
 // the end of a page and the pager seeks to traverse over a new one. In order
 // to do this, it needs to construct the next page's URL.
-func (p FloatingIPPage) NextPageURL() (string, error) {
-	type resp struct {
-		Links []gophercloud.Link `mapstructure:"floatingips_links"`
+func (page FloatingIPPage) NextPageURL() (string, error) {
+	var s struct {
+		Links []gophercloud.Link `json:"floatingips_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)
 }
 
 // IsEmpty checks whether a NetworkPage struct is empty.
-func (p FloatingIPPage) IsEmpty() (bool, error) {
-	is, err := ExtractFloatingIPs(p)
-	if err != nil {
-		return true, nil
-	}
-	return len(is) == 0, nil
+func (page FloatingIPPage) IsEmpty() (bool, error) {
+	is, err := ExtractFloatingIPs(page)
+	return len(is) == 0, err
 }
 
 // ExtractFloatingIPs accepts a Page struct, specifically a FloatingIPPage struct,
 // and extracts the elements into a slice of FloatingIP structs. In other words,
 // a generic collection is mapped into a relevant slice.
 func ExtractFloatingIPs(page pagination.Page) ([]FloatingIP, error) {
-	var resp struct {
-		FloatingIPs []FloatingIP `mapstructure:"floatingips" json:"floatingips"`
+	r := page.(FloatingIPPage)
+	var s struct {
+		FloatingIPs []FloatingIP `json:"floatingips"`
 	}
-
-	err := mapstructure.Decode(page.(FloatingIPPage).Body, &resp)
-
-	return resp.FloatingIPs, err
+	err := r.ExtractInto(&s)
+	return s.FloatingIPs, err
 }
diff --git a/openstack/networking/v2/extensions/layer3/routers/results.go b/openstack/networking/v2/extensions/layer3/routers/results.go
index 2360501..e26f243 100644
--- a/openstack/networking/v2/extensions/layer3/routers/results.go
+++ b/openstack/networking/v2/extensions/layer3/routers/results.go
@@ -1,7 +1,6 @@
 package routers
 
 import (
-	"github.com/mitchellh/mapstructure"
 	"github.com/gophercloud/gophercloud"
 	"github.com/gophercloud/gophercloud/pagination"
 )
@@ -9,12 +8,13 @@
 // GatewayInfo represents the information of an external gateway for any
 // particular network router.
 type GatewayInfo struct {
-	NetworkID string `json:"network_id" mapstructure:"network_id"`
+	NetworkID string `json:"network_id"`
 }
 
+// Route is a possible route in a router.
 type Route struct {
-	NextHop         string `mapstructure:"nexthop" json:"nexthop"`
-	DestinationCIDR string `mapstructure:"destination" json:"destination"`
+	NextHop         string `json:"nexthop"`
+	DestinationCIDR string `json:"destination"`
 }
 
 // Router represents a Neutron router. A router is a logical entity that
@@ -27,28 +27,28 @@
 // interface is added to the subnet's network.
 type Router struct {
 	// Indicates whether or not a router is currently operational.
-	Status string `json:"status" mapstructure:"status"`
+	Status string `json:"status"`
 
 	// Information on external gateway for the router.
-	GatewayInfo GatewayInfo `json:"external_gateway_info" mapstructure:"external_gateway_info"`
+	GatewayInfo GatewayInfo `json:"external_gateway_info"`
 
 	// Administrative state of the router.
-	AdminStateUp bool `json:"admin_state_up" mapstructure:"admin_state_up"`
+	AdminStateUp bool `json:"admin_state_up"`
 
 	// Whether router is disitrubted or not..
-	Distributed bool `json:"distributed" mapstructure:"distributed"`
+	Distributed bool `json:"distributed"`
 
 	// Human readable name for the router. Does not have to be unique.
-	Name string `json:"name" mapstructure:"name"`
+	Name string `json:"name"`
 
 	// Unique identifier for the router.
-	ID string `json:"id" mapstructure:"id"`
+	ID string `json:"id"`
 
 	// Owner of the router. Only admin users can specify a tenant identifier
 	// other than its own.
-	TenantID string `json:"tenant_id" mapstructure:"tenant_id"`
+	TenantID string `json:"tenant_id"`
 
-	Routes []Route `json:"routes" mapstructure:"routes"`
+	Routes []Route `json:"routes"`
 }
 
 // RouterPage is the page returned by a pager when traversing over a
@@ -60,40 +60,33 @@
 // NextPageURL is invoked when a paginated collection of routers has reached
 // the end of a page and the pager seeks to traverse over a new one. In order
 // to do this, it needs to construct the next page's URL.
-func (p RouterPage) NextPageURL() (string, error) {
-	type resp struct {
-		Links []gophercloud.Link `mapstructure:"routers_links"`
+func (page RouterPage) NextPageURL() (string, error) {
+	var s struct {
+		Links []gophercloud.Link `json:"routers_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)
 }
 
 // IsEmpty checks whether a RouterPage struct is empty.
-func (p RouterPage) IsEmpty() (bool, error) {
-	is, err := ExtractRouters(p)
-	if err != nil {
-		return true, nil
-	}
-	return len(is) == 0, nil
+func (page RouterPage) IsEmpty() (bool, error) {
+	is, err := ExtractRouters(page)
+	return len(is) == 0, err
 }
 
 // ExtractRouters accepts a Page struct, specifically a RouterPage struct,
 // and extracts the elements into a slice of Router structs. In other words,
 // a generic collection is mapped into a relevant slice.
 func ExtractRouters(page pagination.Page) ([]Router, error) {
-	var resp struct {
-		Routers []Router `mapstructure:"routers" json:"routers"`
+	r := page.(RouterPage)
+	var s struct {
+		Routers []Router `json:"routers"`
 	}
-
-	err := mapstructure.Decode(page.(RouterPage).Body, &resp)
-
-	return resp.Routers, err
+	err := r.ExtractInto(&s)
+	return s.Routers, err
 }
 
 type commonResult struct {
@@ -102,17 +95,11 @@
 
 // Extract is a function that accepts a result and extracts a router.
 func (r commonResult) Extract() (*Router, error) {
-	if r.Err != nil {
-		return nil, r.Err
-	}
-
-	var res struct {
+	var s struct {
 		Router *Router `json:"router"`
 	}
-
-	err := mapstructure.Decode(r.Body, &res)
-
-	return res.Router, err
+	err := r.ExtractInto(&s)
+	return s.Router, err
 }
 
 // CreateResult represents the result of a create operation.
@@ -140,16 +127,16 @@
 // interface.
 type InterfaceInfo struct {
 	// The ID of the subnet which this interface is associated with.
-	SubnetID string `json:"subnet_id" mapstructure:"subnet_id"`
+	SubnetID string `json:"subnet_id"`
 
 	// The ID of the port that is a part of the subnet.
-	PortID string `json:"port_id" mapstructure:"port_id"`
+	PortID string `json:"port_id"`
 
 	// The UUID of the interface.
-	ID string `json:"id" mapstructure:"id"`
+	ID string `json:"id"`
 
 	// Owner of the interface.
-	TenantID string `json:"tenant_id" mapstructure:"tenant_id"`
+	TenantID string `json:"tenant_id"`
 }
 
 // InterfaceResult represents the result of interface operations, such as
@@ -160,12 +147,7 @@
 
 // Extract is a function that accepts a result and extracts an information struct.
 func (r InterfaceResult) Extract() (*InterfaceInfo, error) {
-	if r.Err != nil {
-		return nil, r.Err
-	}
-
-	var res *InterfaceInfo
-	err := mapstructure.Decode(r.Body, &res)
-
-	return res, err
+	var s InterfaceInfo
+	err := r.ExtractInto(&s)
+	return &s, err
 }
diff --git a/openstack/networking/v2/extensions/lbaas/members/results.go b/openstack/networking/v2/extensions/lbaas/members/results.go
index b948706..ae9f341 100644
--- a/openstack/networking/v2/extensions/lbaas/members/results.go
+++ b/openstack/networking/v2/extensions/lbaas/members/results.go
@@ -1,7 +1,6 @@
 package members
 
 import (
-	"github.com/mitchellh/mapstructure"
 	"github.com/gophercloud/gophercloud"
 	"github.com/gophercloud/gophercloud/pagination"
 )
@@ -15,20 +14,20 @@
 	Weight int
 
 	// The administrative state of the member, which is up (true) or down (false).
-	AdminStateUp bool `json:"admin_state_up" mapstructure:"admin_state_up"`
+	AdminStateUp bool `json:"admin_state_up"`
 
 	// Owner of the member. Only an administrative user can specify a tenant ID
 	// other than its own.
-	TenantID string `json:"tenant_id" mapstructure:"tenant_id"`
+	TenantID string `json:"tenant_id"`
 
 	// The pool to which the member belongs.
-	PoolID string `json:"pool_id" mapstructure:"pool_id"`
+	PoolID string `json:"pool_id"`
 
 	// The IP address of the member.
 	Address string
 
 	// The port on which the application is hosted.
-	ProtocolPort int `json:"protocol_port" mapstructure:"protocol_port"`
+	ProtocolPort int `json:"protocol_port"`
 
 	// The unique ID for the member.
 	ID string
@@ -43,43 +42,33 @@
 // NextPageURL is invoked when a paginated collection of members has reached
 // the end of a page and the pager seeks to traverse over a new one. In order
 // to do this, it needs to construct the next page's URL.
-func (p MemberPage) NextPageURL() (string, error) {
-	type resp struct {
-		Links []gophercloud.Link `mapstructure:"members_links"`
+func (page MemberPage) NextPageURL() (string, error) {
+	var s struct {
+		Links []gophercloud.Link `json:"members_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)
 }
 
 // IsEmpty checks whether a MemberPage struct is empty.
-func (p MemberPage) IsEmpty() (bool, error) {
-	is, err := ExtractMembers(p)
-	if err != nil {
-		return true, nil
-	}
-	return len(is) == 0, nil
+func (page MemberPage) IsEmpty() (bool, error) {
+	is, err := ExtractMembers(page)
+	return len(is) == 0, err
 }
 
 // ExtractMembers accepts a Page struct, specifically a MemberPage struct,
 // and extracts the elements into a slice of Member structs. In other words,
 // a generic collection is mapped into a relevant slice.
 func ExtractMembers(page pagination.Page) ([]Member, error) {
-	var resp struct {
-		Members []Member `mapstructure:"members" json:"members"`
+	r := page.(MemberPage)
+	var s struct {
+		Members []Member `json:"members"`
 	}
-
-	err := mapstructure.Decode(page.(MemberPage).Body, &resp)
-	if err != nil {
-		return nil, err
-	}
-
-	return resp.Members, nil
+	err := r.ExtractInto(&s)
+	return s.Members, err
 }
 
 type commonResult struct {
@@ -88,17 +77,11 @@
 
 // Extract is a function that accepts a result and extracts a router.
 func (r commonResult) Extract() (*Member, error) {
-	if r.Err != nil {
-		return nil, r.Err
-	}
-
-	var res struct {
+	var s struct {
 		Member *Member `json:"member"`
 	}
-
-	err := mapstructure.Decode(r.Body, &res)
-
-	return res.Member, err
+	err := r.ExtractInto(&s)
+	return s.Member, err
 }
 
 // CreateResult represents the result of a create operation.
diff --git a/openstack/networking/v2/extensions/lbaas/monitors/results.go b/openstack/networking/v2/extensions/lbaas/monitors/results.go
index 5303df5..86c24bd 100644
--- a/openstack/networking/v2/extensions/lbaas/monitors/results.go
+++ b/openstack/networking/v2/extensions/lbaas/monitors/results.go
@@ -1,7 +1,6 @@
 package monitors
 
 import (
-	"github.com/mitchellh/mapstructure"
 	"github.com/gophercloud/gophercloud"
 	"github.com/gophercloud/gophercloud/pagination"
 )
@@ -27,7 +26,7 @@
 
 	// Owner of the VIP. Only an administrative user can specify a tenant ID
 	// other than its own.
-	TenantID string `json:"tenant_id" mapstructure:"tenant_id"`
+	TenantID string `json:"tenant_id"`
 
 	// The type of probe sent by the load balancer to verify the member state,
 	// which is PING, TCP, HTTP, or HTTPS.
@@ -42,20 +41,20 @@
 
 	// Number of allowed connection failures before changing the status of the
 	// member to INACTIVE. A valid value is from 1 to 10.
-	MaxRetries int `json:"max_retries" mapstructure:"max_retries"`
+	MaxRetries int `json:"max_retries"`
 
 	// The HTTP method that the monitor uses for requests.
-	HTTPMethod string `json:"http_method" mapstructure:"http_method"`
+	HTTPMethod string `json:"http_method"`
 
 	// The HTTP path of the request sent by the monitor to test the health of a
 	// member. Must be a string beginning with a forward slash (/).
-	URLPath string `json:"url_path" mapstructure:"url_path"`
+	URLPath string `json:"url_path"`
 
 	// Expected HTTP codes for a passing HTTP(S) monitor.
-	ExpectedCodes string `json:"expected_codes" mapstructure:"expected_codes"`
+	ExpectedCodes string `json:"expected_codes"`
 
 	// The administrative state of the health monitor, which is up (true) or down (false).
-	AdminStateUp bool `json:"admin_state_up" mapstructure:"admin_state_up"`
+	AdminStateUp bool `json:"admin_state_up"`
 
 	// The status of the health monitor. Indicates whether the health monitor is
 	// operational.
@@ -71,40 +70,34 @@
 // NextPageURL is invoked when a paginated collection of monitors has reached
 // the end of a page and the pager seeks to traverse over a new one. In order
 // to do this, it needs to construct the next page's URL.
-func (p MonitorPage) NextPageURL() (string, error) {
-	type resp struct {
-		Links []gophercloud.Link `mapstructure:"health_monitors_links"`
+func (page MonitorPage) NextPageURL() (string, error) {
+	var s struct {
+		Links []gophercloud.Link `json:"health_monitors_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)
 }
 
 // IsEmpty checks whether a PoolPage struct is empty.
-func (p MonitorPage) IsEmpty() (bool, error) {
-	is, err := ExtractMonitors(p)
-	if err != nil {
-		return true, nil
-	}
-	return len(is) == 0, nil
+func (page MonitorPage) IsEmpty() (bool, error) {
+	is, err := ExtractMonitors(page)
+	return len(is) == 0, err
 }
 
 // ExtractMonitors accepts a Page struct, specifically a MonitorPage struct,
 // and extracts the elements into a slice of Monitor structs. In other words,
 // a generic collection is mapped into a relevant slice.
 func ExtractMonitors(page pagination.Page) ([]Monitor, error) {
-	var resp struct {
-		Monitors []Monitor `mapstructure:"health_monitors" json:"health_monitors"`
+	r := page.(MonitorPage)
+	var s struct {
+		Monitors []Monitor `json:"health_monitors"`
 	}
-
-	err := mapstructure.Decode(page.(MonitorPage).Body, &resp)
-
-	return resp.Monitors, err
+	err := r.ExtractInto(&s)
+	return s.Monitors, err
 }
 
 type commonResult struct {
@@ -113,17 +106,11 @@
 
 // Extract is a function that accepts a result and extracts a monitor.
 func (r commonResult) Extract() (*Monitor, error) {
-	if r.Err != nil {
-		return nil, r.Err
+	var s struct {
+		Monitor *Monitor `json:"health_monitor"`
 	}
-
-	var res struct {
-		Monitor *Monitor `json:"health_monitor" mapstructure:"health_monitor"`
-	}
-
-	err := mapstructure.Decode(r.Body, &res)
-
-	return res.Monitor, err
+	err := r.ExtractInto(&s)
+	return s.Monitor, err
 }
 
 // CreateResult represents the result of a create operation.
diff --git a/openstack/networking/v2/extensions/lbaas/pools/results.go b/openstack/networking/v2/extensions/lbaas/pools/results.go
index 3308002..135046a 100644
--- a/openstack/networking/v2/extensions/lbaas/pools/results.go
+++ b/openstack/networking/v2/extensions/lbaas/pools/results.go
@@ -1,7 +1,6 @@
 package pools
 
 import (
-	"github.com/mitchellh/mapstructure"
 	"github.com/gophercloud/gophercloud"
 	"github.com/gophercloud/gophercloud/pagination"
 )
@@ -18,7 +17,7 @@
 	// The load-balancer algorithm, which is round-robin, least-connections, and
 	// so on. This value, which must be supported, is dependent on the provider.
 	// Round-robin must be supported.
-	LBMethod string `json:"lb_method" mapstructure:"lb_method"`
+	LBMethod string `json:"lb_method"`
 
 	// The protocol of the pool, which is TCP, HTTP, or HTTPS.
 	Protocol string
@@ -27,30 +26,30 @@
 	Description string
 
 	// The IDs of associated monitors which check the health of the pool members.
-	MonitorIDs []string `json:"health_monitors" mapstructure:"health_monitors"`
+	MonitorIDs []string `json:"health_monitors"`
 
 	// The network on which the members of the pool will be located. Only members
 	// that are on this network can be added to the pool.
-	SubnetID string `json:"subnet_id" mapstructure:"subnet_id"`
+	SubnetID string `json:"subnet_id"`
 
 	// Owner of the pool. Only an administrative user can specify a tenant ID
 	// other than its own.
-	TenantID string `json:"tenant_id" mapstructure:"tenant_id"`
+	TenantID string `json:"tenant_id"`
 
 	// The administrative state of the pool, which is up (true) or down (false).
-	AdminStateUp bool `json:"admin_state_up" mapstructure:"admin_state_up"`
+	AdminStateUp bool `json:"admin_state_up"`
 
 	// Pool name. Does not have to be unique.
 	Name string
 
 	// List of member IDs that belong to the pool.
-	MemberIDs []string `json:"members" mapstructure:"members"`
+	MemberIDs []string `json:"members"`
 
 	// The unique ID for the pool.
 	ID string
 
 	// The ID of the virtual IP associated with this pool
-	VIPID string `json:"vip_id" mapstructure:"vip_id"`
+	VIPID string `json:"vip_id"`
 
 	// The provider
 	Provider string
@@ -65,40 +64,33 @@
 // NextPageURL is invoked when a paginated collection of pools has reached
 // the end of a page and the pager seeks to traverse over a new one. In order
 // to do this, it needs to construct the next page's URL.
-func (p PoolPage) NextPageURL() (string, error) {
-	type resp struct {
-		Links []gophercloud.Link `mapstructure:"pools_links"`
+func (page PoolPage) NextPageURL() (string, error) {
+	var s struct {
+		Links []gophercloud.Link `json:"pools_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)
 }
 
 // IsEmpty checks whether a PoolPage struct is empty.
-func (p PoolPage) IsEmpty() (bool, error) {
-	is, err := ExtractPools(p)
-	if err != nil {
-		return true, nil
-	}
-	return len(is) == 0, nil
+func (page PoolPage) IsEmpty() (bool, error) {
+	is, err := ExtractPools(page)
+	return len(is) == 0, err
 }
 
 // ExtractPools accepts a Page struct, specifically a RouterPage struct,
 // and extracts the elements into a slice of Router structs. In other words,
 // a generic collection is mapped into a relevant slice.
 func ExtractPools(page pagination.Page) ([]Pool, error) {
-	var resp struct {
-		Pools []Pool `mapstructure:"pools" json:"pools"`
+	r := page.(PoolPage)
+	var s struct {
+		Pools []Pool `json:"pools"`
 	}
-
-	err := mapstructure.Decode(page.(PoolPage).Body, &resp)
-
-	return resp.Pools, err
+	err := r.ExtractInto(&s)
+	return s.Pools, err
 }
 
 type commonResult struct {
@@ -107,17 +99,11 @@
 
 // Extract is a function that accepts a result and extracts a router.
 func (r commonResult) Extract() (*Pool, error) {
-	if r.Err != nil {
-		return nil, r.Err
-	}
-
-	var res struct {
+	var s struct {
 		Pool *Pool `json:"pool"`
 	}
-
-	err := mapstructure.Decode(r.Body, &res)
-
-	return res.Pool, err
+	err := r.ExtractInto(&s)
+	return s.Pool, err
 }
 
 // CreateResult represents the result of a create operation.
diff --git a/openstack/networking/v2/extensions/lbaas/vips/results.go b/openstack/networking/v2/extensions/lbaas/vips/results.go
index d7322ca..398c981 100644
--- a/openstack/networking/v2/extensions/lbaas/vips/results.go
+++ b/openstack/networking/v2/extensions/lbaas/vips/results.go
@@ -1,7 +1,6 @@
 package vips
 
 import (
-	"github.com/mitchellh/mapstructure"
 	"github.com/gophercloud/gophercloud"
 	"github.com/gophercloud/gophercloud/pagination"
 )
@@ -23,10 +22,10 @@
 //              same member of the pool.
 type SessionPersistence struct {
 	// The type of persistence mode
-	Type string `mapstructure:"type" json:"type"`
+	Type string `json:"type"`
 
 	// Name of cookie if persistence mode is set appropriately
-	CookieName string `mapstructure:"cookie_name" json:"cookie_name,omitempty"`
+	CookieName string `json:"cookie_name,omitempty"`
 }
 
 // VirtualIP is the primary load balancing configuration object that specifies
@@ -36,49 +35,49 @@
 // server", a "vserver" or a "listener".
 type VirtualIP struct {
 	// The unique ID for the VIP.
-	ID string `mapstructure:"id" json:"id"`
+	ID string `json:"id"`
 
 	// Owner of the VIP. Only an admin user can specify a tenant ID other than its own.
-	TenantID string `mapstructure:"tenant_id" json:"tenant_id"`
+	TenantID string `json:"tenant_id"`
 
 	// Human-readable name for the VIP. Does not have to be unique.
-	Name string `mapstructure:"name" json:"name"`
+	Name string `json:"name"`
 
 	// Human-readable description for the VIP.
-	Description string `mapstructure:"description" json:"description"`
+	Description string `json:"description"`
 
 	// The ID of the subnet on which to allocate the VIP address.
-	SubnetID string `mapstructure:"subnet_id" json:"subnet_id"`
+	SubnetID string `json:"subnet_id"`
 
 	// The IP address of the VIP.
-	Address string `mapstructure:"address" json:"address"`
+	Address string `json:"address"`
 
 	// The protocol of the VIP address. A valid value is TCP, HTTP, or HTTPS.
-	Protocol string `mapstructure:"protocol" json:"protocol"`
+	Protocol string `json:"protocol"`
 
 	// The port on which to listen to client traffic that is associated with the
 	// VIP address. A valid value is from 0 to 65535.
-	ProtocolPort int `mapstructure:"protocol_port" json:"protocol_port"`
+	ProtocolPort int `json:"protocol_port"`
 
 	// The ID of the pool with which the VIP is associated.
-	PoolID string `mapstructure:"pool_id" json:"pool_id"`
+	PoolID string `json:"pool_id"`
 
 	// The ID of the port which belongs to the load balancer
-	PortID string `mapstructure:"port_id" json:"port_id"`
+	PortID string `json:"port_id"`
 
 	// Indicates whether connections in the same session will be processed by the
 	// same pool member or not.
-	Persistence SessionPersistence `mapstructure:"session_persistence" json:"session_persistence"`
+	Persistence SessionPersistence `json:"session_persistence"`
 
 	// The maximum number of connections allowed for the VIP. Default is -1,
 	// meaning no limit.
-	ConnLimit int `mapstructure:"connection_limit" json:"connection_limit"`
+	ConnLimit int `json:"connection_limit"`
 
 	// The administrative state of the VIP. A valid value is true (UP) or false (DOWN).
-	AdminStateUp bool `mapstructure:"admin_state_up" json:"admin_state_up"`
+	AdminStateUp bool `json:"admin_state_up"`
 
 	// The status of the VIP. Indicates whether the VIP is operational.
-	Status string `mapstructure:"status" json:"status"`
+	Status string `json:"status"`
 }
 
 // VIPPage is the page returned by a pager when traversing over a
@@ -90,40 +89,33 @@
 // NextPageURL is invoked when a paginated collection of routers has reached
 // the end of a page and the pager seeks to traverse over a new one. In order
 // to do this, it needs to construct the next page's URL.
-func (p VIPPage) NextPageURL() (string, error) {
-	type resp struct {
-		Links []gophercloud.Link `mapstructure:"vips_links"`
+func (page VIPPage) NextPageURL() (string, error) {
+	var s struct {
+		Links []gophercloud.Link `json:"vips_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)
 }
 
-// IsEmpty checks whether a RouterPage struct is empty.
-func (p VIPPage) IsEmpty() (bool, error) {
-	is, err := ExtractVIPs(p)
-	if err != nil {
-		return true, nil
-	}
-	return len(is) == 0, nil
+// IsEmpty checks whether a VIPPage struct is empty.
+func (page VIPPage) IsEmpty() (bool, error) {
+	is, err := ExtractVIPs(page)
+	return len(is) == 0, err
 }
 
 // ExtractVIPs accepts a Page struct, specifically a VIPPage struct,
 // and extracts the elements into a slice of VirtualIP structs. In other words,
 // a generic collection is mapped into a relevant slice.
 func ExtractVIPs(page pagination.Page) ([]VirtualIP, error) {
-	var resp struct {
-		VIPs []VirtualIP `mapstructure:"vips" json:"vips"`
+	r := page.(VIPPage)
+	var s struct {
+		VIPs []VirtualIP `json:"vips"`
 	}
-
-	err := mapstructure.Decode(page.(VIPPage).Body, &resp)
-
-	return resp.VIPs, err
+	err := r.ExtractInto(&s)
+	return s.VIPs, err
 }
 
 type commonResult struct {
@@ -132,17 +124,11 @@
 
 // Extract is a function that accepts a result and extracts a router.
 func (r commonResult) Extract() (*VirtualIP, error) {
-	if r.Err != nil {
-		return nil, r.Err
+	var s struct {
+		VirtualIP *VirtualIP `json:"vip" json:"vip"`
 	}
-
-	var res struct {
-		VirtualIP *VirtualIP `mapstructure:"vip" json:"vip"`
-	}
-
-	err := mapstructure.Decode(r.Body, &res)
-
-	return res.VirtualIP, err
+	err := r.ExtractInto(&s)
+	return s.VirtualIP, err
 }
 
 // CreateResult represents the result of a create operation.
diff --git a/openstack/networking/v2/extensions/provider/results.go b/openstack/networking/v2/extensions/provider/results.go
index 9590ae5..f437461 100755
--- a/openstack/networking/v2/extensions/provider/results.go
+++ b/openstack/networking/v2/extensions/provider/results.go
@@ -1,7 +1,6 @@
 package provider
 
 import (
-	"github.com/mitchellh/mapstructure"
 	"github.com/gophercloud/gophercloud/openstack/networking/v2/networks"
 	"github.com/gophercloud/gophercloud/pagination"
 )
@@ -22,30 +21,30 @@
 // NetworkExtAttrs represents an extended form of a Network with additional fields.
 type NetworkExtAttrs struct {
 	// UUID for the network
-	ID string `mapstructure:"id" json:"id"`
+	ID string `json:"id"`
 
 	// Human-readable name for the network. Might not be unique.
-	Name string `mapstructure:"name" json:"name"`
+	Name string `json:"name"`
 
 	// The administrative state of network. If false (down), the network does not forward packets.
-	AdminStateUp bool `mapstructure:"admin_state_up" json:"admin_state_up"`
+	AdminStateUp bool `json:"admin_state_up"`
 
 	// Indicates whether network is currently operational. Possible values include
 	// `ACTIVE', `DOWN', `BUILD', or `ERROR'. Plug-ins might define additional values.
-	Status string `mapstructure:"status" json:"status"`
+	Status string `json:"status"`
 
 	// Subnets associated with this network.
-	Subnets []string `mapstructure:"subnets" json:"subnets"`
+	Subnets []string `json:"subnets"`
 
 	// Owner of network. Only admin users can specify a tenant_id other than its own.
-	TenantID string `mapstructure:"tenant_id" json:"tenant_id"`
+	TenantID string `json:"tenant_id"`
 
 	// Specifies whether the network resource can be accessed by any tenant or not.
-	Shared bool `mapstructure:"shared" json:"shared"`
+	Shared bool `json:"shared"`
 
 	// Specifies the nature of the physical network mapped to this network
 	// resource. Examples are flat, vlan, or gre.
-	NetworkType string `json:"provider:network_type" mapstructure:"provider:network_type"`
+	NetworkType string `json:"provider:network_type"`
 
 	// Identifies the physical network on top of which this network object is
 	// being implemented. The OpenStack Networking API does not expose any facility
@@ -53,72 +52,53 @@
 	// the Open vSwitch plug-in this is a symbolic name which is then mapped to
 	// specific bridges on each compute host through the Open vSwitch plug-in
 	// configuration file.
-	PhysicalNetwork string `json:"provider:physical_network" mapstructure:"provider:physical_network"`
+	PhysicalNetwork string `json:"provider:physical_network"`
 
 	// Identifies an isolated segment on the physical network; the nature of the
 	// segment depends on the segmentation model defined by network_type. For
 	// instance, if network_type is vlan, then this is a vlan identifier;
 	// otherwise, if network_type is gre, then this will be a gre key.
-	SegmentationID string `json:"provider:segmentation_id" mapstructure:"provider:segmentation_id"`
+	SegmentationID string `json:"provider:segmentation_id"`
 }
 
 // ExtractGet decorates a GetResult struct returned from a networks.Get()
 // function with extended attributes.
 func ExtractGet(r networks.GetResult) (*NetworkExtAttrs, error) {
-	if r.Err != nil {
-		return nil, r.Err
-	}
-
-	var res struct {
+	var s struct {
 		Network *NetworkExtAttrs `json:"network"`
 	}
-
-	err := mapstructure.WeakDecode(r.Body, &res)
-
-	return res.Network, err
+	err := r.ExtractInto(&s)
+	return s.Network, err
 }
 
 // ExtractCreate decorates a CreateResult struct returned from a networks.Create()
 // function with extended attributes.
 func ExtractCreate(r networks.CreateResult) (*NetworkExtAttrs, error) {
-	if r.Err != nil {
-		return nil, r.Err
-	}
-
-	var res struct {
+	var s struct {
 		Network *NetworkExtAttrs `json:"network"`
 	}
-
-	err := mapstructure.WeakDecode(r.Body, &res)
-
-	return res.Network, err
+	err := r.ExtractInto(&s)
+	return s.Network, err
 }
 
 // ExtractUpdate decorates a UpdateResult struct returned from a
 // networks.Update() function with extended attributes.
 func ExtractUpdate(r networks.UpdateResult) (*NetworkExtAttrs, error) {
-	if r.Err != nil {
-		return nil, r.Err
-	}
-
-	var res struct {
+	var s struct {
 		Network *NetworkExtAttrs `json:"network"`
 	}
-
-	err := mapstructure.WeakDecode(r.Body, &res)
-
-	return res.Network, err
+	err := r.ExtractInto(&s)
+	return s.Network, err
 }
 
 // ExtractList accepts a Page struct, specifically a NetworkPage struct, and
 // extracts the elements into a slice of NetworkExtAttrs structs. In other
 // words, a generic collection is mapped into a relevant slice.
 func ExtractList(page pagination.Page) ([]NetworkExtAttrs, error) {
-	var resp struct {
-		Networks []NetworkExtAttrs `mapstructure:"networks" json:"networks"`
+	r := page.(networks.NetworkPage)
+	var s struct {
+		Networks []NetworkExtAttrs `json:"networks" json:"networks"`
 	}
-
-	err := mapstructure.WeakDecode(page.(networks.NetworkPage).Body, &resp)
-
-	return resp.Networks, err
+	err := r.ExtractInto(&s)
+	return s.Networks, err
 }
diff --git a/openstack/networking/v2/extensions/provider/results_test.go b/openstack/networking/v2/extensions/provider/results_test.go
index 90d6ad1..59f06cc 100644
--- a/openstack/networking/v2/extensions/provider/results_test.go
+++ b/openstack/networking/v2/extensions/provider/results_test.go
@@ -49,7 +49,7 @@
             "tenant_id": "26a7980765d0414dbc1fc1f88cdb7e6e",
             "shared": true,
             "id": "db193ab3-96e3-4cb3-8fc5-05f4296d0324",
-            "provider:segmentation_id": 1234567890,
+            "provider:segmentation_id": "1234567890",
             "provider:physical_network": null,
             "provider:network_type": "local"
         }
diff --git a/openstack/networking/v2/extensions/security/groups/results.go b/openstack/networking/v2/extensions/security/groups/results.go
index 9530cde..7479e19 100644
--- a/openstack/networking/v2/extensions/security/groups/results.go
+++ b/openstack/networking/v2/extensions/security/groups/results.go
@@ -1,7 +1,6 @@
 package groups
 
 import (
-	"github.com/mitchellh/mapstructure"
 	"github.com/gophercloud/gophercloud"
 	"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/rules"
 	"github.com/gophercloud/gophercloud/pagination"
@@ -21,11 +20,11 @@
 
 	// A slice of security group rules that dictate the permitted behaviour for
 	// traffic entering and leaving the group.
-	Rules []rules.SecGroupRule `json:"security_group_rules" mapstructure:"security_group_rules"`
+	Rules []rules.SecGroupRule `json:"security_group_rules"`
 
 	// Owner of the security group. Only admin users can specify a TenantID
 	// other than their own.
-	TenantID string `json:"tenant_id" mapstructure:"tenant_id"`
+	TenantID string `json:"tenant_id"`
 }
 
 // SecGroupPage is the page returned by a pager when traversing over a
@@ -37,40 +36,34 @@
 // NextPageURL is invoked when a paginated collection of security groups has
 // reached the end of a page and the pager seeks to traverse over a new one. In
 // order to do this, it needs to construct the next page's URL.
-func (p SecGroupPage) NextPageURL() (string, error) {
-	type resp struct {
-		Links []gophercloud.Link `mapstructure:"security_groups_links"`
+func (page SecGroupPage) NextPageURL() (string, error) {
+	var s struct {
+		Links []gophercloud.Link `json:"security_groups_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)
 }
 
 // IsEmpty checks whether a SecGroupPage struct is empty.
-func (p SecGroupPage) IsEmpty() (bool, error) {
-	is, err := ExtractGroups(p)
-	if err != nil {
-		return true, nil
-	}
-	return len(is) == 0, nil
+func (page SecGroupPage) IsEmpty() (bool, error) {
+	is, err := ExtractGroups(page)
+	return len(is) == 0, err
 }
 
 // ExtractGroups accepts a Page struct, specifically a SecGroupPage struct,
 // and extracts the elements into a slice of SecGroup structs. In other words,
 // a generic collection is mapped into a relevant slice.
 func ExtractGroups(page pagination.Page) ([]SecGroup, error) {
-	var resp struct {
-		SecGroups []SecGroup `mapstructure:"security_groups" json:"security_groups"`
+	r := page.(SecGroupPage)
+	var s struct {
+		SecGroups []SecGroup `json:"security_groups"`
 	}
-
-	err := mapstructure.Decode(page.(SecGroupPage).Body, &resp)
-
-	return resp.SecGroups, err
+	err := r.ExtractInto(&s)
+	return s.SecGroups, err
 }
 
 type commonResult struct {
@@ -79,17 +72,11 @@
 
 // Extract is a function that accepts a result and extracts a security group.
 func (r commonResult) Extract() (*SecGroup, error) {
-	if r.Err != nil {
-		return nil, r.Err
+	var s struct {
+		SecGroup *SecGroup `json:"security_group"`
 	}
-
-	var res struct {
-		SecGroup *SecGroup `mapstructure:"security_group" json:"security_group"`
-	}
-
-	err := mapstructure.Decode(r.Body, &res)
-
-	return res.SecGroup, err
+	err := r.ExtractInto(&s)
+	return s.SecGroup, err
 }
 
 // CreateResult represents the result of a create operation.
diff --git a/openstack/networking/v2/extensions/security/rules/results.go b/openstack/networking/v2/extensions/security/rules/results.go
index 1181ebb..a9d6f1b 100644
--- a/openstack/networking/v2/extensions/security/rules/results.go
+++ b/openstack/networking/v2/extensions/security/rules/results.go
@@ -1,7 +1,6 @@
 package rules
 
 import (
-	"github.com/mitchellh/mapstructure"
 	"github.com/gophercloud/gophercloud"
 	"github.com/gophercloud/gophercloud/pagination"
 )
@@ -20,21 +19,21 @@
 
 	// Must be IPv4 or IPv6, and addresses represented in CIDR must match the
 	// ingress or egress rules.
-	EtherType string `json:"ethertype" mapstructure:"ethertype"`
+	EtherType string `json:"ethertype"`
 
 	// The security group ID to associate with this security group rule.
-	SecGroupID string `json:"security_group_id" mapstructure:"security_group_id"`
+	SecGroupID string `json:"security_group_id"`
 
 	// The minimum port number in the range that is matched by the security group
 	// rule. If the protocol is TCP or UDP, this value must be less than or equal
 	// to the value of the PortRangeMax attribute. If the protocol is ICMP, this
 	// value must be an ICMP type.
-	PortRangeMin int `json:"port_range_min" mapstructure:"port_range_min"`
+	PortRangeMin int `json:"port_range_min"`
 
 	// The maximum port number in the range that is matched by the security group
 	// rule. The PortRangeMin attribute constrains the PortRangeMax attribute. If
 	// the protocol is ICMP, this value must be an ICMP type.
-	PortRangeMax int `json:"port_range_max" mapstructure:"port_range_max"`
+	PortRangeMax int `json:"port_range_max"`
 
 	// The protocol that is matched by the security group rule. Valid values are
 	// "tcp", "udp", "icmp" or an empty string.
@@ -42,15 +41,15 @@
 
 	// The remote group ID to be associated with this security group rule. You
 	// can specify either RemoteGroupID or RemoteIPPrefix.
-	RemoteGroupID string `json:"remote_group_id" mapstructure:"remote_group_id"`
+	RemoteGroupID string `json:"remote_group_id"`
 
 	// The remote IP prefix to be associated with this security group rule. You
 	// can specify either RemoteGroupID or RemoteIPPrefix . This attribute
 	// matches the specified IP prefix as the source IP address of the IP packet.
-	RemoteIPPrefix string `json:"remote_ip_prefix" mapstructure:"remote_ip_prefix"`
+	RemoteIPPrefix string `json:"remote_ip_prefix"`
 
 	// The owner of this security group rule.
-	TenantID string `json:"tenant_id" mapstructure:"tenant_id"`
+	TenantID string `json:"tenant_id"`
 }
 
 // SecGroupRulePage is the page returned by a pager when traversing over a
@@ -62,40 +61,33 @@
 // NextPageURL is invoked when a paginated collection of security group rules has
 // reached the end of a page and the pager seeks to traverse over a new one. In
 // order to do this, it needs to construct the next page's URL.
-func (p SecGroupRulePage) NextPageURL() (string, error) {
-	type resp struct {
-		Links []gophercloud.Link `mapstructure:"security_group_rules_links"`
+func (page SecGroupRulePage) NextPageURL() (string, error) {
+	var s struct {
+		Links []gophercloud.Link `json:"security_group_rules_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)
 }
 
 // IsEmpty checks whether a SecGroupRulePage struct is empty.
-func (p SecGroupRulePage) IsEmpty() (bool, error) {
-	is, err := ExtractRules(p)
-	if err != nil {
-		return true, nil
-	}
-	return len(is) == 0, nil
+func (page SecGroupRulePage) IsEmpty() (bool, error) {
+	is, err := ExtractRules(page)
+	return len(is) == 0, err
 }
 
 // ExtractRules accepts a Page struct, specifically a SecGroupRulePage struct,
 // and extracts the elements into a slice of SecGroupRule structs. In other words,
 // a generic collection is mapped into a relevant slice.
 func ExtractRules(page pagination.Page) ([]SecGroupRule, error) {
-	var resp struct {
-		SecGroupRules []SecGroupRule `mapstructure:"security_group_rules" json:"security_group_rules"`
+	r := page.(SecGroupRulePage)
+	var s struct {
+		SecGroupRules []SecGroupRule `json:"security_group_rules"`
 	}
-
-	err := mapstructure.Decode(page.(SecGroupRulePage).Body, &resp)
-
-	return resp.SecGroupRules, err
+	err := r.ExtractInto(&s)
+	return s.SecGroupRules, err
 }
 
 type commonResult struct {
@@ -104,17 +96,11 @@
 
 // Extract is a function that accepts a result and extracts a security rule.
 func (r commonResult) Extract() (*SecGroupRule, error) {
-	if r.Err != nil {
-		return nil, r.Err
+	var s struct {
+		SecGroupRule *SecGroupRule `json:"security_group_rule"`
 	}
-
-	var res struct {
-		SecGroupRule *SecGroupRule `mapstructure:"security_group_rule" json:"security_group_rule"`
-	}
-
-	err := mapstructure.Decode(r.Body, &res)
-
-	return res.SecGroupRule, err
+	err := r.ExtractInto(&s)
+	return s.SecGroupRule, err
 }
 
 // CreateResult represents the result of a create operation.