You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficcontrol.apache.org by ro...@apache.org on 2021/01/12 18:45:08 UTC

[trafficcontrol] branch master updated: Refactor TO Go client internals (#5334)

This is an automated email from the ASF dual-hosted git repository.

rob pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficcontrol.git


The following commit(s) were added to refs/heads/master by this push:
     new 179f08c  Refactor TO Go client internals (#5334)
179f08c is described below

commit 179f08cc27f684230121f24110b1361ae5a1c083
Author: Rawlin Peters <ra...@apache.org>
AuthorDate: Tue Jan 12 11:44:56 2021 -0700

    Refactor TO Go client internals (#5334)
---
 CHANGELOG.md                                       |   3 +
 lib/go-tc/parameters.go                            |   4 +
 .../api/v3/deliveryservice_requests_test.go        |  40 ++--
 traffic_ops/testing/api/v3/profiles_test.go        |   6 +-
 traffic_ops/testing/api/v3/roles_test.go           |  16 +-
 .../testing/api/v3/staticdnsentries_test.go        |  60 +++---
 traffic_ops/v3-client/README.md                    |   4 +-
 traffic_ops/v3-client/about.go                     |  19 +-
 traffic_ops/v3-client/api_capability.go            |  12 +-
 traffic_ops/v3-client/asn.go                       |  64 +------
 traffic_ops/v3-client/cachegroup.go                | 169 +++--------------
 traffic_ops/v3-client/cachegroup_parameters.go     |  63 +------
 traffic_ops/v3-client/capability.go                |  33 +---
 traffic_ops/v3-client/cdn.go                       | 128 ++-----------
 traffic_ops/v3-client/cdn_domains.go               |  10 +-
 traffic_ops/v3-client/cdnfederations.go            |  41 ++--
 traffic_ops/v3-client/coordinate.go                | 106 ++---------
 traffic_ops/v3-client/crconfig.go                  |  24 +--
 traffic_ops/v3-client/deliveryservice.go           | 173 ++++-------------
 traffic_ops/v3-client/deliveryservice_regexes.go   |  44 ++---
 .../v3-client/deliveryservice_request_comments.go  |  84 +--------
 traffic_ops/v3-client/deliveryservice_requests.go  | 162 ++--------------
 .../deliveryservices_required_capabilities.go      |  25 +--
 traffic_ops/v3-client/deliveryserviceserver.go     |  72 +++----
 traffic_ops/v3-client/division.go                  | 107 ++---------
 traffic_ops/v3-client/dsuser.go                    |   9 +-
 traffic_ops/v3-client/federation.go                |  96 ++--------
 .../v3-client/federation_federation_resolver.go    |  48 +----
 traffic_ops/v3-client/federation_resolver.go       |  34 +---
 traffic_ops/v3-client/iso.go                       |  17 +-
 traffic_ops/v3-client/job.go                       | 203 +++++++-------------
 traffic_ops/v3-client/log.go                       |  16 +-
 traffic_ops/v3-client/origin.go                    |  72 ++-----
 traffic_ops/v3-client/parameter.go                 | 160 ++--------------
 traffic_ops/v3-client/phys_location.go             | 107 ++---------
 traffic_ops/v3-client/ping.go                      |  16 +-
 traffic_ops/v3-client/profile.go                   | 209 ++-------------------
 traffic_ops/v3-client/profile_parameter.go         |  88 ++-------
 traffic_ops/v3-client/region.go                    | 116 ++----------
 traffic_ops/v3-client/role.go                      | 154 +++------------
 traffic_ops/v3-client/server.go                    | 154 +++------------
 .../v3-client/server_server_capabilities.go        |  19 +-
 traffic_ops/v3-client/server_update_status.go      |  54 +-----
 traffic_ops/v3-client/servercapability.go          |  65 +------
 traffic_ops/v3-client/servercheck.go               |  14 +-
 traffic_ops/v3-client/servercheckextensions.go     |  32 +---
 traffic_ops/v3-client/serviceCategory.go           |  72 +------
 traffic_ops/v3-client/session.go                   |  76 ++++++--
 traffic_ops/v3-client/staticdnsentry.go            | 116 +++---------
 traffic_ops/v3-client/stats_summary.go             |  20 +-
 traffic_ops/v3-client/status.go                    | 107 ++---------
 traffic_ops/v3-client/steering.go                  |  16 +-
 traffic_ops/v3-client/steeringtarget.go            |  55 +-----
 traffic_ops/v3-client/tenant.go                    |  57 ++----
 traffic_ops/v3-client/topology.go                  |  91 ++-------
 traffic_ops/v3-client/topology_queue_updates.go    |  22 +--
 traffic_ops/v3-client/traffic_monitor.go           |  17 +-
 traffic_ops/v3-client/traffic_stats.go             |   7 +-
 traffic_ops/v3-client/type.go                      | 109 ++---------
 traffic_ops/v3-client/user.go                      |  99 ++--------
 traffic_ops/v3-client/util.go                      |  64 +------
 61 files changed, 772 insertions(+), 3308 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 66f19c7..8d2599e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -34,6 +34,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
 - [#5364](https://github.com/apache/trafficcontrol/issues/5364) - Cascade server deletes to delete corresponding IP addresses and interfaces
 - [#5390](https://github.com/apache/trafficcontrol/issues/5390) - Improve the way TO deals with delivery service server assignments
 
+### Changed
+- Refactored the Traffic Ops Go client internals so that all public methods have a consistent behavior/implementation
+
 ## [5.0.0] - 2020-10-20
 ### Added
 - Traffic Ops Ort: Disabled ntpd verification (ntpd is deprecated in CentOS)
diff --git a/lib/go-tc/parameters.go b/lib/go-tc/parameters.go
index a48b61c..a665c67 100644
--- a/lib/go-tc/parameters.go
+++ b/lib/go-tc/parameters.go
@@ -251,6 +251,10 @@ type ProfileParametersNullable struct {
 	Parameter   *int       `json:"parameter" db:"parameter_id"`
 }
 
+type ProfileParametersNullableResponse struct {
+	Response []ProfileParametersNullable `json:"response"`
+}
+
 // ProfileExportImportParameterNullable is an object of the form used by Traffic Ops
 // to represent parameters for exported and imported profiles.
 type ProfileExportImportParameterNullable struct {
diff --git a/traffic_ops/testing/api/v3/deliveryservice_requests_test.go b/traffic_ops/testing/api/v3/deliveryservice_requests_test.go
index 94984cc..8b8ecf8 100644
--- a/traffic_ops/testing/api/v3/deliveryservice_requests_test.go
+++ b/traffic_ops/testing/api/v3/deliveryservice_requests_test.go
@@ -112,13 +112,9 @@ func CreateTestDeliveryServiceRequests(t *testing.T) {
 func TestDeliveryServiceRequestRequired(t *testing.T) {
 	WithObjs(t, []TCObj{CDNs, Types, Parameters, Tenants}, func() {
 		dsr := testData.DeliveryServiceRequests[dsrRequired]
-		alerts, _, err := TOSession.CreateDeliveryServiceRequest(dsr)
-		if err != nil {
-			t.Errorf("Error occurred %v", err)
-		}
-
-		if len(alerts.Alerts) == 0 {
-			t.Errorf("Expected: validation error alerts, actual: %+v", alerts)
+		_, _, err := TOSession.CreateDeliveryServiceRequest(dsr)
+		if err == nil {
+			t.Error("expected: validation error, actual: nil")
 		}
 	})
 }
@@ -135,12 +131,9 @@ func TestDeliveryServiceRequestRules(t *testing.T) {
 		dsr.DeliveryService.RoutingName = routingName
 		dsr.DeliveryService.XMLID = XMLID
 
-		alerts, _, err := TOSession.CreateDeliveryServiceRequest(dsr)
-		if err != nil {
-			t.Errorf("Error occurred %v", err)
-		}
-		if len(alerts.Alerts) == 0 {
-			t.Errorf("Expected: validation error alerts, actual: %+v", alerts)
+		_, _, err := TOSession.CreateDeliveryServiceRequest(dsr)
+		if err == nil {
+			t.Error("expected: validation error, actual: nil")
 		}
 	})
 }
@@ -182,14 +175,14 @@ func TestDeliveryServiceRequestBad(t *testing.T) {
 		}
 		src.Status = s
 
-		alerts, _, err := TOSession.CreateDeliveryServiceRequest(src)
-		if err != nil {
-			t.Errorf("Error creating DeliveryServiceRequest %v", err)
+		_, _, err = TOSession.CreateDeliveryServiceRequest(src)
+		if err == nil {
+			t.Fatal("expected: validation error, actual: nil")
 		}
-		expected := []string{
-			`'status' invalid transition from draft to pending`,
+		expected := `'status' invalid transition from draft to pending`
+		if !strings.Contains(err.Error(), expected) {
+			t.Fatalf("expected: error message to contain %s, actual: %s", expected, err.Error())
 		}
-		utils.Compare(t, expected, alerts.ToStrings())
 	})
 }
 
@@ -221,11 +214,14 @@ func TestDeliveryServiceRequestWorkflow(t *testing.T) {
 
 		// Create a duplicate request -- should fail because xmlId is the same
 		alerts, _, err = TOSession.CreateDeliveryServiceRequest(src)
-		if err != nil {
-			t.Errorf("Error creating DeliveryServiceRequest %v", err)
+		if err == nil {
+			t.Fatal("expected: validation error, actual: nil")
 		}
 
-		expected = []string{`An active request exists for delivery service 'test-transitions'`}
+		expectedStr := `An active request exists for delivery service 'test-transitions'`
+		if !strings.Contains(err.Error(), expectedStr) {
+			t.Errorf("expected: error message containing %s, actual: %v", expectedStr, err)
+		}
 		utils.Compare(t, expected, alerts.ToStrings())
 
 		dsrs, _, err = TOSession.GetDeliveryServiceRequestByXMLID(`test-transitions`)
diff --git a/traffic_ops/testing/api/v3/profiles_test.go b/traffic_ops/testing/api/v3/profiles_test.go
index 681eaa4..7c8f7d1 100644
--- a/traffic_ops/testing/api/v3/profiles_test.go
+++ b/traffic_ops/testing/api/v3/profiles_test.go
@@ -424,9 +424,9 @@ func DeleteTestProfiles(t *testing.T) {
 		}
 
 		// Attempt to export Profile
-		profile, _, err := TOSession.ExportProfile(profileID)
-		if profile != nil {
-			t.Errorf("expected Profile: %s to be nil on export", pr.Name)
+		_, _, err = TOSession.ExportProfile(profileID)
+		if err == nil {
+			t.Errorf("export deleted profile %s - expected: error, actual: nil", pr.Name)
 		}
 	}
 }
diff --git a/traffic_ops/testing/api/v3/roles_test.go b/traffic_ops/testing/api/v3/roles_test.go
index d0650ca..190f072 100644
--- a/traffic_ops/testing/api/v3/roles_test.go
+++ b/traffic_ops/testing/api/v3/roles_test.go
@@ -19,6 +19,7 @@ import (
 	"net/http"
 	"reflect"
 	"sort"
+	"strings"
 	"testing"
 	"time"
 
@@ -118,7 +119,11 @@ func GetTestRolesIMS(t *testing.T) {
 }
 
 func CreateTestRoles(t *testing.T) {
-	expectedAlerts := []tc.Alerts{tc.Alerts{[]tc.Alert{tc.Alert{"role was created.", "success"}}}, tc.Alerts{[]tc.Alert{tc.Alert{"can not add non-existent capabilities: [invalid-capability]", "error"}}}, tc.Alerts{[]tc.Alert{tc.Alert{"role was created.", "success"}}}}
+	expectedAlerts := []string{
+		"",
+		"can not add non-existent capabilities: [invalid-capability]",
+		"",
+	}
 	for i, role := range testData.Roles {
 		var alerts tc.Alerts
 		alerts, _, status, err := TOSession.CreateRole(role)
@@ -126,10 +131,13 @@ func CreateTestRoles(t *testing.T) {
 		t.Log("Response: ", alerts)
 		if err != nil {
 			t.Logf("error: %v", err)
-			//t.Errorf("could not CREATE role: %v", err)
 		}
-		if !reflect.DeepEqual(alerts, expectedAlerts[i]) {
-			t.Errorf("got alerts: %v but expected alerts: %v", alerts, expectedAlerts[i])
+		if expectedAlerts[i] == "" && err != nil {
+			t.Errorf("expected: no error, actual: %v", err)
+		} else if len(expectedAlerts[i]) > 0 && err == nil {
+			t.Errorf("expected: error containing '%s', actual: nil", expectedAlerts[i])
+		} else if err != nil && !strings.Contains(err.Error(), expectedAlerts[i]) {
+			t.Errorf("expected: error containing '%s', actual: %v", expectedAlerts[i], err)
 		}
 	}
 }
diff --git a/traffic_ops/testing/api/v3/staticdnsentries_test.go b/traffic_ops/testing/api/v3/staticdnsentries_test.go
index 8bf36c5..129f986 100644
--- a/traffic_ops/testing/api/v3/staticdnsentries_test.go
+++ b/traffic_ops/testing/api/v3/staticdnsentries_test.go
@@ -17,8 +17,8 @@ package v3
 
 import (
 	"net/http"
-	"reflect"
 	"sort"
+	"strings"
 	"testing"
 	"time"
 
@@ -175,11 +175,12 @@ func UpdateTestStaticDNSEntries(t *testing.T) {
 
 func UpdateTestStaticDNSEntriesInvalidAddress(t *testing.T) {
 
-	expectedAlerts := []tc.Alerts{
-		tc.Alerts{[]tc.Alert{tc.Alert{"'address' must be a valid IPv4 address", "error"}}},
-		tc.Alerts{[]tc.Alert{tc.Alert{"'address' must be a valid DNS name", "error"}}},
-		tc.Alerts{[]tc.Alert{tc.Alert{"'address' for type: CNAME_RECORD must have a trailing period", "error"}}},
-		tc.Alerts{[]tc.Alert{tc.Alert{"'address' must be a valid IPv6 address", "error"}}}}
+	expectedAlerts := []string{
+		"'address' must be a valid IPv4 address",
+		"'address' must be a valid DNS name",
+		"'address' for type: CNAME_RECORD must have a trailing period",
+		"'address' must be a valid IPv6 address",
+	}
 
 	// A_RECORD
 	firstStaticDNSEntry := testData.StaticDNSEntries[0]
@@ -191,15 +192,15 @@ func UpdateTestStaticDNSEntriesInvalidAddress(t *testing.T) {
 	remoteStaticDNSEntry := resp[0]
 	expectedAddress := "test.testdomain.net."
 	remoteStaticDNSEntry.Address = expectedAddress
-	var alert tc.Alerts
 	var status int
-	alert, _, status, err = TOSession.UpdateStaticDNSEntryByID(remoteStaticDNSEntry.ID, remoteStaticDNSEntry)
+	_, _, status, err = TOSession.UpdateStaticDNSEntryByID(remoteStaticDNSEntry.ID, remoteStaticDNSEntry)
 	t.Log("Status Code [expect 400]: ", status)
-	if err != nil {
-		t.Logf("cannot UPDATE StaticDNSEntries using url: %v - %v\n", err, alert)
-	}
-	if !reflect.DeepEqual(alert, expectedAlerts[0]) {
-		t.Errorf("got alerts: %v but expected alerts: %v", alert, expectedAlerts[0])
+	if err == nil {
+		t.Errorf("making invalid update to static DNS entry - expected: error, actual: nil")
+	} else {
+		if !strings.Contains(err.Error(), expectedAlerts[0]) {
+			t.Errorf("got err: %v, but expected err containing: %v", err, expectedAlerts[0])
+		}
 	}
 
 	// CNAME_RECORD
@@ -212,25 +213,23 @@ func UpdateTestStaticDNSEntriesInvalidAddress(t *testing.T) {
 	remoteStaticDNSEntry = resp[0]
 	expectedAddress = "2001:0db8:85a3:0000:0000:8a2e:0370:7334"
 	remoteStaticDNSEntry.Address = expectedAddress
-	alert, _, status, err = TOSession.UpdateStaticDNSEntryByID(remoteStaticDNSEntry.ID, remoteStaticDNSEntry)
+	_, _, status, err = TOSession.UpdateStaticDNSEntryByID(remoteStaticDNSEntry.ID, remoteStaticDNSEntry)
 	t.Log("Status Code [expect 400]: ", status)
-	if err != nil {
-		t.Logf("cannot UPDATE StaticDNSEntries using url: %v - %v\n", err, alert)
-	}
-	if !reflect.DeepEqual(alert, expectedAlerts[1]) {
-		t.Errorf("got alerts: %v but expected alerts: %v", alert, expectedAlerts[1])
+	if err == nil {
+		t.Errorf("making invalid update to static DNS entry - expected: error, actual: nil")
+	} else if !strings.Contains(err.Error(), expectedAlerts[1]) {
+		t.Errorf("got err: %v, but expected err containing: %v", err, expectedAlerts[1])
 	}
 
 	//CNAME_RECORD: missing a trailing period
 	expectedAddressMissingPeriod := "cdn.test.com"
 	remoteStaticDNSEntry.Address = expectedAddressMissingPeriod
-	alert, _, status, err = TOSession.UpdateStaticDNSEntryByID(remoteStaticDNSEntry.ID, remoteStaticDNSEntry)
+	_, _, status, err = TOSession.UpdateStaticDNSEntryByID(remoteStaticDNSEntry.ID, remoteStaticDNSEntry)
 	t.Log("Status Code [expect 400]: ", status)
-	if err != nil {
-		t.Logf("cannot UPDATE StaticDNSEntries using url: %v - %v\n", err, alert)
-	}
-	if !reflect.DeepEqual(alert, expectedAlerts[2]) {
-		t.Errorf("got alerts: %v but expected alerts: %v", alert, expectedAlerts[2])
+	if err == nil {
+		t.Errorf("making invalid update to static DNS entry - expected: error, actual: nil")
+	} else if !strings.Contains(err.Error(), expectedAlerts[2]) {
+		t.Errorf("got err: %v, but expected err containing: %v", err, expectedAlerts[2])
 	}
 
 	// AAAA_RECORD
@@ -243,13 +242,12 @@ func UpdateTestStaticDNSEntriesInvalidAddress(t *testing.T) {
 	remoteStaticDNSEntry = resp[0]
 	expectedAddress = "192.168.0.1"
 	remoteStaticDNSEntry.Address = expectedAddress
-	alert, _, status, err = TOSession.UpdateStaticDNSEntryByID(remoteStaticDNSEntry.ID, remoteStaticDNSEntry)
+	_, _, status, err = TOSession.UpdateStaticDNSEntryByID(remoteStaticDNSEntry.ID, remoteStaticDNSEntry)
 	t.Log("Status Code [expect 400]: ", status)
-	if err != nil {
-		t.Logf("cannot UPDATE StaticDNSEntries using url: %v - %v\n", err, alert)
-	}
-	if !reflect.DeepEqual(alert, expectedAlerts[3]) {
-		t.Errorf("got alerts: %v but expected alerts: %v", alert, expectedAlerts[3])
+	if err == nil {
+		t.Errorf("making invalid update to static DNS entry - expected: error, actual: nil")
+	} else if !strings.Contains(err.Error(), expectedAlerts[3]) {
+		t.Errorf("got err: %v, but expected err containging: %v", err, expectedAlerts[3])
 	}
 }
 
diff --git a/traffic_ops/v3-client/README.md b/traffic_ops/v3-client/README.md
index f445a22..0dbae83 100644
--- a/traffic_ops/v3-client/README.md
+++ b/traffic_ops/v3-client/README.md
@@ -40,8 +40,8 @@ func main() {
 		os.Exit(1)
 	}
 	fmt.Println("Connected to: " + remoteaddr.String())
-	var cdns []v13.CDN
-	cdns, _, err = session.GetCDNs()
+	var cdns []tc.CDN
+	cdns, _, err = session.GetCDNsWithHdr(nil)
 	if err != nil {
 		fmt.Printf("An error occurred while getting cdns:\n\t%v\n", err)
 		os.Exit(1)
diff --git a/traffic_ops/v3-client/about.go b/traffic_ops/v3-client/about.go
index c15e74b..ea883c8 100644
--- a/traffic_ops/v3-client/about.go
+++ b/traffic_ops/v3-client/about.go
@@ -20,11 +20,6 @@ package client
    limitations under the License.
 */
 
-import (
-	"encoding/json"
-	"net/http"
-)
-
 const (
 	API_ABOUT = apiBase + "/about"
 )
@@ -32,17 +27,7 @@ const (
 // GetAbout gets data about the TO instance.
 func (to *Session) GetAbout() (map[string]string, ReqInf, error) {
 	route := API_ABOUT
-	resp, remoteAddr, err := to.request(http.MethodGet, route, nil, nil)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	var data map[string]string
-	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
-		return nil, reqInf, err
-	}
-
-	return data, reqInf, nil
+	reqInf, err := to.get(route, nil, &data)
+	return data, reqInf, err
 }
diff --git a/traffic_ops/v3-client/api_capability.go b/traffic_ops/v3-client/api_capability.go
index fcb081e..51045f2 100644
--- a/traffic_ops/v3-client/api_capability.go
+++ b/traffic_ops/v3-client/api_capability.go
@@ -1,9 +1,7 @@
 package client
 
 import (
-	"encoding/json"
 	"fmt"
-	"net/http"
 	"net/url"
 
 	"github.com/apache/trafficcontrol/lib/go-tc"
@@ -46,15 +44,7 @@ func (to *Session) GetAPICapabilities(capability string, order string) (tc.APICa
 		path = fmt.Sprintf("%s?%s", path, vals.Encode())
 	}
 
-	httpResp, remoteAddr, err := to.request(http.MethodGet, path, nil, nil)
-	reqInf.RemoteAddr = remoteAddr
-
-	if err != nil {
-		return tc.APICapabilityResponse{}, reqInf, err
-	}
-	defer httpResp.Body.Close()
-
-	err = json.NewDecoder(httpResp.Body).Decode(&resp)
+	reqInf, err := to.get(path, nil, &resp)
 
 	return resp, reqInf, err
 }
diff --git a/traffic_ops/v3-client/asn.go b/traffic_ops/v3-client/asn.go
index a0ff4ae..790a23d 100644
--- a/traffic_ops/v3-client/asn.go
+++ b/traffic_ops/v3-client/asn.go
@@ -16,9 +16,7 @@
 package client
 
 import (
-	"encoding/json"
 	"fmt"
-	"net"
 	"net/http"
 	"net/url"
 
@@ -31,77 +29,31 @@ const (
 
 // CreateASN creates a ASN
 func (to *Session) CreateASN(entity tc.ASN) (tc.Alerts, ReqInf, error) {
-
-	var remoteAddr net.Addr
-	reqBody, err := json.Marshal(entity)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	resp, remoteAddr, err := to.request(http.MethodPost, API_ASNS, reqBody, nil)
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
 	var alerts tc.Alerts
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
-	return alerts, reqInf, nil
+	reqInf, err := to.post(API_ASNS, entity, nil, &alerts)
+	return alerts, reqInf, err
 }
 
 // UpdateASNByID updates a ASN by ID
 func (to *Session) UpdateASNByID(id int, entity tc.ASN) (tc.Alerts, ReqInf, error) {
-
-	var remoteAddr net.Addr
-	reqBody, err := json.Marshal(entity)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
 	route := fmt.Sprintf("%s?id=%d", API_ASNS, id)
-	resp, remoteAddr, err := to.request(http.MethodPut, route, reqBody, nil)
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
 	var alerts tc.Alerts
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
-	return alerts, reqInf, nil
+	reqInf, err := to.put(route, entity, nil, &alerts)
+	return alerts, reqInf, err
 }
 
 // GetASNsWithHeader Returns a list of ASNs matching query params
 func (to *Session) GetASNsWithHeader(params *url.Values, header http.Header) ([]tc.ASN, ReqInf, error) {
 	route := fmt.Sprintf("%s?%s", API_ASNS, params.Encode())
-	resp, remoteAddr, err := to.request(http.MethodGet, route, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.ASN{}, reqInf, nil
-		}
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	var data tc.ASNsResponse
-	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
-		return data.Response, reqInf, err
-	}
-	return data.Response, reqInf, nil
+	reqInf, err := to.get(route, header, &data)
+	return data.Response, reqInf, err
 }
 
 // DeleteASNByASN deletes an ASN by asn number
 func (to *Session) DeleteASNByASN(asn int) (tc.Alerts, ReqInf, error) {
 	route := fmt.Sprintf("%s?id=%d", API_ASNS, asn)
-	resp, remoteAddr, err := to.request(http.MethodDelete, route, nil, nil)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
 	var alerts tc.Alerts
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
-	return alerts, reqInf, nil
+	reqInf, err := to.del(route, nil, &alerts)
+	return alerts, reqInf, err
 }
diff --git a/traffic_ops/v3-client/cachegroup.go b/traffic_ops/v3-client/cachegroup.go
index 38dae87..dc24382 100644
--- a/traffic_ops/v3-client/cachegroup.go
+++ b/traffic_ops/v3-client/cachegroup.go
@@ -16,15 +16,12 @@
 package client
 
 import (
-	"encoding/json"
 	"errors"
 	"fmt"
-	"net"
 	"net/http"
 	"net/url"
 	"strconv"
 
-	"github.com/apache/trafficcontrol/lib/go-log"
 	"github.com/apache/trafficcontrol/lib/go-tc"
 )
 
@@ -35,7 +32,7 @@ const (
 // Create a CacheGroup.
 func (to *Session) CreateCacheGroupNullable(cachegroup tc.CacheGroupNullable) (*tc.CacheGroupDetailResponse, ReqInf, error) {
 	if cachegroup.TypeID == nil && cachegroup.Type != nil {
-		ty, _, err := to.GetTypeByName(*cachegroup.Type)
+		ty, _, err := to.GetTypeByNameWithHdr(*cachegroup.Type, nil)
 		if err != nil {
 			return nil, ReqInf{}, err
 		}
@@ -46,7 +43,7 @@ func (to *Session) CreateCacheGroupNullable(cachegroup tc.CacheGroupNullable) (*
 	}
 
 	if cachegroup.ParentCachegroupID == nil && cachegroup.ParentName != nil {
-		p, _, err := to.GetCacheGroupNullableByName(*cachegroup.ParentName)
+		p, _, err := to.GetCacheGroupNullableByNameWithHdr(*cachegroup.ParentName, nil)
 		if err != nil {
 			return nil, ReqInf{}, err
 		}
@@ -57,7 +54,7 @@ func (to *Session) CreateCacheGroupNullable(cachegroup tc.CacheGroupNullable) (*
 	}
 
 	if cachegroup.SecondaryParentCachegroupID == nil && cachegroup.SecondaryParentName != nil {
-		p, _, err := to.GetCacheGroupNullableByName(*cachegroup.SecondaryParentName)
+		p, _, err := to.GetCacheGroupNullableByNameWithHdr(*cachegroup.SecondaryParentName, nil)
 		if err != nil {
 			return nil, ReqInf{}, err
 		}
@@ -67,48 +64,16 @@ func (to *Session) CreateCacheGroupNullable(cachegroup tc.CacheGroupNullable) (*
 		cachegroup.SecondaryParentCachegroupID = p[0].ID
 	}
 
-	reqBody, err := json.Marshal(cachegroup)
-	if err != nil {
-		return nil, ReqInf{}, err
-	}
-	resp, remoteAddr, err := to.request(http.MethodPost, API_CACHEGROUPS, reqBody, nil)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
 	var cachegroupResp tc.CacheGroupDetailResponse
-	if err = json.NewDecoder(resp.Body).Decode(&cachegroupResp); err != nil {
-		return nil, reqInf, err
-	}
-	return &cachegroupResp, reqInf, nil
+	reqInf, err := to.post(API_CACHEGROUPS, cachegroup, nil, &cachegroupResp)
+	return &cachegroupResp, reqInf, err
 }
 
 func (to *Session) UpdateCacheGroupNullableByIDWithHdr(id int, cachegroup tc.CacheGroupNullable, h http.Header) (*tc.CacheGroupDetailResponse, ReqInf, error) {
-
-	var remoteAddr net.Addr
-	reqBody, err := json.Marshal(cachegroup)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return nil, reqInf, err
-	}
 	route := fmt.Sprintf("%s/%d", API_CACHEGROUPS, id)
-	resp, remoteAddr, err := to.request(http.MethodPut, route, reqBody, h)
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
 	var cachegroupResp tc.CacheGroupDetailResponse
-	if err = json.NewDecoder(resp.Body).Decode(&cachegroupResp); err != nil {
-		return nil, reqInf, err
-	}
-	return &cachegroupResp, reqInf, nil
+	reqInf, err := to.put(route, cachegroup, h, &cachegroupResp)
+	return &cachegroupResp, reqInf, err
 }
 
 // Update a CacheGroup by ID.
@@ -118,18 +83,9 @@ func (to *Session) UpdateCacheGroupNullableByID(id int, cachegroup tc.CacheGroup
 }
 
 func (to *Session) GetCacheGroupsNullableWithHdr(header http.Header) ([]tc.CacheGroupNullable, ReqInf, error) {
-	resp, remoteAddr, err := to.request(http.MethodGet, API_CACHEGROUPS, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	var data tc.CacheGroupsNullableResponse
-	if err = json.NewDecoder(resp.Body).Decode(&data); err != nil {
-		return nil, reqInf, err
-	}
-	return data.Response, reqInf, nil
+	reqInf, err := to.get(API_CACHEGROUPS, header, &data)
+	return data.Response, reqInf, err
 }
 
 // Returns a list of CacheGroups.
@@ -140,19 +96,9 @@ func (to *Session) GetCacheGroupsNullable() ([]tc.CacheGroupNullable, ReqInf, er
 
 func (to *Session) GetCacheGroupNullableByIDWithHdr(id int, header http.Header) ([]tc.CacheGroupNullable, ReqInf, error) {
 	route := fmt.Sprintf("%s?id=%v", API_CACHEGROUPS, id)
-	resp, remoteAddr, err := to.request(http.MethodGet, route, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	var data tc.CacheGroupsNullableResponse
-	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
-		return nil, reqInf, err
-	}
-
-	return data.Response, reqInf, nil
+	reqInf, err := to.get(route, header, &data)
+	return data.Response, reqInf, err
 }
 
 // GET a CacheGroup by the CacheGroup ID.
@@ -163,25 +109,9 @@ func (to *Session) GetCacheGroupNullableByID(id int) ([]tc.CacheGroupNullable, R
 
 func (to *Session) GetCacheGroupNullableByNameWithHdr(name string, header http.Header) ([]tc.CacheGroupNullable, ReqInf, error) {
 	route := fmt.Sprintf("%s?name=%s", API_CACHEGROUPS, url.QueryEscape(name))
-	resp, remoteAddr, err := to.request(http.MethodGet, route, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.CacheGroupNullable{}, reqInf, nil
-		}
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	var data tc.CacheGroupsNullableResponse
-	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
-		return nil, reqInf, err
-	}
-
-	return data.Response, reqInf, nil
+	reqInf, err := to.get(route, header, &data)
+	return data.Response, reqInf, err
 }
 
 // GET a CacheGroup by the CacheGroup name.
@@ -192,25 +122,9 @@ func (to *Session) GetCacheGroupNullableByName(name string) ([]tc.CacheGroupNull
 
 func (to *Session) GetCacheGroupNullableByShortNameWithHdr(shortName string, header http.Header) ([]tc.CacheGroupNullable, ReqInf, error) {
 	route := fmt.Sprintf("%s?shortName=%s", API_CACHEGROUPS, url.QueryEscape(shortName))
-	resp, remoteAddr, err := to.request(http.MethodGet, route, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.CacheGroupNullable{}, reqInf, nil
-		}
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	var data tc.CacheGroupsNullableResponse
-	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
-		return nil, reqInf, err
-	}
-
-	return data.Response, reqInf, nil
+	reqInf, err := to.get(route, header, &data)
+	return data.Response, reqInf, err
 }
 
 // GET a CacheGroup by the CacheGroup short name.
@@ -222,17 +136,9 @@ func (to *Session) GetCacheGroupNullableByShortName(shortName string) ([]tc.Cach
 // DELETE a CacheGroup by ID.
 func (to *Session) DeleteCacheGroupByID(id int) (tc.Alerts, ReqInf, error) {
 	route := fmt.Sprintf("%s/%d", API_CACHEGROUPS, id)
-	resp, remoteAddr, err := to.request(http.MethodDelete, route, nil, nil)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
 	var alerts tc.Alerts
-	if err = json.NewDecoder(resp.Body).Decode(&alerts); err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	return alerts, reqInf, nil
+	reqInf, err := to.del(route, nil, &alerts)
+	return alerts, reqInf, err
 }
 
 // GetCacheGroupsByQueryParams gets cache groups by the given query parameters.
@@ -246,48 +152,15 @@ func (to *Session) GetCacheGroupsByQueryParamsWithHdr(qparams url.Values, header
 	if len(qparams) > 0 {
 		route += "?" + qparams.Encode()
 	}
-
-	resp, remoteAddr, err := to.request(http.MethodGet, route, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.CacheGroupNullable{}, reqInf, nil
-		}
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer log.Close(resp.Body, "unable to close cachegroups response body")
-
 	var data tc.CacheGroupsNullableResponse
-	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
-		return nil, reqInf, err
-	}
-
-	return data.Response, reqInf, nil
+	reqInf, err := to.get(route, header, &data)
+	return data.Response, reqInf, err
 }
 
 func (to *Session) SetCachegroupDeliveryServices(cgID int, dsIDs []int) (tc.CacheGroupPostDSRespResponse, ReqInf, error) {
 	uri := apiBase + `/cachegroups/` + strconv.Itoa(cgID) + `/deliveryservices`
 	req := tc.CachegroupPostDSReq{DeliveryServices: dsIDs}
-	reqBody, err := json.Marshal(req)
-	if err != nil {
-		return tc.CacheGroupPostDSRespResponse{}, ReqInf{}, err
-	}
-	reqResp, remoteAddr, err := to.request(http.MethodPost, uri, reqBody, nil)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if reqResp != nil {
-		reqInf.StatusCode = reqResp.StatusCode
-	}
-	if err != nil {
-		return tc.CacheGroupPostDSRespResponse{}, reqInf, errors.New("requesting from Traffic Ops: " + err.Error())
-	}
-	defer log.Close(reqResp.Body, "unable to close response body")
-
 	resp := tc.CacheGroupPostDSRespResponse{}
-	if err := json.NewDecoder(reqResp.Body).Decode(&resp); err != nil {
-		return tc.CacheGroupPostDSRespResponse{}, reqInf, errors.New("decoding response: " + err.Error())
-	}
-	return resp, reqInf, nil
+	reqInf, err := to.post(uri, req, nil, &resp)
+	return resp, reqInf, err
 }
diff --git a/traffic_ops/v3-client/cachegroup_parameters.go b/traffic_ops/v3-client/cachegroup_parameters.go
index dd970f1..fe70383 100644
--- a/traffic_ops/v3-client/cachegroup_parameters.go
+++ b/traffic_ops/v3-client/cachegroup_parameters.go
@@ -16,7 +16,6 @@
 package client
 
 import (
-	"encoding/json"
 	"fmt"
 	"net/http"
 
@@ -51,40 +50,16 @@ func (to *Session) GetCacheGroupParametersByQueryParams(cacheGroupID int, queryP
 
 func (to *Session) getCacheGroupParameters(route, queryParams string, header http.Header) ([]tc.CacheGroupParameter, ReqInf, error) {
 	r := fmt.Sprintf("%s%s", route, queryParams)
-	resp, remoteAddr, err := to.request(http.MethodGet, r, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.CacheGroupParameter{}, reqInf, nil
-		}
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	var data tc.CacheGroupParametersResponse
-	if err = json.NewDecoder(resp.Body).Decode(&data); err != nil {
-		return nil, reqInf, err
-	}
-	return data.Response, reqInf, nil
+	reqInf, err := to.get(r, header, &data)
+	return data.Response, reqInf, err
 }
 
 func (to *Session) GetAllCacheGroupParametersWithHdr(header http.Header) ([]tc.CacheGroupParametersResponseNullable, ReqInf, error) {
 	route := fmt.Sprintf("%s/", API_CACHEGROUPPARAMETERS)
-	resp, remoteAddr, err := to.request(http.MethodGet, route, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	var data tc.AllCacheGroupParametersResponse
-	if err = json.NewDecoder(resp.Body).Decode(&data); err != nil {
-		return nil, reqInf, err
-	}
-	return data.Response.CacheGroupParameters, reqInf, nil
+	reqInf, err := to.get(route, header, &data)
+	return data.Response.CacheGroupParameters, reqInf, err
 }
 
 // GetAllCacheGroupParameters Gets all Cachegroup Parameter associations
@@ -96,18 +71,9 @@ func (to *Session) GetAllCacheGroupParameters() ([]tc.CacheGroupParametersRespon
 // DeleteCacheGroupParameter Deassociates a Parameter with a Cache Group
 func (to *Session) DeleteCacheGroupParameter(cacheGroupID, parameterID int) (tc.Alerts, ReqInf, error) {
 	route := fmt.Sprintf("%s/%d/%d", API_CACHEGROUPPARAMETERS, cacheGroupID, parameterID)
-	resp, remoteAddr, err := to.request(http.MethodDelete, route, nil, nil)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	var alerts tc.Alerts
-	if err = json.NewDecoder(resp.Body).Decode(&alerts); err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	return alerts, reqInf, nil
+	reqInf, err := to.del(route, nil, &alerts)
+	return alerts, reqInf, err
 }
 
 // CreateCacheGroupParameter Associates a Parameter with a Cache Group
@@ -116,20 +82,7 @@ func (to *Session) CreateCacheGroupParameter(cacheGroupID, parameterID int) (*tc
 		CacheGroupID: cacheGroupID,
 		ParameterID:  parameterID,
 	}
-	reqBody, err := json.Marshal(cacheGroupParameterReq)
-	if err != nil {
-		return nil, ReqInf{}, err
-	}
-	resp, remoteAddr, err := to.request(http.MethodPost, API_CACHEGROUPPARAMETERS, reqBody, nil)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	var data tc.CacheGroupParametersPostResponse
-	if err = json.NewDecoder(resp.Body).Decode(&data); err != nil {
-		return nil, reqInf, err
-	}
-	return &data, reqInf, nil
+	reqInf, err := to.post(API_CACHEGROUPPARAMETERS, cacheGroupParameterReq, nil, &data)
+	return &data, reqInf, err
 }
diff --git a/traffic_ops/v3-client/capability.go b/traffic_ops/v3-client/capability.go
index 0bd6070..fbebe12 100644
--- a/traffic_ops/v3-client/capability.go
+++ b/traffic_ops/v3-client/capability.go
@@ -14,7 +14,6 @@ package client
  * limitations under the License.
  */
 
-import "encoding/json"
 import "errors"
 import "net/http"
 import "net/url"
@@ -24,21 +23,8 @@ import "github.com/apache/trafficcontrol/lib/go-tc"
 const API_CAPABILITIES = apiBase + "/capabilities"
 
 func (to *Session) GetCapabilitiesWithHdr(header http.Header) ([]tc.Capability, ReqInf, error) {
-	resp, remoteAddr, err := to.request(http.MethodGet, API_CAPABILITIES, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.Capability{}, reqInf, nil
-		}
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	var data tc.CapabilitiesResponse
-	err = json.NewDecoder(resp.Body).Decode(&data)
+	reqInf, err := to.get(API_CAPABILITIES, header, &data)
 	return data.Response, reqInf, err
 }
 
@@ -52,25 +38,12 @@ func (to *Session) GetCapabilityWithHdr(c string, header http.Header) (tc.Capabi
 	v := url.Values{}
 	v.Add("name", c)
 	endpoint := API_CAPABILITIES + "?" + v.Encode()
-	resp, remoteAddr, err := to.request(http.MethodGet, endpoint, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return tc.Capability{}, reqInf, nil
-		}
-	}
-	if err != nil {
-		return tc.Capability{}, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	var data tc.CapabilitiesResponse
-	err = json.NewDecoder(resp.Body).Decode(&data)
+	reqInf, err := to.get(endpoint, header, &data)
 	if err != nil {
 		return tc.Capability{}, reqInf, err
 	} else if data.Response == nil || len(data.Response) < 1 {
-		return tc.Capability{}, reqInf, errors.New("Invalid response - no capability returned!")
+		return tc.Capability{}, reqInf, errors.New("invalid response - no capability returned")
 	}
 
 	return data.Response[0], reqInf, nil
diff --git a/traffic_ops/v3-client/cdn.go b/traffic_ops/v3-client/cdn.go
index 7e069b0..ce56522 100644
--- a/traffic_ops/v3-client/cdn.go
+++ b/traffic_ops/v3-client/cdn.go
@@ -16,9 +16,7 @@
 package client
 
 import (
-	"encoding/json"
 	"fmt"
-	"net"
 	"net/http"
 	"net/url"
 
@@ -31,43 +29,16 @@ const (
 
 // CreateCDN creates a CDN.
 func (to *Session) CreateCDN(cdn tc.CDN) (tc.Alerts, ReqInf, error) {
-
-	var remoteAddr net.Addr
-	reqBody, err := json.Marshal(cdn)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	resp, remoteAddr, err := to.request(http.MethodPost, API_CDNS, reqBody, nil)
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
 	var alerts tc.Alerts
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
-	return alerts, reqInf, nil
+	reqInf, err := to.post(API_CDNS, cdn, nil, &alerts)
+	return alerts, reqInf, err
 }
 
 func (to *Session) UpdateCDNByIDWithHdr(id int, cdn tc.CDN, header http.Header) (tc.Alerts, ReqInf, error) {
-
-	var remoteAddr net.Addr
-	reqBody, err := json.Marshal(cdn)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
 	route := fmt.Sprintf("%s/%d", API_CDNS, id)
-	resp, remoteAddr, err := to.request(http.MethodPut, route, reqBody, header)
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-	}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
 	var alerts tc.Alerts
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
-	return alerts, reqInf, nil
+	reqInf, err := to.put(route, cdn, header, &alerts)
+	return alerts, reqInf, err
 }
 
 // UpdateCDNByID updates a CDN by ID.
@@ -77,22 +48,9 @@ func (to *Session) UpdateCDNByID(id int, cdn tc.CDN) (tc.Alerts, ReqInf, error)
 }
 
 func (to *Session) GetCDNsWithHdr(header http.Header) ([]tc.CDN, ReqInf, error) {
-	resp, remoteAddr, err := to.request(http.MethodGet, API_CDNS, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.CDN{}, reqInf, nil
-		}
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	var data tc.CDNsResponse
-	err = json.NewDecoder(resp.Body).Decode(&data)
-	return data.Response, reqInf, nil
+	reqInf, err := to.get(API_CDNS, header, &data)
+	return data.Response, reqInf, err
 }
 
 // GetCDNs eturns a list of CDNs.
@@ -103,25 +61,9 @@ func (to *Session) GetCDNs() ([]tc.CDN, ReqInf, error) {
 
 func (to *Session) GetCDNByIDWithHdr(id int, header http.Header) ([]tc.CDN, ReqInf, error) {
 	route := fmt.Sprintf("%s?id=%v", API_CDNS, id)
-	resp, remoteAddr, err := to.request(http.MethodGet, route, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.CDN{}, reqInf, nil
-		}
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	var data tc.CDNsResponse
-	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
-		return nil, reqInf, err
-	}
-
-	return data.Response, reqInf, nil
+	reqInf, err := to.get(route, header, &data)
+	return data.Response, reqInf, err
 }
 
 // GetCDNByID a CDN by the CDN ID.
@@ -131,26 +73,10 @@ func (to *Session) GetCDNByID(id int) ([]tc.CDN, ReqInf, error) {
 }
 
 func (to *Session) GetCDNByNameWithHdr(name string, header http.Header) ([]tc.CDN, ReqInf, error) {
-	url := fmt.Sprintf("%s?name=%s", API_CDNS, url.QueryEscape(name))
-	resp, remoteAddr, err := to.request(http.MethodGet, url, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.CDN{}, reqInf, nil
-		}
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
+	route := fmt.Sprintf("%s?name=%s", API_CDNS, url.QueryEscape(name))
 	var data tc.CDNsResponse
-	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
-		return nil, reqInf, err
-	}
-
-	return data.Response, reqInf, nil
+	reqInf, err := to.get(route, header, &data)
+	return data.Response, reqInf, err
 }
 
 // GetCDNByName gets a CDN by the CDN name.
@@ -162,38 +88,16 @@ func (to *Session) GetCDNByName(name string) ([]tc.CDN, ReqInf, error) {
 // DeleteCDNByID deletes a CDN by ID.
 func (to *Session) DeleteCDNByID(id int) (tc.Alerts, ReqInf, error) {
 	route := fmt.Sprintf("%s/%d", API_CDNS, id)
-	resp, remoteAddr, err := to.request(http.MethodDelete, route, nil, nil)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
 	var alerts tc.Alerts
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
-	return alerts, reqInf, nil
+	reqInf, err := to.del(route, nil, &alerts)
+	return alerts, reqInf, err
 }
 
 func (to *Session) GetCDNSSLKeysWithHdr(name string, header http.Header) ([]tc.CDNSSLKeys, ReqInf, error) {
-	url := fmt.Sprintf("%s/name/%s/sslkeys", API_CDNS, name)
-	resp, remoteAddr, err := to.request(http.MethodGet, url, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.CDNSSLKeys{}, reqInf, nil
-		}
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
+	route := fmt.Sprintf("%s/name/%s/sslkeys", API_CDNS, name)
 	var data tc.CDNSSLKeysResponse
-	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
-		return nil, reqInf, err
-	}
-
-	return data.Response, reqInf, nil
+	reqInf, err := to.get(route, header, &data)
+	return data.Response, reqInf, err
 }
 
 // Deprecated: GetCDNSSLKeys will be removed in 6.0. Use GetCDNSSLKeysWithHdr.
diff --git a/traffic_ops/v3-client/cdn_domains.go b/traffic_ops/v3-client/cdn_domains.go
index e1c66ac..a3cdc3b 100644
--- a/traffic_ops/v3-client/cdn_domains.go
+++ b/traffic_ops/v3-client/cdn_domains.go
@@ -1,8 +1,9 @@
 package client
 
 import (
-	"github.com/apache/trafficcontrol/lib/go-tc"
 	"net/http"
+
+	"github.com/apache/trafficcontrol/lib/go-tc"
 )
 
 /*
@@ -22,11 +23,8 @@ import (
 
 func (to *Session) GetDomainsWithHdr(header http.Header) ([]tc.Domain, ReqInf, error) {
 	var data tc.DomainsResponse
-	inf, err := get(to, apiBase+"/cdns/domains", &data, header)
-	if err != nil {
-		return nil, inf, err
-	}
-	return data.Response, inf, nil
+	inf, err := to.get(apiBase+"/cdns/domains", header, &data)
+	return data.Response, inf, err
 }
 
 // Deprecated: GetDomains will be removed in 6.0. Use GetDomainsWithHdr.
diff --git a/traffic_ops/v3-client/cdnfederations.go b/traffic_ops/v3-client/cdnfederations.go
index 9e2626f..bf5ade8 100644
--- a/traffic_ops/v3-client/cdnfederations.go
+++ b/traffic_ops/v3-client/cdnfederations.go
@@ -16,9 +16,9 @@
 package client
 
 import (
-	"encoding/json"
 	"fmt"
 	"net/http"
+	"net/url"
 
 	"github.com/apache/trafficcontrol/lib/go-tc"
 )
@@ -29,21 +29,16 @@ import (
  * keep the same behavior from perl. */
 
 func (to *Session) CreateCDNFederationByName(f tc.CDNFederation, CDNName string) (*tc.CreateCDNFederationResponse, ReqInf, error) {
-	jsonReq, err := json.Marshal(f)
-	if err != nil { //There is no remoteAddr for ReqInf at this point
-		return nil, ReqInf{CacheHitStatus: CacheHitStatusMiss}, err
-	}
-
 	data := tc.CreateCDNFederationResponse{}
-	url := fmt.Sprintf("%s/cdns/%s/federations", apiBase, CDNName)
-	inf, err := makeReq(to, "POST", url, jsonReq, &data, nil)
+	route := fmt.Sprintf("%s/cdns/%s/federations", apiBase, url.QueryEscape(CDNName))
+	inf, err := to.post(route, f, nil, &data)
 	return &data, inf, err
 }
 
 func (to *Session) GetCDNFederationsByNameWithHdr(CDNName string, header http.Header) (*tc.CDNFederationResponse, ReqInf, error) {
 	data := tc.CDNFederationResponse{}
-	url := fmt.Sprintf("%s/cdns/%s/federations", apiBase, CDNName)
-	inf, err := get(to, url, &data, header)
+	route := fmt.Sprintf("%s/cdns/%s/federations", apiBase, url.QueryEscape(CDNName))
+	inf, err := to.get(route, header, &data)
 	return &data, inf, err
 }
 
@@ -53,21 +48,18 @@ func (to *Session) GetCDNFederationsByName(CDNName string) (*tc.CDNFederationRes
 }
 
 func (to *Session) GetCDNFederationsByNameWithHdrReturnList(CDNName string, header http.Header) ([]tc.CDNFederation, ReqInf, error) {
-	url := fmt.Sprintf("%s/cdns/%s/federations", apiBase, CDNName)
+	route := fmt.Sprintf("%s/cdns/%s/federations", apiBase, url.QueryEscape(CDNName))
 	resp := struct {
 		Response []tc.CDNFederation `json:"response"`
 	}{}
-	inf, err := get(to, url, &resp, header)
-	if err != nil {
-		return nil, inf, err
-	}
-	return resp.Response, inf, nil
+	inf, err := to.get(route, header, &resp)
+	return resp.Response, inf, err
 }
 
 func (to *Session) GetCDNFederationsByIDWithHdr(CDNName string, ID int, header http.Header) (*tc.CDNFederationResponse, ReqInf, error) {
 	data := tc.CDNFederationResponse{}
-	url := fmt.Sprintf("%s/cdns/%s/federations?id=%v", apiBase, CDNName, ID)
-	inf, err := get(to, url, &data, header)
+	route := fmt.Sprintf("%s/cdns/%s/federations?id=%v", apiBase, url.QueryEscape(CDNName), ID)
+	inf, err := to.get(route, header, &data)
 	return &data, inf, err
 }
 
@@ -77,14 +69,9 @@ func (to *Session) GetCDNFederationsByID(CDNName string, ID int) (*tc.CDNFederat
 }
 
 func (to *Session) UpdateCDNFederationsByIDWithHdr(f tc.CDNFederation, CDNName string, ID int, h http.Header) (*tc.UpdateCDNFederationResponse, ReqInf, error) {
-	jsonReq, err := json.Marshal(f)
-	if err != nil { //There is no remoteAddr for ReqInf at this point
-		return nil, ReqInf{CacheHitStatus: CacheHitStatusMiss}, err
-	}
-
 	data := tc.UpdateCDNFederationResponse{}
-	url := fmt.Sprintf("%s/cdns/%s/federations/%d", apiBase, CDNName, ID)
-	inf, err := makeReq(to, "PUT", url, jsonReq, &data, h)
+	route := fmt.Sprintf("%s/cdns/%s/federations/%d", apiBase, url.QueryEscape(CDNName), ID)
+	inf, err := to.put(route, f, h, &data)
 	return &data, inf, err
 }
 
@@ -95,7 +82,7 @@ func (to *Session) UpdateCDNFederationsByID(f tc.CDNFederation, CDNName string,
 
 func (to *Session) DeleteCDNFederationByID(CDNName string, ID int) (*tc.DeleteCDNFederationResponse, ReqInf, error) {
 	data := tc.DeleteCDNFederationResponse{}
-	url := fmt.Sprintf("%s/cdns/%s/federations/%d", apiBase, CDNName, ID)
-	inf, err := makeReq(to, "DELETE", url, nil, &data, nil)
+	route := fmt.Sprintf("%s/cdns/%s/federations/%d", apiBase, url.QueryEscape(CDNName), ID)
+	inf, err := to.del(route, nil, &data)
 	return &data, inf, err
 }
diff --git a/traffic_ops/v3-client/coordinate.go b/traffic_ops/v3-client/coordinate.go
index e0c9acb..971234f 100644
--- a/traffic_ops/v3-client/coordinate.go
+++ b/traffic_ops/v3-client/coordinate.go
@@ -16,9 +16,7 @@
 package client
 
 import (
-	"encoding/json"
 	"fmt"
-	"net"
 	"net/http"
 
 	"github.com/apache/trafficcontrol/lib/go-tc"
@@ -30,43 +28,16 @@ const (
 
 // Create a Coordinate
 func (to *Session) CreateCoordinate(coordinate tc.Coordinate) (tc.Alerts, ReqInf, error) {
-
-	var remoteAddr net.Addr
-	reqBody, err := json.Marshal(coordinate)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	resp, remoteAddr, err := to.request(http.MethodPost, API_COORDINATES, reqBody, nil)
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
 	var alerts tc.Alerts
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
-	return alerts, reqInf, nil
+	reqInf, err := to.post(API_COORDINATES, coordinate, nil, &alerts)
+	return alerts, reqInf, err
 }
 
 func (to *Session) UpdateCoordinateByIDWithHdr(id int, coordinate tc.Coordinate, header http.Header) (tc.Alerts, ReqInf, error) {
-
-	var remoteAddr net.Addr
-	reqBody, err := json.Marshal(coordinate)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
 	route := fmt.Sprintf("%s?id=%d", API_COORDINATES, id)
-	resp, remoteAddr, err := to.request(http.MethodPut, route, reqBody, header)
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-	}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
 	var alerts tc.Alerts
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
-	return alerts, reqInf, nil
+	reqInf, err := to.put(route, coordinate, header, &alerts)
+	return alerts, reqInf, err
 }
 
 // Update a Coordinate by ID
@@ -76,22 +47,9 @@ func (to *Session) UpdateCoordinateByID(id int, coordinate tc.Coordinate) (tc.Al
 }
 
 func (to *Session) GetCoordinatesWithHdr(header http.Header) ([]tc.Coordinate, ReqInf, error) {
-	resp, remoteAddr, err := to.request(http.MethodGet, API_COORDINATES, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.Coordinate{}, reqInf, nil
-		}
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	var data tc.CoordinatesResponse
-	err = json.NewDecoder(resp.Body).Decode(&data)
-	return data.Response, reqInf, nil
+	reqInf, err := to.get(API_COORDINATES, header, &data)
+	return data.Response, reqInf, err
 }
 
 // Returns a list of Coordinates
@@ -102,25 +60,9 @@ func (to *Session) GetCoordinates() ([]tc.Coordinate, ReqInf, error) {
 
 func (to *Session) GetCoordinateByIDWithHdr(id int, header http.Header) ([]tc.Coordinate, ReqInf, error) {
 	route := fmt.Sprintf("%s?id=%d", API_COORDINATES, id)
-	resp, remoteAddr, err := to.request(http.MethodGet, route, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.Coordinate{}, reqInf, nil
-		}
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	var data tc.CoordinatesResponse
-	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
-		return nil, reqInf, err
-	}
-
-	return data.Response, reqInf, nil
+	reqInf, err := to.get(route, header, &data)
+	return data.Response, reqInf, err
 }
 
 // GET a Coordinate by the Coordinate id
@@ -136,38 +78,16 @@ func (to *Session) GetCoordinateByName(name string) ([]tc.Coordinate, ReqInf, er
 }
 
 func (to *Session) GetCoordinateByNameWithHdr(name string, header http.Header) ([]tc.Coordinate, ReqInf, error) {
-	url := fmt.Sprintf("%s?name=%s", API_COORDINATES, name)
-	resp, remoteAddr, err := to.request(http.MethodGet, url, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.Coordinate{}, reqInf, nil
-		}
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
+	route := fmt.Sprintf("%s?name=%s", API_COORDINATES, name)
 	var data tc.CoordinatesResponse
-	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
-		return nil, reqInf, err
-	}
-
-	return data.Response, reqInf, nil
+	reqInf, err := to.get(route, header, &data)
+	return data.Response, reqInf, err
 }
 
 // DELETE a Coordinate by ID
 func (to *Session) DeleteCoordinateByID(id int) (tc.Alerts, ReqInf, error) {
 	route := fmt.Sprintf("%s?id=%d", API_COORDINATES, id)
-	resp, remoteAddr, err := to.request(http.MethodDelete, route, nil, nil)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
 	var alerts tc.Alerts
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
-	return alerts, reqInf, nil
+	reqInf, err := to.del(route, nil, &alerts)
+	return alerts, reqInf, err
 }
diff --git a/traffic_ops/v3-client/crconfig.go b/traffic_ops/v3-client/crconfig.go
index 81d44fc..6c9006f 100644
--- a/traffic_ops/v3-client/crconfig.go
+++ b/traffic_ops/v3-client/crconfig.go
@@ -18,9 +18,10 @@ package client
 import (
 	"encoding/json"
 	"fmt"
-	"github.com/apache/trafficcontrol/lib/go-tc"
 	"net/http"
 	"net/url"
+
+	"github.com/apache/trafficcontrol/lib/go-tc"
 )
 
 const (
@@ -43,16 +44,13 @@ func (to *Session) GetCRConfig(cdn string) ([]byte, ReqInf, error) {
 	if err := json.Unmarshal(bts, &resp); err != nil {
 		return nil, reqInf, err
 	}
-	return []byte(resp.Response), reqInf, nil
+	return resp.Response, reqInf, nil
 }
 
 func (to *Session) SnapshotCRConfigWithHdr(cdn string, header http.Header) (ReqInf, error) {
 	uri := fmt.Sprintf("%s?cdn=%s", API_SNAPSHOT, url.QueryEscape(cdn))
-	resp, remoteAddr, err := to.request(http.MethodPut, uri, nil, header)
-	reqInf := ReqInf{RemoteAddr: remoteAddr, CacheHitStatus: CacheHitStatusMiss}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-	}
+	resp := OuterResponse{}
+	reqInf, err := to.put(uri, nil, header, &resp)
 	return reqInf, err
 }
 
@@ -68,7 +66,7 @@ func (to *Session) GetCRConfigNew(cdn string) ([]byte, ReqInf, error) {
 	if err := json.Unmarshal(bts, &resp); err != nil {
 		return nil, reqInf, err
 	}
-	return []byte(resp.Response), reqInf, nil
+	return resp.Response, reqInf, nil
 }
 
 // SnapshotCRConfig snapshots a CDN by name.
@@ -80,13 +78,7 @@ func (to *Session) SnapshotCRConfig(cdn string) (ReqInf, error) {
 // SnapshotCDNByID snapshots a CDN by ID.
 func (to *Session) SnapshotCRConfigByID(id int) (tc.Alerts, ReqInf, error) {
 	url := fmt.Sprintf("%s?cdnID=%d", API_SNAPSHOT, id)
-	resp, remoteAddr, err := to.request(http.MethodPut, url, nil, nil)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
 	var alerts tc.Alerts
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
-	return alerts, reqInf, nil
+	reqInf, err := to.put(url, nil, nil, &alerts)
+	return alerts, reqInf, err
 }
diff --git a/traffic_ops/v3-client/deliveryservice.go b/traffic_ops/v3-client/deliveryservice.go
index c2b55e8..36ecea7 100644
--- a/traffic_ops/v3-client/deliveryservice.go
+++ b/traffic_ops/v3-client/deliveryservice.go
@@ -119,7 +119,7 @@ const (
 
 func (to *Session) GetDeliveryServicesByServerV30WithHdr(id int, header http.Header) ([]tc.DeliveryServiceNullableV30, ReqInf, error) {
 	var data tc.DeliveryServicesResponseV30
-	reqInf, err := get(to, fmt.Sprintf(API_SERVER_DELIVERY_SERVICES, id), &data, header)
+	reqInf, err := to.get(fmt.Sprintf(API_SERVER_DELIVERY_SERVICES, id), header, &data)
 	return data.Response, reqInf, err
 }
 
@@ -138,12 +138,8 @@ func (to *Session) GetDeliveryServicesByServer(id int) ([]tc.DeliveryServiceNull
 func (to *Session) GetDeliveryServicesByServerWithHdr(id int, header http.Header) ([]tc.DeliveryServiceNullable, ReqInf, error) {
 	var data tc.DeliveryServicesNullableResponse
 
-	reqInf, err := get(to, fmt.Sprintf(API_SERVER_DELIVERY_SERVICES, id), &data, header)
-	if err != nil {
-		return nil, reqInf, err
-	}
-
-	return data.Response, reqInf, nil
+	reqInf, err := to.get(fmt.Sprintf(API_SERVER_DELIVERY_SERVICES, id), header, &data)
+	return data.Response, reqInf, err
 }
 
 // GetDeliveryServicesV30WithHdr returns all (tenant-visible) Delivery Services that
@@ -154,10 +150,8 @@ func (to *Session) GetDeliveryServicesV30WithHdr(header http.Header, params url.
 	if params != nil {
 		uri += "?" + params.Encode()
 	}
-
 	var data tc.DeliveryServicesResponseV30
-
-	reqInf, err := get(to, uri, &data, header)
+	reqInf, err := to.get(uri, header, &data)
 	return data.Response, reqInf, err
 }
 
@@ -165,11 +159,8 @@ func (to *Session) GetDeliveryServicesNullableWithHdr(header http.Header) ([]tc.
 	data := struct {
 		Response []tc.DeliveryServiceNullable `json:"response"`
 	}{}
-	reqInf, err := get(to, API_DELIVERY_SERVICES, &data, header)
-	if err != nil {
-		return nil, reqInf, err
-	}
-	return data.Response, reqInf, nil
+	reqInf, err := to.get(API_DELIVERY_SERVICES, header, &data)
+	return data.Response, reqInf, err
 }
 
 // GetDeliveryServicesNullable returns a slice of Delivery Services.
@@ -187,11 +178,8 @@ func (to *Session) GetDeliveryServicesByCDNIDWithHdr(cdnID int, header http.Head
 	data := struct {
 		Response []tc.DeliveryServiceNullable `json:"response"`
 	}{}
-	reqInf, err := get(to, API_DELIVERY_SERVICES+"?cdn="+strconv.Itoa(cdnID), &data, header)
-	if err != nil {
-		return nil, reqInf, err
-	}
-	return data.Response, reqInf, nil
+	reqInf, err := to.get(API_DELIVERY_SERVICES+"?cdn="+strconv.Itoa(cdnID), header, &data)
+	return data.Response, reqInf, err
 }
 
 // GetDeliveryServicesByCDNID returns the (tenant-visible) Delivery Services within the CDN identified
@@ -212,7 +200,7 @@ func (to *Session) GetDeliveryServiceNullableWithHdr(id string, header http.Head
 		Response []tc.DeliveryServiceNullableV30 `json:"response"`
 	}{}
 	route := fmt.Sprintf("%s?id=%s", API_DELIVERY_SERVICES, id)
-	reqInf, err := get(to, route, &data, header)
+	reqInf, err := to.get(route, header, &data)
 	if err != nil {
 		return nil, reqInf, err
 	}
@@ -234,7 +222,7 @@ func (to *Session) GetDeliveryServiceNullable(id string) (*tc.DeliveryServiceNul
 	data := struct {
 		Response []tc.DeliveryServiceNullable `json:"response"`
 	}{}
-	reqInf, err := get(to, API_DELIVERY_SERVICES+"?id="+id, &data, nil)
+	reqInf, err := to.get(API_DELIVERY_SERVICES+"?id="+url.QueryEscape(id), nil, &data)
 	if err != nil {
 		return nil, reqInf, err
 	}
@@ -248,12 +236,8 @@ func (to *Session) GetDeliveryServiceNullable(id string) (*tc.DeliveryServiceNul
 // the given XMLID.
 func (to *Session) GetDeliveryServiceByXMLIDNullableWithHdr(XMLID string, header http.Header) ([]tc.DeliveryServiceNullableV30, ReqInf, error) {
 	var data tc.DeliveryServicesResponseV30
-	reqInf, err := get(to, API_DELIVERY_SERVICES+"?xmlId="+XMLID, &data, header)
-	if err != nil {
-		return nil, reqInf, err
-	}
-
-	return data.Response, reqInf, nil
+	reqInf, err := to.get(API_DELIVERY_SERVICES+"?xmlId="+url.QueryEscape(XMLID), header, &data)
+	return data.Response, reqInf, err
 }
 
 // GetDeliveryServiceByXMLIDNullable returns the Delivery Service identified by the passed XMLID.
@@ -281,7 +265,7 @@ func (to *Session) GetDeliveryServiceByXMLIDNullable(XMLID string) ([]tc.Deliver
 func (to *Session) CreateDeliveryServiceV30(ds tc.DeliveryServiceNullableV30) (tc.DeliveryServiceNullableV30, ReqInf, error) {
 	var reqInf ReqInf
 	if ds.TypeID == nil && ds.Type != nil {
-		ty, _, err := to.GetTypeByName(ds.Type.String())
+		ty, _, err := to.GetTypeByNameWithHdr(ds.Type.String(), nil)
 		if err != nil {
 			return tc.DeliveryServiceNullableV30{}, reqInf, err
 		}
@@ -292,7 +276,7 @@ func (to *Session) CreateDeliveryServiceV30(ds tc.DeliveryServiceNullableV30) (t
 	}
 
 	if ds.CDNID == nil && ds.CDNName != nil {
-		cdns, _, err := to.GetCDNByName(*ds.CDNName)
+		cdns, _, err := to.GetCDNByNameWithHdr(*ds.CDNName, nil)
 		if err != nil {
 			return tc.DeliveryServiceNullableV30{}, reqInf, err
 		}
@@ -303,7 +287,7 @@ func (to *Session) CreateDeliveryServiceV30(ds tc.DeliveryServiceNullableV30) (t
 	}
 
 	if ds.ProfileID == nil && ds.ProfileName != nil {
-		profiles, _, err := to.GetProfileByName(*ds.ProfileName)
+		profiles, _, err := to.GetProfileByNameWithHdr(*ds.ProfileName, nil)
 		if err != nil {
 			return tc.DeliveryServiceNullableV30{}, reqInf, err
 		}
@@ -314,20 +298,15 @@ func (to *Session) CreateDeliveryServiceV30(ds tc.DeliveryServiceNullableV30) (t
 	}
 
 	if ds.TenantID == nil && ds.Tenant != nil {
-		ten, _, err := to.TenantByName(*ds.Tenant)
+		ten, _, err := to.TenantByNameWithHdr(*ds.Tenant, nil)
 		if err != nil {
 			return tc.DeliveryServiceNullableV30{}, reqInf, err
 		}
 		ds.TenantID = &ten.ID
 	}
 
-	bts, err := json.Marshal(ds)
-	if err != nil {
-		return tc.DeliveryServiceNullableV30{}, reqInf, nil
-	}
-
 	var data tc.DeliveryServicesResponseV30
-	reqInf, err = post(to, API_DELIVERY_SERVICES, bts, &data)
+	reqInf, err := to.post(API_DELIVERY_SERVICES, ds, nil, &data)
 	if err != nil {
 		return tc.DeliveryServiceNullableV30{}, reqInf, err
 	}
@@ -348,7 +327,7 @@ func (to *Session) CreateDeliveryServiceV30(ds tc.DeliveryServiceNullableV30) (t
 // CreateDeliveryServiceV30.
 func (to *Session) CreateDeliveryServiceNullable(ds *tc.DeliveryServiceNullable) (*tc.CreateDeliveryServiceNullableResponse, error) {
 	if ds.TypeID == nil && ds.Type != nil {
-		ty, _, err := to.GetTypeByName(ds.Type.String())
+		ty, _, err := to.GetTypeByNameWithHdr(ds.Type.String(), nil)
 		if err != nil {
 			return nil, err
 		}
@@ -359,7 +338,7 @@ func (to *Session) CreateDeliveryServiceNullable(ds *tc.DeliveryServiceNullable)
 	}
 
 	if ds.CDNID == nil && ds.CDNName != nil {
-		cdns, _, err := to.GetCDNByName(*ds.CDNName)
+		cdns, _, err := to.GetCDNByNameWithHdr(*ds.CDNName, nil)
 		if err != nil {
 			return nil, err
 		}
@@ -370,7 +349,7 @@ func (to *Session) CreateDeliveryServiceNullable(ds *tc.DeliveryServiceNullable)
 	}
 
 	if ds.ProfileID == nil && ds.ProfileName != nil {
-		profiles, _, err := to.GetProfileByName(*ds.ProfileName)
+		profiles, _, err := to.GetProfileByNameWithHdr(*ds.ProfileName, nil)
 		if err != nil {
 			return nil, err
 		}
@@ -381,7 +360,7 @@ func (to *Session) CreateDeliveryServiceNullable(ds *tc.DeliveryServiceNullable)
 	}
 
 	if ds.TenantID == nil && ds.Tenant != nil {
-		ten, _, err := to.TenantByName(*ds.Tenant)
+		ten, _, err := to.TenantByNameWithHdr(*ds.Tenant, nil)
 		if err != nil {
 			return nil, err
 		}
@@ -389,11 +368,7 @@ func (to *Session) CreateDeliveryServiceNullable(ds *tc.DeliveryServiceNullable)
 	}
 
 	var data tc.CreateDeliveryServiceNullableResponse
-	jsonReq, err := json.Marshal(ds)
-	if err != nil {
-		return nil, err
-	}
-	_, err = post(to, API_DELIVERY_SERVICES, jsonReq, &data)
+	_, err := to.post(API_DELIVERY_SERVICES, ds, nil, &data)
 	if err != nil {
 		return nil, err
 	}
@@ -404,14 +379,8 @@ func (to *Session) CreateDeliveryServiceNullable(ds *tc.DeliveryServiceNullable)
 // UpdateDeliveryServiceV30WithHdr replaces the Delivery Service identified by the
 // integral, unique identifier 'id' with the one it's passed.
 func (to *Session) UpdateDeliveryServiceV30WithHdr(id int, ds tc.DeliveryServiceNullableV30, header http.Header) (tc.DeliveryServiceNullableV30, ReqInf, error) {
-	var reqInf ReqInf
-	bts, err := json.Marshal(ds)
-	if err != nil {
-		return tc.DeliveryServiceNullableV30{}, reqInf, err
-	}
-
 	var data tc.DeliveryServicesResponseV30
-	reqInf, err = put(to, fmt.Sprintf(API_DELIVERY_SERVICE_ID, id), bts, &data, header)
+	reqInf, err := to.put(fmt.Sprintf(API_DELIVERY_SERVICE_ID, id), ds, header, &data)
 	if err != nil {
 		return tc.DeliveryServiceNullableV30{}, reqInf, err
 	}
@@ -437,32 +406,26 @@ func (to *Session) UpdateDeliveryServiceNullable(id string, ds *tc.DeliveryServi
 
 func (to *Session) UpdateDeliveryServiceNullableWithHdr(id string, ds *tc.DeliveryServiceNullable, header http.Header) (*tc.UpdateDeliveryServiceNullableResponse, error) {
 	var data tc.UpdateDeliveryServiceNullableResponse
-	jsonReq, err := json.Marshal(ds)
-	if err != nil {
-		return nil, err
-	}
-	_, err = put(to, fmt.Sprintf(API_DELIVERY_SERVICE_ID, id), jsonReq, &data, header)
+	_, err := to.put(fmt.Sprintf(API_DELIVERY_SERVICE_ID, id), ds, header, &data)
 	if err != nil {
 		return nil, err
 	}
-
 	return &data, nil
 }
 
 // DeleteDeliveryService deletes the DeliveryService matching the ID it's passed.
 func (to *Session) DeleteDeliveryService(id string) (*tc.DeleteDeliveryServiceResponse, error) {
 	var data tc.DeleteDeliveryServiceResponse
-	_, err := del(to, fmt.Sprintf(API_DELIVERY_SERVICE_ID, id), &data)
+	_, err := to.del(fmt.Sprintf(API_DELIVERY_SERVICE_ID, id), nil, &data)
 	if err != nil {
 		return nil, err
 	}
-
 	return &data, nil
 }
 
 func (to *Session) GetDeliveryServiceHealthWithHdr(id string, header http.Header) (*tc.DeliveryServiceHealth, ReqInf, error) {
 	var data tc.DeliveryServiceHealthResponse
-	reqInf, err := get(to, fmt.Sprintf(API_DELIVERY_SERVICE_HEALTH, id), &data, nil)
+	reqInf, err := to.get(fmt.Sprintf(API_DELIVERY_SERVICE_HEALTH, id), nil, &data)
 	if err != nil {
 		return nil, reqInf, err
 	}
@@ -479,11 +442,10 @@ func (to *Session) GetDeliveryServiceHealth(id string) (*tc.DeliveryServiceHealt
 
 func (to *Session) GetDeliveryServiceCapacityWithHdr(id string, header http.Header) (*tc.DeliveryServiceCapacity, ReqInf, error) {
 	var data tc.DeliveryServiceCapacityResponse
-	reqInf, err := get(to, fmt.Sprintf(API_DELIVERY_SERVICE_CAPACITY, id), &data, header)
+	reqInf, err := to.get(fmt.Sprintf(API_DELIVERY_SERVICE_CAPACITY, id), header, &data)
 	if err != nil {
 		return nil, reqInf, err
 	}
-
 	return &data.Response, reqInf, nil
 }
 
@@ -494,40 +456,6 @@ func (to *Session) GetDeliveryServiceCapacity(id string) (*tc.DeliveryServiceCap
 	return to.GetDeliveryServiceCapacityWithHdr(id, nil)
 }
 
-// GetDeliveryServiceServer returns associations between Delivery Services and servers using the
-// provided pagination controls.
-// Deprecated: GetDeliveryServiceServer will be removed in 6.0. Use GetDeliveryServiceServerWithHdr.
-func (to *Session) GetDeliveryServiceServer(page, limit string) ([]tc.DeliveryServiceServer, ReqInf, error) {
-	return to.GetDeliveryServiceServerWithHdr(page, limit, nil)
-}
-
-func (to *Session) GetDeliveryServiceServerWithHdr(page, limit string, header http.Header) ([]tc.DeliveryServiceServer, ReqInf, error) {
-	var data tc.DeliveryServiceServerResponse
-	reqInf, err := get(to, API_DELIVERY_SERVICE_SERVER+"?page="+page+"&limit="+limit, &data, header)
-	if err != nil {
-		return nil, reqInf, err
-	}
-
-	return data.Response, reqInf, nil
-}
-
-// GetDeliveryServiceRegexes returns the "Regexes" (Regular Expressions) used by all (tenant-visible)
-// Delivery Services.
-// Deprecated: GetDeliveryServiceRegexes will be removed in 6.0. Use GetDeliveryServiceRegexesWithHdr.
-func (to *Session) GetDeliveryServiceRegexes() ([]tc.DeliveryServiceRegexes, ReqInf, error) {
-	return to.GetDeliveryServiceRegexesWithHdr(nil)
-}
-
-func (to *Session) GetDeliveryServiceRegexesWithHdr(header http.Header) ([]tc.DeliveryServiceRegexes, ReqInf, error) {
-	var data tc.DeliveryServiceRegexResponse
-	reqInf, err := get(to, API_DELIVERY_SERVICES_REGEXES, &data, header)
-	if err != nil {
-		return nil, reqInf, err
-	}
-
-	return data.Response, reqInf, nil
-}
-
 // GenerateSSLKeysForDS generates ssl keys for a given cdn
 func (to *Session) GenerateSSLKeysForDS(XMLID string, CDNName string, sslFields tc.SSLKeyRequestFields) (string, ReqInf, error) {
 	version := util.JSONIntStr(1)
@@ -543,14 +471,10 @@ func (to *Session) GenerateSSLKeysForDS(XMLID string, CDNName string, sslFields
 		State:           sslFields.State,
 		Version:         &version,
 	}
-	jsonReq, err := json.Marshal(request)
-	if err != nil {
-		return "", ReqInf{}, err
-	}
 	response := struct {
 		Response string `json:"response"`
 	}{}
-	reqInf, err := post(to, API_DELIVERY_SERVICE_GENERATE_SSL_KEYS, jsonReq, &response)
+	reqInf, err := to.post(API_DELIVERY_SERVICE_GENERATE_SSL_KEYS, request, nil, &response)
 	if err != nil {
 		return "", reqInf, err
 	}
@@ -559,13 +483,10 @@ func (to *Session) GenerateSSLKeysForDS(XMLID string, CDNName string, sslFields
 
 func (to *Session) DeleteDeliveryServiceSSLKeysByID(XMLID string) (string, ReqInf, error) {
 	resp := struct {
-		Response string `json:"resposne"`
+		Response string `json:"response"`
 	}{}
-	reqInf, err := del(to, fmt.Sprintf(API_DELIVERY_SERVICE_XMLID_SSL_KEYS, XMLID), &resp)
-	if err != nil {
-		return "", reqInf, err
-	}
-	return resp.Response, reqInf, nil
+	reqInf, err := to.del(fmt.Sprintf(API_DELIVERY_SERVICE_XMLID_SSL_KEYS, url.QueryEscape(XMLID)), nil, &resp)
+	return resp.Response, reqInf, err
 }
 
 // GetDeliveryServiceSSLKeysByID returns information about the SSL Keys used by the Delivery
@@ -577,11 +498,10 @@ func (to *Session) GetDeliveryServiceSSLKeysByID(XMLID string) (*tc.DeliveryServ
 
 func (to *Session) GetDeliveryServiceSSLKeysByIDWithHdr(XMLID string, header http.Header) (*tc.DeliveryServiceSSLKeys, ReqInf, error) {
 	var data tc.DeliveryServiceSSLKeysResponse
-	reqInf, err := get(to, fmt.Sprintf(API_DELIVERY_SERVICE_XMLID_SSL_KEYS, XMLID), &data, header)
+	reqInf, err := to.get(fmt.Sprintf(API_DELIVERY_SERVICE_XMLID_SSL_KEYS, url.QueryEscape(XMLID)), header, &data)
 	if err != nil {
 		return nil, reqInf, err
 	}
-
 	return &data.Response, reqInf, nil
 }
 
@@ -590,11 +510,8 @@ func (to *Session) GetDeliveryServicesEligibleWithHdr(dsID int, header http.Head
 		Response []tc.DSServer `json:"response"`
 	}{Response: []tc.DSServer{}}
 
-	reqInf, err := get(to, fmt.Sprintf(API_DELIVERY_SERVICE_ELIGIBLE_SERVERS, dsID), &resp, header)
-	if err != nil {
-		return nil, reqInf, err
-	}
-	return resp.Response, reqInf, nil
+	reqInf, err := to.get(fmt.Sprintf(API_DELIVERY_SERVICE_ELIGIBLE_SERVERS, dsID), header, &resp)
+	return resp.Response, reqInf, err
 }
 
 // GetDeliveryServicesEligible returns the servers eligible for assignment to the Delivery
@@ -616,7 +533,7 @@ func (to *Session) GetDeliveryServiceURLSigKeysWithHdr(dsName string, header htt
 		Response tc.URLSigKeys `json:"response"`
 	}{}
 
-	reqInf, err := get(to, fmt.Sprintf(API_DELIVERY_SERVICES_URL_SIGNING_KEYS, dsName), &data, header)
+	reqInf, err := to.get(fmt.Sprintf(API_DELIVERY_SERVICES_URL_SIGNING_KEYS, dsName), header, &data)
 	if err != nil {
 		return tc.URLSigKeys{}, reqInf, err
 	}
@@ -632,7 +549,7 @@ func (to *Session) GetDeliveryServiceURISigningKeys(dsName string) ([]byte, ReqI
 // identified by the XMLID 'dsName'. The result is not parsed.
 func (to *Session) GetDeliveryServiceURISigningKeysWithHdr(dsName string, header http.Header) ([]byte, ReqInf, error) {
 	data := json.RawMessage{}
-	reqInf, err := get(to, fmt.Sprintf(API_DELIVERY_SERVICES_URI_SIGNING_KEYS, dsName), &data, header)
+	reqInf, err := to.get(fmt.Sprintf(API_DELIVERY_SERVICES_URI_SIGNING_KEYS, url.QueryEscape(dsName)), header, &data)
 	if err != nil {
 		return []byte{}, reqInf, err
 	}
@@ -642,14 +559,8 @@ func (to *Session) GetDeliveryServiceURISigningKeysWithHdr(dsName string, header
 // SafeDeliveryServiceUpdateV30WithHdr updates the "safe" fields of the Delivery
 // Service identified by the integral, unique identifier 'id'.
 func (to *Session) SafeDeliveryServiceUpdateV30WithHdr(id int, r tc.DeliveryServiceSafeUpdateRequest, header http.Header) (tc.DeliveryServiceNullableV30, ReqInf, error) {
-	var reqInf ReqInf
-	req, err := json.Marshal(r)
-	if err != nil {
-		return tc.DeliveryServiceNullableV30{}, reqInf, err
-	}
-
 	var data tc.DeliveryServiceSafeUpdateResponseV30
-	reqInf, err = put(to, fmt.Sprintf(API_DELIVERY_SERVICES_SAFE_UPDATE, id), req, &data, header)
+	reqInf, err := to.put(fmt.Sprintf(API_DELIVERY_SERVICES_SAFE_UPDATE, id), r, header, &data)
 	if err != nil {
 		return tc.DeliveryServiceNullableV30{}, reqInf, err
 	}
@@ -667,18 +578,12 @@ func (to *Session) SafeDeliveryServiceUpdateV30WithHdr(id int, r tc.DeliveryServ
 // versioned methods, specifically, for API v3.0 - in this case,
 // SafeDeliveryServiceUpdateV30WithHdr.
 func (to *Session) UpdateDeliveryServiceSafe(id int, ds tc.DeliveryServiceSafeUpdateRequest) ([]tc.DeliveryServiceNullable, ReqInf, error) {
-	var reqInf ReqInf
 	var resp tc.DeliveryServiceSafeUpdateResponse
-
-	req, err := json.Marshal(ds)
+	reqInf, err := to.put(fmt.Sprintf(API_DELIVERY_SERVICES_SAFE_UPDATE, id), ds, nil, &resp)
 	if err != nil {
 		return resp.Response, reqInf, err
 	}
 
-	if reqInf, err = put(to, fmt.Sprintf(API_DELIVERY_SERVICES_SAFE_UPDATE, id), req, &resp, nil); err != nil {
-		return resp.Response, reqInf, err
-	}
-
 	if len(resp.Response) < 1 {
 		err = errors.New("Traffic Ops returned success, but response was missing the Delivery Service")
 	}
@@ -695,6 +600,6 @@ func (to *Session) UpdateDeliveryServiceSafe(id int, ds tc.DeliveryServiceSafeUp
 // GetDeliveryServicesV30WithHdr.
 func (to *Session) GetAccessibleDeliveryServicesByTenant(tenantId int) ([]tc.DeliveryServiceNullable, ReqInf, error) {
 	data := tc.DeliveryServicesNullableResponse{}
-	reqInf, err := get(to, fmt.Sprintf("%v?accessibleTo=%v", API_DELIVERY_SERVICES, tenantId), &data, nil)
+	reqInf, err := to.get(fmt.Sprintf("%s?accessibleTo=%d", API_DELIVERY_SERVICES, tenantId), nil, &data)
 	return data.Response, reqInf, err
 }
diff --git a/traffic_ops/v3-client/deliveryservice_regexes.go b/traffic_ops/v3-client/deliveryservice_regexes.go
index 3e412df..ec5e7bd 100644
--- a/traffic_ops/v3-client/deliveryservice_regexes.go
+++ b/traffic_ops/v3-client/deliveryservice_regexes.go
@@ -16,9 +16,7 @@
 package client
 
 import (
-	"encoding/json"
 	"fmt"
-	"net"
 	"net/http"
 
 	"github.com/apache/trafficcontrol/lib/go-tc"
@@ -26,7 +24,7 @@ import (
 
 const (
 	// See: https://traffic-control-cdn.readthedocs.io/en/latest/api/v3/deliveryservices_id_regexes.html
-	API_DS_REGEXES = apiBase + "/deliveryservices/%v/regexes"
+	API_DS_REGEXES = apiBase + "/deliveryservices/%d/regexes"
 )
 
 // GetDeliveryServiceRegexesByDSID gets DeliveryServiceRegexes by a DS id
@@ -35,32 +33,26 @@ func (to *Session) GetDeliveryServiceRegexesByDSID(dsID int, params map[string]s
 	response := struct {
 		Response []tc.DeliveryServiceIDRegex `json:"response"`
 	}{}
+	reqInf, err := to.get(fmt.Sprintf(API_DS_REGEXES, dsID)+mapToQueryParameters(params), nil, &response)
+	return response.Response, reqInf, err
+}
+
+// GetDeliveryServiceRegexes returns the "Regexes" (Regular Expressions) used by all (tenant-visible)
+// Delivery Services.
+// Deprecated: GetDeliveryServiceRegexes will be removed in 6.0. Use GetDeliveryServiceRegexesWithHdr.
+func (to *Session) GetDeliveryServiceRegexes() ([]tc.DeliveryServiceRegexes, ReqInf, error) {
+	return to.GetDeliveryServiceRegexesWithHdr(nil)
+}
 
-	reqInf, err := get(to, fmt.Sprintf(API_DS_REGEXES, dsID)+mapToQueryParameters(params), &response, nil)
-	if err != nil {
-		return []tc.DeliveryServiceIDRegex{}, reqInf, err
-	}
-	return response.Response, reqInf, nil
+func (to *Session) GetDeliveryServiceRegexesWithHdr(header http.Header) ([]tc.DeliveryServiceRegexes, ReqInf, error) {
+	var data tc.DeliveryServiceRegexResponse
+	reqInf, err := to.get(API_DELIVERY_SERVICES_REGEXES, header, &data)
+	return data.Response, reqInf, err
 }
 
 func (to *Session) PostDeliveryServiceRegexesByDSID(dsID int, regex tc.DeliveryServiceRegexPost) (tc.Alerts, ReqInf, error) {
 	var alerts tc.Alerts
-	var remoteAddr net.Addr
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	reqBody, err := json.Marshal(regex)
-	if err != nil {
-		return alerts, reqInf, err
-	}
-
-	resp, remoteAddr, err := to.request(http.MethodPost, fmt.Sprintf(API_DS_REGEXES, dsID), reqBody, nil)
-	reqInf.RemoteAddr = remoteAddr
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-	}
-	if err != nil {
-		return alerts, reqInf, err
-	}
-	defer resp.Body.Close()
-
-	return alerts, reqInf, nil
+	route := fmt.Sprintf(API_DS_REGEXES, dsID)
+	reqInf, err := to.post(route, regex, nil, &alerts)
+	return alerts, reqInf, err
 }
diff --git a/traffic_ops/v3-client/deliveryservice_request_comments.go b/traffic_ops/v3-client/deliveryservice_request_comments.go
index a9e3574..64c49f6 100644
--- a/traffic_ops/v3-client/deliveryservice_request_comments.go
+++ b/traffic_ops/v3-client/deliveryservice_request_comments.go
@@ -16,8 +16,6 @@
 package client
 
 import (
-	"encoding/json"
-	"net"
 	"net/http"
 
 	"github.com/apache/trafficcontrol/lib/go-tc"
@@ -31,43 +29,16 @@ const (
 
 // Create a delivery service request comment
 func (to *Session) CreateDeliveryServiceRequestComment(comment tc.DeliveryServiceRequestComment) (tc.Alerts, ReqInf, error) {
-
-	var remoteAddr net.Addr
-	reqBody, err := json.Marshal(comment)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	resp, remoteAddr, err := to.request(http.MethodPost, API_DELIVERY_SERVICE_REQUEST_COMMENTS, reqBody, nil)
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
 	var alerts tc.Alerts
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
-	return alerts, reqInf, nil
+	reqInf, err := to.post(API_DELIVERY_SERVICE_REQUEST_COMMENTS, comment, nil, &alerts)
+	return alerts, reqInf, err
 }
 
 func (to *Session) UpdateDeliveryServiceRequestCommentByIDWithHdr(id int, comment tc.DeliveryServiceRequestComment, header http.Header) (tc.Alerts, ReqInf, error) {
-
-	var remoteAddr net.Addr
-	reqBody, err := json.Marshal(comment)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
 	route := fmt.Sprintf("%s?id=%d", API_DELIVERY_SERVICE_REQUEST_COMMENTS, id)
-	resp, remoteAddr, err := to.request(http.MethodPut, route, reqBody, header)
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-	}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
 	var alerts tc.Alerts
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
-	return alerts, reqInf, nil
+	reqInf, err := to.put(route, comment, header, &alerts)
+	return alerts, reqInf, err
 }
 
 // Update a delivery service request by ID
@@ -77,22 +48,9 @@ func (to *Session) UpdateDeliveryServiceRequestCommentByID(id int, comment tc.De
 }
 
 func (to *Session) GetDeliveryServiceRequestCommentsWithHdr(header http.Header) ([]tc.DeliveryServiceRequestComment, ReqInf, error) {
-	resp, remoteAddr, err := to.request(http.MethodGet, API_DELIVERY_SERVICE_REQUEST_COMMENTS, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.DeliveryServiceRequestComment{}, reqInf, nil
-		}
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	var data tc.DeliveryServiceRequestCommentsResponse
-	err = json.NewDecoder(resp.Body).Decode(&data)
-	return data.Response, reqInf, nil
+	reqInf, err := to.get(API_DELIVERY_SERVICE_REQUEST_COMMENTS, header, &data)
+	return data.Response, reqInf, err
 }
 
 // Returns a list of delivery service request comments
@@ -103,25 +61,9 @@ func (to *Session) GetDeliveryServiceRequestComments() ([]tc.DeliveryServiceRequ
 
 func (to *Session) GetDeliveryServiceRequestCommentByIDWithHdr(id int, header http.Header) ([]tc.DeliveryServiceRequestComment, ReqInf, error) {
 	route := fmt.Sprintf("%s?id=%d", API_DELIVERY_SERVICE_REQUEST_COMMENTS, id)
-	resp, remoteAddr, err := to.request(http.MethodGet, route, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.DeliveryServiceRequestComment{}, reqInf, nil
-		}
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	var data tc.DeliveryServiceRequestCommentsResponse
-	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
-		return nil, reqInf, err
-	}
-
-	return data.Response, reqInf, nil
+	reqInf, err := to.get(route, header, &data)
+	return data.Response, reqInf, err
 }
 
 // GET a delivery service request comment by ID
@@ -133,13 +75,7 @@ func (to *Session) GetDeliveryServiceRequestCommentByID(id int) ([]tc.DeliverySe
 // DELETE a delivery service request comment by ID
 func (to *Session) DeleteDeliveryServiceRequestCommentByID(id int) (tc.Alerts, ReqInf, error) {
 	route := fmt.Sprintf("%s?id=%d", API_DELIVERY_SERVICE_REQUEST_COMMENTS, id)
-	resp, remoteAddr, err := to.request(http.MethodDelete, route, nil, nil)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
 	var alerts tc.Alerts
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
-	return alerts, reqInf, nil
+	reqInf, err := to.del(route, nil, &alerts)
+	return alerts, reqInf, err
 }
diff --git a/traffic_ops/v3-client/deliveryservice_requests.go b/traffic_ops/v3-client/deliveryservice_requests.go
index 949986f..9997bfc 100644
--- a/traffic_ops/v3-client/deliveryservice_requests.go
+++ b/traffic_ops/v3-client/deliveryservice_requests.go
@@ -16,11 +16,8 @@
 package client
 
 import (
-	"encoding/json"
 	"errors"
 	"fmt"
-	"io/ioutil"
-	"net"
 	"net/http"
 	"net/url"
 
@@ -34,9 +31,8 @@ const (
 // CreateDeliveryServiceRequest creates a Delivery Service Request.
 func (to *Session) CreateDeliveryServiceRequest(dsr tc.DeliveryServiceRequest) (tc.Alerts, ReqInf, error) {
 	var alerts tc.Alerts
-	var remoteAddr net.Addr
 	if dsr.AssigneeID == 0 && dsr.Assignee != "" {
-		res, reqInf, err := to.GetUserByUsername(dsr.Assignee)
+		res, reqInf, err := to.GetUserByUsernameWithHdr(dsr.Assignee, nil)
 		if err != nil {
 			return alerts, reqInf, err
 		}
@@ -47,7 +43,7 @@ func (to *Session) CreateDeliveryServiceRequest(dsr tc.DeliveryServiceRequest) (
 	}
 
 	if dsr.AuthorID == 0 && dsr.Author != "" {
-		res, reqInf, err := to.GetUserByUsername(dsr.Author)
+		res, reqInf, err := to.GetUserByUsernameWithHdr(dsr.Author, nil)
 		if err != nil {
 			return alerts, reqInf, err
 		}
@@ -58,7 +54,7 @@ func (to *Session) CreateDeliveryServiceRequest(dsr tc.DeliveryServiceRequest) (
 	}
 
 	if dsr.DeliveryService.TypeID == 0 && dsr.DeliveryService.Type.String() != "" {
-		ty, reqInf, err := to.GetTypeByName(dsr.DeliveryService.Type.String())
+		ty, reqInf, err := to.GetTypeByNameWithHdr(dsr.DeliveryService.Type.String(), nil)
 		if err != nil || len(ty) == 0 {
 			return alerts, reqInf, errors.New("no type named " + dsr.DeliveryService.Type.String())
 		}
@@ -66,7 +62,7 @@ func (to *Session) CreateDeliveryServiceRequest(dsr tc.DeliveryServiceRequest) (
 	}
 
 	if dsr.DeliveryService.CDNID == 0 && dsr.DeliveryService.CDNName != "" {
-		cdns, reqInf, err := to.GetCDNByName(dsr.DeliveryService.CDNName)
+		cdns, reqInf, err := to.GetCDNByNameWithHdr(dsr.DeliveryService.CDNName, nil)
 		if err != nil || len(cdns) == 0 {
 			return alerts, reqInf, errors.New("no CDN named " + dsr.DeliveryService.CDNName)
 		}
@@ -74,7 +70,7 @@ func (to *Session) CreateDeliveryServiceRequest(dsr tc.DeliveryServiceRequest) (
 	}
 
 	if dsr.DeliveryService.ProfileID == 0 && dsr.DeliveryService.ProfileName != "" {
-		profiles, reqInf, err := to.GetProfileByName(dsr.DeliveryService.ProfileName)
+		profiles, reqInf, err := to.GetProfileByNameWithHdr(dsr.DeliveryService.ProfileName, nil)
 		if err != nil || len(profiles) == 0 {
 			return alerts, reqInf, errors.New("no Profile named " + dsr.DeliveryService.ProfileName)
 		}
@@ -82,57 +78,23 @@ func (to *Session) CreateDeliveryServiceRequest(dsr tc.DeliveryServiceRequest) (
 	}
 
 	if dsr.DeliveryService.TenantID == 0 && dsr.DeliveryService.Tenant != "" {
-		ten, reqInf, err := to.TenantByName(dsr.DeliveryService.Tenant)
+		ten, reqInf, err := to.TenantByNameWithHdr(dsr.DeliveryService.Tenant, nil)
 		if err != nil || ten == nil {
 			return alerts, reqInf, errors.New("no Tenant named " + dsr.DeliveryService.Tenant)
 		}
 		dsr.DeliveryService.TenantID = ten.ID
 	}
 
-	reqBody, err := json.Marshal(dsr)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return alerts, reqInf, err
-	}
-	resp, remoteAddr, err := to.RawRequest(http.MethodPost, API_DS_REQUESTS, reqBody)
-	defer resp.Body.Close()
-
-	if err == nil {
-		body, readErr := ioutil.ReadAll(resp.Body)
-		if readErr != nil {
-			return alerts, reqInf, readErr
-		}
-		if err = json.Unmarshal(body, &alerts); err != nil {
-			return alerts, reqInf, err
-		}
-	}
-
+	reqInf, err := to.post(API_DS_REQUESTS, dsr, nil, &alerts)
 	return alerts, reqInf, err
 }
 
 func (to *Session) GetDeliveryServiceRequestsWithHdr(header http.Header) ([]tc.DeliveryServiceRequest, ReqInf, error) {
-	resp, remoteAddr, err := to.request(http.MethodGet, API_DS_REQUESTS, nil, header)
-
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.DeliveryServiceRequest{}, reqInf, nil
-		}
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	data := struct {
 		Response []tc.DeliveryServiceRequest `json:"response"`
 	}{}
-	if err = json.NewDecoder(resp.Body).Decode(&data); err != nil {
-		return nil, reqInf, err
-	}
-
-	return data.Response, reqInf, nil
+	reqInf, err := to.get(API_DS_REQUESTS, header, &data)
+	return data.Response, reqInf, err
 }
 
 // GetDeliveryServiceRequests retrieves all deliveryservices available to session user.
@@ -143,28 +105,11 @@ func (to *Session) GetDeliveryServiceRequests() ([]tc.DeliveryServiceRequest, Re
 
 func (to *Session) GetDeliveryServiceRequestByXMLIDWithHdr(XMLID string, header http.Header) ([]tc.DeliveryServiceRequest, ReqInf, error) {
 	route := fmt.Sprintf("%s?xmlId=%s", API_DS_REQUESTS, url.QueryEscape(XMLID))
-	resp, remoteAddr, err := to.request(http.MethodGet, route, nil, header)
-
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.DeliveryServiceRequest{}, reqInf, nil
-		}
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	data := struct {
 		Response []tc.DeliveryServiceRequest `json:"response"`
 	}{}
-	if err = json.NewDecoder(resp.Body).Decode(&data); err != nil {
-		return nil, reqInf, err
-	}
-
-	return data.Response, reqInf, nil
+	reqInf, err := to.get(route, header, &data)
+	return data.Response, reqInf, err
 }
 
 // GET a DeliveryServiceRequest by the DeliveryServiceRequest XMLID
@@ -175,27 +120,11 @@ func (to *Session) GetDeliveryServiceRequestByXMLID(XMLID string) ([]tc.Delivery
 
 func (to *Session) GetDeliveryServiceRequestByIDWithHdr(id int, header http.Header) ([]tc.DeliveryServiceRequest, ReqInf, error) {
 	route := fmt.Sprintf("%s?id=%d", API_DS_REQUESTS, id)
-	resp, remoteAddr, err := to.request(http.MethodGet, route, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.DeliveryServiceRequest{}, reqInf, nil
-		}
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	data := struct {
 		Response []tc.DeliveryServiceRequest `json:"response"`
 	}{}
-	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
-		return nil, reqInf, err
-	}
-
-	return data.Response, reqInf, nil
+	reqInf, err := to.get(route, header, &data)
+	return data.Response, reqInf, err
 }
 
 // GET a DeliveryServiceRequest by the DeliveryServiceRequest id
@@ -206,24 +135,9 @@ func (to *Session) GetDeliveryServiceRequestByID(id int) ([]tc.DeliveryServiceRe
 
 func (to *Session) UpdateDeliveryServiceRequestByIDWithHdr(id int, dsr tc.DeliveryServiceRequest, header http.Header) (tc.Alerts, ReqInf, error) {
 	route := fmt.Sprintf("%s?id=%d", API_DS_REQUESTS, id)
-
-	var remoteAddr net.Addr
-	reqBody, err := json.Marshal(dsr)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	resp, remoteAddr, err := to.request(http.MethodPut, route, reqBody, header)
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-	}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
 	var alerts tc.Alerts
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
-	return alerts, reqInf, nil
+	reqInf, err := to.put(route, dsr, header, &alerts)
+	return alerts, reqInf, err
 }
 
 // Update a DeliveryServiceRequest by ID
@@ -235,49 +149,7 @@ func (to *Session) UpdateDeliveryServiceRequestByID(id int, dsr tc.DeliveryServi
 // DELETE a DeliveryServiceRequest by DeliveryServiceRequest assignee
 func (to *Session) DeleteDeliveryServiceRequestByID(id int) (tc.Alerts, ReqInf, error) {
 	route := fmt.Sprintf("%s?id=%d", API_DS_REQUESTS, id)
-	resp, remoteAddr, err := to.RawRequest(http.MethodDelete, route, nil)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
 	var alerts tc.Alerts
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
-	return alerts, reqInf, nil
-}
-
-/*
-
-// Returns a list of DeliveryServiceRequests
-func (to *Session) GetDeliveryServiceRequests() ([]tc.DeliveryServiceRequest, ReqInf, error) {
-	resp, remoteAddr, err := to.request(http.MethodGet, API_DS_REQUESTS, nil)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
-	var data tc.DeliveryServiceRequestsResponse
-	err = json.NewDecoder(resp.Body).Decode(&data)
-	return data.Response, reqInf, nil
-}
-
-// GET a DeliveryServiceRequest by the DeliveryServiceRequest assignee
-func (to *Session) GetDeliveryServiceRequestByAssignee(assignee string) ([]tc.DeliveryServiceRequest, ReqInf, error) {
-	url := fmt.Sprintf("%s/assignee/%s", API_DS_REQUESTS, assignee)
-	resp, remoteAddr, err := to.request(http.MethodGet, url, nil)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
-	var data tc.DeliveryServiceRequestsResponse
-	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
-		return nil, reqInf, err
-	}
-
-	return data.Response, reqInf, nil
+	reqInf, err := to.del(route, nil, &alerts)
+	return alerts, reqInf, err
 }
-
-*/
diff --git a/traffic_ops/v3-client/deliveryservices_required_capabilities.go b/traffic_ops/v3-client/deliveryservices_required_capabilities.go
index a75b7f3..792e2bd 100644
--- a/traffic_ops/v3-client/deliveryservices_required_capabilities.go
+++ b/traffic_ops/v3-client/deliveryservices_required_capabilities.go
@@ -16,9 +16,7 @@
 package client
 
 import (
-	"encoding/json"
 	"fmt"
-	"net"
 	"net/http"
 	"net/url"
 	"strconv"
@@ -33,13 +31,7 @@ const (
 // CreateDeliveryServicesRequiredCapability assigns a Required Capability to a Delivery Service
 func (to *Session) CreateDeliveryServicesRequiredCapability(capability tc.DeliveryServicesRequiredCapability) (tc.Alerts, ReqInf, error) {
 	var alerts tc.Alerts
-	var remoteAddr net.Addr
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	reqBody, err := json.Marshal(capability)
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	reqInf, err = post(to, API_DELIVERY_SERVICES_REQUIRED_CAPABILITIES, reqBody, &alerts)
+	reqInf, err := to.post(API_DELIVERY_SERVICES_REQUIRED_CAPABILITIES, capability, nil, &alerts)
 	return alerts, reqInf, err
 }
 
@@ -49,8 +41,8 @@ func (to *Session) DeleteDeliveryServicesRequiredCapability(deliveryserviceID in
 	param := url.Values{}
 	param.Add("deliveryServiceID", strconv.Itoa(deliveryserviceID))
 	param.Add("requiredCapability", capability)
-	url := fmt.Sprintf("%s?%s", API_DELIVERY_SERVICES_REQUIRED_CAPABILITIES, param.Encode())
-	reqInf, err := del(to, url, &alerts)
+	route := fmt.Sprintf("%s?%s", API_DELIVERY_SERVICES_REQUIRED_CAPABILITIES, param.Encode())
+	reqInf, err := to.del(route, nil, &alerts)
 	return alerts, reqInf, err
 }
 
@@ -66,19 +58,16 @@ func (to *Session) GetDeliveryServicesRequiredCapabilitiesWithHdr(deliveryServic
 		param.Add("requiredCapability", *capability)
 	}
 
-	url := API_DELIVERY_SERVICES_REQUIRED_CAPABILITIES
+	route := API_DELIVERY_SERVICES_REQUIRED_CAPABILITIES
 	if len(param) > 0 {
-		url = fmt.Sprintf("%s?%s", url, param.Encode())
+		route = fmt.Sprintf("%s?%s", route, param.Encode())
 	}
 
 	resp := struct {
 		Response []tc.DeliveryServicesRequiredCapability `json:"response"`
 	}{}
-	reqInf, err := get(to, url, &resp, header)
-	if err != nil {
-		return nil, reqInf, err
-	}
-	return resp.Response, reqInf, nil
+	reqInf, err := to.get(route, header, &resp)
+	return resp.Response, reqInf, err
 }
 
 // GetDeliveryServicesRequiredCapabilities retrieves a list of Required Capabilities that are assigned to a Delivery Service
diff --git a/traffic_ops/v3-client/deliveryserviceserver.go b/traffic_ops/v3-client/deliveryserviceserver.go
index bcc753f..9f13e95 100644
--- a/traffic_ops/v3-client/deliveryserviceserver.go
+++ b/traffic_ops/v3-client/deliveryserviceserver.go
@@ -16,35 +16,28 @@
 package client
 
 import (
-	"encoding/json"
-	"errors"
 	"fmt"
 	"net/http"
 	"net/url"
 	"strconv"
 	"strings"
 
-	"github.com/apache/trafficcontrol/lib/go-log"
 	"github.com/apache/trafficcontrol/lib/go-tc"
 	"github.com/apache/trafficcontrol/lib/go-util"
 )
 
 // CreateDeliveryServiceServers associates the given servers with the given delivery services. If replace is true, it deletes any existing associations for the given delivery service.
 func (to *Session) CreateDeliveryServiceServers(dsID int, serverIDs []int, replace bool) (*tc.DSServerIDs, ReqInf, error) {
-	path := apiBase + `/deliveryserviceserver`
+	path := API_DELIVERY_SERVICE_SERVER
 	req := tc.DSServerIDs{
 		DeliveryServiceID: util.IntPtr(dsID),
 		ServerIDs:         serverIDs,
 		Replace:           util.BoolPtr(replace),
 	}
-	jsonReq, err := json.Marshal(&req)
-	if err != nil {
-		return nil, ReqInf{}, err
-	}
 	resp := struct {
 		Response tc.DSServerIDs `json:"response"`
 	}{}
-	reqInf, err := post(to, path, jsonReq, &resp)
+	reqInf, err := to.post(path, req, nil, &resp)
 	if err != nil {
 		return nil, reqInf, err
 	}
@@ -53,38 +46,32 @@ func (to *Session) CreateDeliveryServiceServers(dsID int, serverIDs []int, repla
 
 func (to *Session) DeleteDeliveryServiceServer(dsID int, serverID int) (tc.Alerts, ReqInf, error) {
 	route := apiBase + `/deliveryserviceserver/` + strconv.Itoa(dsID) + "/" + strconv.Itoa(serverID)
-	reqResp, remoteAddr, err := to.request(http.MethodDelete, route, nil, nil)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, errors.New("requesting from Traffic Ops: " + err.Error())
-	}
-	defer reqResp.Body.Close()
 	resp := tc.Alerts{}
-	if err = json.NewDecoder(reqResp.Body).Decode(&resp); err != nil {
-		return tc.Alerts{}, reqInf, errors.New("decoding response: " + err.Error())
-	}
-	return resp, reqInf, nil
+	reqInf, err := to.del(route, nil, &resp)
+	return resp, reqInf, err
 }
 
 // AssignServersToDeliveryService assigns the given list of servers to the delivery service with the given xmlId.
 func (to *Session) AssignServersToDeliveryService(servers []string, xmlId string) (tc.Alerts, ReqInf, error) {
-	route := fmt.Sprintf(API_DELIVERY_SERVICES_SERVERS, xmlId)
+	route := fmt.Sprintf(API_DELIVERY_SERVICES_SERVERS, url.QueryEscape(xmlId))
 	dss := tc.DeliveryServiceServers{ServerNames: servers, XmlId: xmlId}
-	reqBody, err := json.Marshal(&dss)
-	reqResp, remoteAddr, err := to.request(http.MethodPost, route, reqBody, nil)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if reqResp != nil {
-		reqInf.StatusCode = reqResp.StatusCode
-	}
-	if err != nil {
-		return tc.Alerts{}, reqInf, errors.New("requesting from Traffic Ops: " + err.Error())
-	}
-	defer log.Close(reqResp.Body, "unable to close response body")
 	resp := tc.Alerts{}
-	if err = json.NewDecoder(reqResp.Body).Decode(&resp); err != nil {
-		return tc.Alerts{}, reqInf, errors.New("decoding response: " + err.Error())
-	}
-	return resp, reqInf, nil
+	reqInf, err := to.post(route, dss, nil, &resp)
+	return resp, reqInf, err
+}
+
+// GetDeliveryServiceServer returns associations between Delivery Services and servers using the
+// provided pagination controls.
+// Deprecated: GetDeliveryServiceServer will be removed in 6.0. Use GetDeliveryServiceServerWithHdr.
+func (to *Session) GetDeliveryServiceServer(page, limit string) ([]tc.DeliveryServiceServer, ReqInf, error) {
+	return to.GetDeliveryServiceServerWithHdr(page, limit, nil)
+}
+
+func (to *Session) GetDeliveryServiceServerWithHdr(page, limit string, header http.Header) ([]tc.DeliveryServiceServer, ReqInf, error) {
+	var data tc.DeliveryServiceServerResponse
+	// TODO: page and limit should be integers not strings
+	reqInf, err := to.get(API_DELIVERY_SERVICE_SERVER+"?page="+url.QueryEscape(page)+"&limit="+url.QueryEscape(limit), header, &data)
+	return data.Response, reqInf, err
 }
 
 func (to *Session) GetDeliveryServiceServersWithHdr(h http.Header) (tc.DeliveryServiceServerResponse, ReqInf, error) {
@@ -140,22 +127,11 @@ func (to *Session) GetDeliveryServiceServersWithLimits(limit int, deliveryServic
 }
 
 func (to *Session) getDeliveryServiceServers(urlQuery url.Values, h http.Header) (tc.DeliveryServiceServerResponse, ReqInf, error) {
-	route := apiBase + `/deliveryserviceserver`
+	route := API_DELIVERY_SERVICE_SERVER
 	if qry := urlQuery.Encode(); qry != "" {
 		route += `?` + qry
 	}
-	reqResp, remoteAddr, err := to.request(http.MethodGet, route, nil, h)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if reqResp != nil {
-		reqInf.StatusCode = reqResp.StatusCode
-	}
-	if err != nil {
-		return tc.DeliveryServiceServerResponse{}, reqInf, errors.New("requesting from Traffic Ops: " + err.Error())
-	}
-	defer reqResp.Body.Close()
 	resp := tc.DeliveryServiceServerResponse{}
-	if err = json.NewDecoder(reqResp.Body).Decode(&resp); err != nil {
-		return tc.DeliveryServiceServerResponse{}, reqInf, errors.New("decoding response: " + err.Error())
-	}
-	return resp, reqInf, nil
+	reqInf, err := to.get(route, h, &resp)
+	return resp, reqInf, err
 }
diff --git a/traffic_ops/v3-client/division.go b/traffic_ops/v3-client/division.go
index 942f1b3..aadda2a 100644
--- a/traffic_ops/v3-client/division.go
+++ b/traffic_ops/v3-client/division.go
@@ -16,10 +16,9 @@
 package client
 
 import (
-	"encoding/json"
 	"fmt"
-	"net"
 	"net/http"
+	"net/url"
 
 	"github.com/apache/trafficcontrol/lib/go-tc"
 )
@@ -30,43 +29,16 @@ const (
 
 // Create a Division
 func (to *Session) CreateDivision(division tc.Division) (tc.Alerts, ReqInf, error) {
-
-	var remoteAddr net.Addr
-	reqBody, err := json.Marshal(division)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	resp, remoteAddr, err := to.request(http.MethodPost, API_DIVISIONS, reqBody, nil)
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
 	var alerts tc.Alerts
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
-	return alerts, reqInf, nil
+	reqInf, err := to.post(API_DIVISIONS, division, nil, &alerts)
+	return alerts, reqInf, err
 }
 
 func (to *Session) UpdateDivisionByIDWithHdr(id int, division tc.Division, header http.Header) (tc.Alerts, ReqInf, error) {
-
-	var remoteAddr net.Addr
-	reqBody, err := json.Marshal(division)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
 	route := fmt.Sprintf("%s/%d", API_DIVISIONS, id)
-	resp, remoteAddr, err := to.request(http.MethodPut, route, reqBody, header)
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-	}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
 	var alerts tc.Alerts
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
-	return alerts, reqInf, nil
+	reqInf, err := to.put(route, division, header, &alerts)
+	return alerts, reqInf, err
 }
 
 // Update a Division by ID
@@ -76,22 +48,9 @@ func (to *Session) UpdateDivisionByID(id int, division tc.Division) (tc.Alerts,
 }
 
 func (to *Session) GetDivisionsWithHdr(header http.Header) ([]tc.Division, ReqInf, error) {
-	resp, remoteAddr, err := to.request(http.MethodGet, API_DIVISIONS, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.Division{}, reqInf, nil
-		}
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	var data tc.DivisionsResponse
-	err = json.NewDecoder(resp.Body).Decode(&data)
-	return data.Response, reqInf, nil
+	reqInf, err := to.get(API_DIVISIONS, header, &data)
+	return data.Response, reqInf, err
 }
 
 // Returns a list of Divisions
@@ -102,25 +61,9 @@ func (to *Session) GetDivisions() ([]tc.Division, ReqInf, error) {
 
 func (to *Session) GetDivisionByIDWithHdr(id int, header http.Header) ([]tc.Division, ReqInf, error) {
 	route := fmt.Sprintf("%s?id=%d", API_DIVISIONS, id)
-	resp, remoteAddr, err := to.request(http.MethodGet, route, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.Division{}, reqInf, nil
-		}
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	var data tc.DivisionsResponse
-	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
-		return nil, reqInf, err
-	}
-
-	return data.Response, reqInf, nil
+	reqInf, err := to.get(route, header, &data)
+	return data.Response, reqInf, err
 }
 
 // GET a Division by the Division id
@@ -130,26 +73,10 @@ func (to *Session) GetDivisionByID(id int) ([]tc.Division, ReqInf, error) {
 }
 
 func (to *Session) GetDivisionByNameWithHdr(name string, header http.Header) ([]tc.Division, ReqInf, error) {
-	url := fmt.Sprintf("%s?name=%s", API_DIVISIONS, name)
-	resp, remoteAddr, err := to.request(http.MethodGet, url, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.Division{}, reqInf, nil
-		}
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
+	route := fmt.Sprintf("%s?name=%s", API_DIVISIONS, url.QueryEscape(name))
 	var data tc.DivisionsResponse
-	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
-		return nil, reqInf, err
-	}
-
-	return data.Response, reqInf, nil
+	reqInf, err := to.get(route, header, &data)
+	return data.Response, reqInf, err
 }
 
 // GET a Division by the Division name
@@ -161,13 +88,7 @@ func (to *Session) GetDivisionByName(name string) ([]tc.Division, ReqInf, error)
 // DELETE a Division by Division id
 func (to *Session) DeleteDivisionByID(id int) (tc.Alerts, ReqInf, error) {
 	route := fmt.Sprintf("%s/%d", API_DIVISIONS, id)
-	resp, remoteAddr, err := to.request(http.MethodDelete, route, nil, nil)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
 	var alerts tc.Alerts
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
-	return alerts, reqInf, nil
+	reqInf, err := to.del(route, nil, &alerts)
+	return alerts, reqInf, err
 }
diff --git a/traffic_ops/v3-client/dsuser.go b/traffic_ops/v3-client/dsuser.go
index 587af06..e8ca524 100644
--- a/traffic_ops/v3-client/dsuser.go
+++ b/traffic_ops/v3-client/dsuser.go
@@ -16,7 +16,6 @@ package client
 */
 
 import (
-	"encoding/json"
 	"strconv"
 
 	tc "github.com/apache/trafficcontrol/lib/go-tc"
@@ -26,12 +25,8 @@ import (
 func (to *Session) SetDeliveryServiceUser(userID int, dses []int, replace bool) (*tc.UserDeliveryServicePostResponse, error) {
 	uri := apiBase + `/deliveryservice_user`
 	ds := tc.DeliveryServiceUserPost{UserID: &userID, DeliveryServices: &dses, Replace: &replace}
-	jsonReq, err := json.Marshal(ds)
-	if err != nil {
-		return nil, err
-	}
 	resp := tc.UserDeliveryServicePostResponse{}
-	_, err = post(to, uri, jsonReq, &resp)
+	_, err := to.post(uri, ds, nil, &resp)
 	if err != nil {
 		return nil, err
 	}
@@ -42,7 +37,7 @@ func (to *Session) SetDeliveryServiceUser(userID int, dses []int, replace bool)
 func (to *Session) DeleteDeliveryServiceUser(userID int, dsID int) (*tc.UserDeliveryServiceDeleteResponse, error) {
 	uri := apiBase + `/deliveryservice_user/` + strconv.Itoa(dsID) + `/` + strconv.Itoa(userID)
 	resp := tc.UserDeliveryServiceDeleteResponse{}
-	if _, err := del(to, uri, &resp); err != nil {
+	if _, err := to.del(uri, nil, &resp); err != nil {
 		return nil, err
 	}
 	return &resp, nil
diff --git a/traffic_ops/v3-client/federation.go b/traffic_ops/v3-client/federation.go
index ab42a1a..e16d375 100644
--- a/traffic_ops/v3-client/federation.go
+++ b/traffic_ops/v3-client/federation.go
@@ -20,17 +20,20 @@ import (
 	"errors"
 	"fmt"
 	"net/http"
+	"net/url"
 	"strconv"
 
 	"github.com/apache/trafficcontrol/lib/go-tc"
 )
 
+const APIFederations = apiBase + "/federations"
+
 func (to *Session) FederationsWithHdr(header http.Header) ([]tc.AllDeliveryServiceFederationsMapping, ReqInf, error) {
 	type FederationResponse struct {
 		Response []tc.AllDeliveryServiceFederationsMapping `json:"response"`
 	}
 	data := FederationResponse{}
-	inf, err := get(to, apiBase+"/federations", &data, header)
+	inf, err := to.get(APIFederations, header, &data)
 	return data.Response, inf, err
 }
 
@@ -44,7 +47,7 @@ func (to *Session) AllFederationsWithHdr(header http.Header) ([]tc.AllDeliverySe
 		Response []tc.AllDeliveryServiceFederationsMapping `json:"response"`
 	}
 	data := FederationResponse{}
-	inf, err := get(to, apiBase+"/federations/all", &data, header)
+	inf, err := to.get(apiBase+"/federations/all", header, &data)
 	return data.Response, inf, err
 }
 
@@ -59,7 +62,7 @@ func (to *Session) AllFederationsForCDNWithHdr(cdnName string, header http.Heade
 		Response []json.RawMessage `json:"response"`
 	}
 	data := FederationResponse{}
-	inf, err := get(to, apiBase+"/federations/all?cdnName="+cdnName, &data, header)
+	inf, err := to.get(apiBase+"/federations/all?cdnName="+url.QueryEscape(cdnName), header, &data)
 	if err != nil {
 		return nil, inf, err
 	}
@@ -86,12 +89,8 @@ func (to *Session) AllFederationsForCDN(cdnName string) ([]tc.AllDeliveryService
 
 func (to *Session) CreateFederationDeliveryServices(federationID int, deliveryServiceIDs []int, replace bool) (ReqInf, error) {
 	req := tc.FederationDSPost{DSIDs: deliveryServiceIDs, Replace: &replace}
-	jsonReq, err := json.Marshal(req)
-	if err != nil {
-		return ReqInf{CacheHitStatus: CacheHitStatusMiss}, err
-	}
 	resp := map[string]interface{}{}
-	inf, err := makeReq(to, http.MethodPost, apiBase+`/federations/`+strconv.Itoa(federationID)+`/deliveryservices`, jsonReq, &resp, nil)
+	inf, err := to.post(apiBase+`/federations/`+strconv.Itoa(federationID)+`/deliveryservices`, req, nil, &resp)
 	return inf, err
 }
 
@@ -100,7 +99,7 @@ func (to *Session) GetFederationDeliveryServicesWithHdr(federationID int, header
 		Response []tc.FederationDeliveryServiceNullable `json:"response"`
 	}
 	data := FederationDSesResponse{}
-	inf, err := get(to, fmt.Sprintf("%s/federations/%v/deliveryservices", apiBase, federationID), &data, header)
+	inf, err := to.get(fmt.Sprintf("%s/federations/%d/deliveryservices", apiBase, federationID), header, &data)
 	return data.Response, inf, err
 }
 
@@ -112,29 +111,17 @@ func (to *Session) GetFederationDeliveryServices(federationID int) ([]tc.Federat
 
 // DeleteFederationDeliveryService Deletes a given Delivery Service from a Federation
 func (to *Session) DeleteFederationDeliveryService(federationID, deliveryServiceID int) (tc.Alerts, ReqInf, error) {
-	route := fmt.Sprintf("%s/federations/%v/deliveryservices/%v", apiBase, federationID, deliveryServiceID)
-	resp, remoteAddr, err := to.request(http.MethodDelete, route, nil, nil)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
+	route := fmt.Sprintf("%s/federations/%d/deliveryservices/%d", apiBase, federationID, deliveryServiceID)
 	var alerts tc.Alerts
-	if err = json.NewDecoder(resp.Body).Decode(&alerts); err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	return alerts, reqInf, nil
+	reqInf, err := to.del(route, nil, &alerts)
+	return alerts, reqInf, err
 }
 
 // GetFederationUsers Associates the given Users' IDs to a Federation
 func (to *Session) CreateFederationUsers(federationID int, userIDs []int, replace bool) (tc.Alerts, ReqInf, error) {
 	req := tc.FederationUserPost{IDs: userIDs, Replace: &replace}
-	jsonReq, err := json.Marshal(req)
-	if err != nil {
-		return tc.Alerts{}, ReqInf{CacheHitStatus: CacheHitStatusMiss}, err
-	}
 	var alerts tc.Alerts
-	inf, err := makeReq(to, http.MethodPost, fmt.Sprintf("%s/federations/%v/users", apiBase, federationID), jsonReq, &alerts, nil)
+	inf, err := to.post(fmt.Sprintf("%s/federations/%d/users", apiBase, federationID), req, nil, &alerts)
 	return alerts, inf, err
 }
 
@@ -143,7 +130,7 @@ func (to *Session) GetFederationUsersWithHdr(federationID int, header http.Heade
 		Response []tc.FederationUser `json:"response"`
 	}
 	data := FederationUsersResponse{}
-	inf, err := get(to, fmt.Sprintf("%s/federations/%v/users", apiBase, federationID), &data, header)
+	inf, err := to.get(fmt.Sprintf("%s/federations/%d/users", apiBase, federationID), header, &data)
 	return data.Response, inf, err
 }
 
@@ -155,39 +142,17 @@ func (to *Session) GetFederationUsers(federationID int) ([]tc.FederationUser, Re
 
 // DeleteFederationUser Deletes a given User from a Federation
 func (to *Session) DeleteFederationUser(federationID, userID int) (tc.Alerts, ReqInf, error) {
-	route := fmt.Sprintf("%s/federations/%v/users/%v", apiBase, federationID, userID)
-	resp, remoteAddr, err := to.request(http.MethodDelete, route, nil, nil)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
+	route := fmt.Sprintf("%s/federations/%d/users/%d", apiBase, federationID, userID)
 	var alerts tc.Alerts
-	if err = json.NewDecoder(resp.Body).Decode(&alerts); err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	return alerts, reqInf, nil
+	reqInf, err := to.del(route, nil, &alerts)
+	return alerts, reqInf, err
 }
 
 // AddFederationResolverMappingsForCurrentUser adds Federation Resolver mappings to one or more
 // Delivery Services for the current user.
 func (to *Session) AddFederationResolverMappingsForCurrentUser(mappings tc.DeliveryServiceFederationResolverMappingRequest) (tc.Alerts, ReqInf, error) {
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss}
 	var alerts tc.Alerts
-
-	bts, err := json.Marshal(mappings)
-	if err != nil {
-		return alerts, reqInf, err
-	}
-
-	resp, remoteAddr, err := to.request(http.MethodPost, apiBase+"/federations", bts, nil)
-	reqInf.RemoteAddr = remoteAddr
-	if err != nil {
-		return alerts, reqInf, err
-	}
-	defer resp.Body.Close()
-
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
+	reqInf, err := to.post(APIFederations, mappings, nil, &alerts)
 	return alerts, reqInf, err
 }
 
@@ -195,17 +160,8 @@ func (to *Session) AddFederationResolverMappingsForCurrentUser(mappings tc.Deliv
 // Federations assigned to the currently authenticated user, as well as deleting ALL of the
 // Federation Resolvers themselves.
 func (to *Session) DeleteFederationResolverMappingsForCurrentUser() (tc.Alerts, ReqInf, error) {
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss}
 	var alerts tc.Alerts
-
-	resp, remoteAddr, err := to.request(http.MethodDelete, apiBase+"/federations", nil, nil)
-	reqInf.RemoteAddr = remoteAddr
-	if err != nil {
-		return alerts, reqInf, err
-	}
-	defer resp.Body.Close()
-
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
+	reqInf, err := to.del(APIFederations, nil, &alerts)
 	return alerts, reqInf, err
 }
 
@@ -216,21 +172,7 @@ func (to *Session) DeleteFederationResolverMappingsForCurrentUser() (tc.Alerts,
 // equivalent to a call to DeleteFederationResolverMappingsForCurrentUser followed by a call to
 // AddFederationResolverMappingsForCurrentUser .
 func (to *Session) ReplaceFederationResolverMappingsForCurrentUser(mappings tc.DeliveryServiceFederationResolverMappingRequest) (tc.Alerts, ReqInf, error) {
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss}
 	var alerts tc.Alerts
-
-	bts, err := json.Marshal(mappings)
-	if err != nil {
-		return alerts, reqInf, err
-	}
-
-	resp, remoteAddr, err := to.request(http.MethodPut, apiBase+"/federations", bts, nil)
-	reqInf.RemoteAddr = remoteAddr
-	if err != nil {
-		return alerts, reqInf, err
-	}
-	defer resp.Body.Close()
-
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
+	reqInf, err := to.put(APIFederations, mappings, nil, &alerts)
 	return alerts, reqInf, err
 }
diff --git a/traffic_ops/v3-client/federation_federation_resolver.go b/traffic_ops/v3-client/federation_federation_resolver.go
index cfcedb1..198c778 100644
--- a/traffic_ops/v3-client/federation_federation_resolver.go
+++ b/traffic_ops/v3-client/federation_federation_resolver.go
@@ -14,57 +14,27 @@ package client
    limitations under the License.
 */
 import (
-	"encoding/json"
 	"fmt"
-	"net/http"
 
 	"github.com/apache/trafficcontrol/lib/go-tc"
 )
 
 // GetFederationFederationResolversByID retrieves all Federation Resolvers belonging to Federation of ID.
 func (to *Session) GetFederationFederationResolversByID(id int) (tc.FederationFederationResolversResponse, ReqInf, error) {
-	var (
-		path   = fmt.Sprintf("%s/federations/%d/federation_resolvers", apiBase, id)
-		reqInf = ReqInf{CacheHitStatus: CacheHitStatusMiss}
-		resp   tc.FederationFederationResolversResponse
-	)
-	httpResp, remoteAddr, err := to.request(http.MethodGet, path, nil, nil)
-	reqInf.RemoteAddr = remoteAddr
-	if err != nil {
-		return resp, reqInf, err
-	}
-	defer httpResp.Body.Close()
-
-	err = json.NewDecoder(httpResp.Body).Decode(&resp)
-
+	path := fmt.Sprintf("%s/federations/%d/federation_resolvers", apiBase, id)
+	resp := tc.FederationFederationResolversResponse{}
+	reqInf, err := to.get(path, nil, &resp)
 	return resp, reqInf, err
 }
 
 // AssignFederationFederationResolver creates the Federation Resolver 'fr'.
 func (to *Session) AssignFederationFederationResolver(fedID int, resolverIDs []int, replace bool) (tc.AssignFederationFederationResolversResponse, ReqInf, error) {
-	var (
-		path = fmt.Sprintf("%s/federations/%d/federation_resolvers", apiBase, fedID)
-		req  = tc.AssignFederationResolversRequest{
-			Replace:        replace,
-			FedResolverIDs: resolverIDs,
-		}
-		reqInf = ReqInf{CacheHitStatus: CacheHitStatusMiss}
-		resp   tc.AssignFederationFederationResolversResponse
-	)
-
-	reqBody, err := json.Marshal(req)
-	if err != nil {
-		return resp, reqInf, err
+	path := fmt.Sprintf("%s/federations/%d/federation_resolvers", apiBase, fedID)
+	req := tc.AssignFederationResolversRequest{
+		Replace:        replace,
+		FedResolverIDs: resolverIDs,
 	}
-
-	httpResp, remoteAddr, err := to.request(http.MethodPost, path, reqBody, nil)
-	reqInf.RemoteAddr = remoteAddr
-	if err != nil {
-		return resp, reqInf, err
-	}
-	defer httpResp.Body.Close()
-
-	err = json.NewDecoder(httpResp.Body).Decode(&resp)
-
+	resp := tc.AssignFederationFederationResolversResponse{}
+	reqInf, err := to.post(path, req, nil, &resp)
 	return resp, reqInf, err
 }
diff --git a/traffic_ops/v3-client/federation_resolver.go b/traffic_ops/v3-client/federation_resolver.go
index 9a9def8..db4bc5c 100644
--- a/traffic_ops/v3-client/federation_resolver.go
+++ b/traffic_ops/v3-client/federation_resolver.go
@@ -13,7 +13,7 @@ package client
    See the License for the specific language governing permissions and
    limitations under the License.
 */
-import "encoding/json"
+
 import "fmt"
 import "net/http"
 import "net/url"
@@ -41,7 +41,7 @@ func (to *Session) getFederationResolvers(id *uint, ip *string, t *string, heade
 	var data struct {
 		Response []tc.FederationResolver `json:"response"`
 	}
-	inf, err := get(to, path, &data, header)
+	inf, err := to.get(path, header, &data)
 	return data.Response, inf, err
 }
 
@@ -98,39 +98,15 @@ func (to *Session) GetFederationResolversByType(t string) ([]tc.FederationResolv
 
 // CreateFederationResolver creates the Federation Resolver 'fr'.
 func (to *Session) CreateFederationResolver(fr tc.FederationResolver) (tc.Alerts, ReqInf, error) {
-	var reqInf = ReqInf{CacheHitStatus: CacheHitStatusMiss}
 	var alerts tc.Alerts
-
-	req, err := json.Marshal(fr)
-	if err != nil {
-		return alerts, reqInf, err
-	}
-
-	var resp *http.Response
-	resp, reqInf.RemoteAddr, err = to.request(http.MethodPost, apiBase+"/federation_resolvers", req, nil)
-	if err != nil {
-		return alerts, reqInf, err
-	}
-	defer resp.Body.Close()
-
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
+	reqInf, err := to.post(apiBase+"/federation_resolvers", fr, nil, &alerts)
 	return alerts, reqInf, err
 }
 
 // DeleteFederationResolver deletes the Federation Resolver identified by 'id'.
 func (to *Session) DeleteFederationResolver(id uint) (tc.Alerts, ReqInf, error) {
-	var reqInf = ReqInf{CacheHitStatus: CacheHitStatusMiss}
 	var alerts tc.Alerts
-
-	var path = fmt.Sprintf("%s/federation_resolvers?id=%d", apiBase, id)
-	var resp *http.Response
-	var err error
-	resp, reqInf.RemoteAddr, err = to.request(http.MethodDelete, path, nil, nil)
-	if err != nil {
-		return alerts, reqInf, err
-	}
-	defer resp.Body.Close()
-
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
+	path := fmt.Sprintf("%s/federation_resolvers?id=%d", apiBase, id)
+	reqInf, err := to.del(path, nil, &alerts)
 	return alerts, reqInf, err
 }
diff --git a/traffic_ops/v3-client/iso.go b/traffic_ops/v3-client/iso.go
index edf4bb0..d10a8c8 100644
--- a/traffic_ops/v3-client/iso.go
+++ b/traffic_ops/v3-client/iso.go
@@ -20,9 +20,6 @@ package client
  */
 
 import (
-	"encoding/json"
-	"net/http"
-
 	"github.com/apache/trafficcontrol/lib/go-tc"
 )
 
@@ -36,19 +33,9 @@ const (
 //  key:   Name of OS
 //  value: Directory where the ISO source can be found
 func (to *Session) GetOSVersions() (map[string]string, ReqInf, error) {
-	resp, remoteAddr, err := to.request(http.MethodGet, API_OSVERSIONS, nil, nil)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	var data struct {
 		Versions tc.OSVersionsResponse `json:"response"`
 	}
-	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
-		return nil, reqInf, err
-	}
-
-	return data.Versions, reqInf, nil
+	reqInf, err := to.get(API_OSVERSIONS, nil, &data)
+	return data.Versions, reqInf, err
 }
diff --git a/traffic_ops/v3-client/job.go b/traffic_ops/v3-client/job.go
index c97202e..9076a84 100644
--- a/traffic_ops/v3-client/job.go
+++ b/traffic_ops/v3-client/job.go
@@ -16,11 +16,9 @@
 package client
 
 import (
-	"encoding/json"
 	"errors"
 	"fmt"
-	"net"
-	"net/http"
+	"net/url"
 	"strconv"
 
 	"github.com/apache/trafficcontrol/lib/go-tc"
@@ -28,64 +26,23 @@ import (
 
 // Creates a new Content Invalidation Job
 func (to *Session) CreateInvalidationJob(job tc.InvalidationJobInput) (tc.Alerts, ReqInf, error) {
-	remoteAddr := (net.Addr)(nil)
-	reqBody, err := json.Marshal(job)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	resp, remoteAddr, err := to.request(http.MethodPost, apiBase+`/jobs`, reqBody, nil)
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-	}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
 	var alerts tc.Alerts
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
+	reqInf, err := to.post(apiBase+`/jobs`, job, nil, &alerts)
 	return alerts, reqInf, err
 }
 
 // Deletes a Content Invalidation Job
 func (to *Session) DeleteInvalidationJob(jobID uint64) (tc.Alerts, ReqInf, error) {
-	remoteAddr := (net.Addr)(nil)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	resp, remoteAddr, err := to.request(http.MethodDelete, fmt.Sprintf("%v/jobs?id=%v", apiBase, jobID), nil, nil)
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-	}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
 	var alerts tc.Alerts
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
+	reqInf, err := to.del(fmt.Sprintf("%s/jobs?id=%d", apiBase, jobID), nil, &alerts)
 	return alerts, reqInf, err
 
 }
 
 // Updates a Content Invalidation Job
 func (to *Session) UpdateInvalidationJob(job tc.InvalidationJob) (tc.Alerts, ReqInf, error) {
-	remoteAddr := (net.Addr)(nil)
-	reqBody, err := json.Marshal(job)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	if job.ID == nil {
-		return tc.Alerts{}, reqInf, errors.New("job id cannot be nil")
-	}
-	resp, remoteAddr, err := to.request(http.MethodPut, fmt.Sprintf(`%v/jobs?id=%v`, apiBase, *job.ID), reqBody, nil)
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-	}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
 	var alerts tc.Alerts
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
+	reqInf, err := to.put(fmt.Sprintf(`%s/jobs?id=%d`, apiBase, *job.ID), job, nil, &alerts)
 	return alerts, reqInf, err
 }
 
@@ -95,31 +52,18 @@ func (to *Session) UpdateInvalidationJob(job tc.InvalidationJob) (tc.Alerts, Req
 //
 // Deprecated, use GetInvalidationJobs instead
 func (to *Session) GetJobs(deliveryServiceID *int, userID *int) ([]tc.Job, ReqInf, error) {
-	path := apiBase + "/jobs"
-	if deliveryServiceID != nil || userID != nil {
-		path += "?"
-		if deliveryServiceID != nil {
-			path += "dsId=" + strconv.Itoa(*deliveryServiceID)
-			if userID != nil {
-				path += "&"
-			}
-		}
-		if userID != nil {
-			path += "userId=" + strconv.Itoa(*userID)
-		}
+	params := url.Values{}
+	if deliveryServiceID != nil {
+		params.Add("dsId", strconv.Itoa(*deliveryServiceID))
 	}
-
-	resp, remoteAddr, err := to.request(http.MethodGet, path, nil, nil)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return nil, reqInf, err
+	if userID != nil {
+		params.Add("userId", strconv.Itoa(*userID))
 	}
-	defer resp.Body.Close()
-
+	path := apiBase + "/jobs?" + params.Encode()
 	data := struct {
 		Response []tc.Job `json:"response"`
 	}{}
-	err = json.NewDecoder(resp.Body).Decode(&data)
+	reqInf, err := to.get(path, nil, &data)
 	return data.Response, reqInf, err
 }
 
@@ -139,81 +83,74 @@ func (to *Session) GetJobs(deliveryServiceID *int, userID *int) ([]tc.Job, ReqIn
 // be a string, in which case it should be the username of the desired user, or it may be an actual
 // tc.User or tc.UserCurrent structure.
 func (to *Session) GetInvalidationJobs(ds *interface{}, user *interface{}) ([]tc.InvalidationJob, ReqInf, error) {
-	path := apiBase + "/jobs"
-	if ds != nil || user != nil {
-		path += "?"
-
-		if ds != nil {
-			d := *ds
-			switch t := d.(type) {
-			case uint:
-				path += "dsId=" + strconv.FormatUint(uint64(d.(uint)), 10)
-			case float64:
-				path += "dsId=" + strconv.FormatInt(int64(d.(float64)), 10)
-			case int:
-				path += "dsId=" + strconv.FormatInt(int64(d.(int)), 10)
-			case string:
-				path += "deliveryService=" + d.(string)
-			case tc.DeliveryServiceNullable:
-				if d.(tc.DeliveryServiceNullable).XMLID != nil {
-					path += "deliveryService=" + *d.(tc.DeliveryServiceNullable).XMLID
-				} else if d.(tc.DeliveryServiceNullable).ID != nil {
-					path += "dsId=" + strconv.FormatInt(int64(*d.(tc.DeliveryServiceNullable).ID), 10)
-				} else {
-					return nil, ReqInf{}, errors.New("No non-nil identifier on passed Delivery Service!")
-				}
-			default:
-				return nil, ReqInf{}, fmt.Errorf("Invalid type for argument 'ds': %T*", t)
-			}
-
-			if user != nil {
-				path += "&"
+	const DSIDKey = "dsId"
+	const DSKey = "deliveryService"
+	const UserKey = "userId"
+	const CreatedKey = "createdBy"
+
+	params := url.Values{}
+	if ds != nil {
+		d := *ds
+		switch t := d.(type) {
+		case uint:
+			params.Add(DSIDKey, strconv.FormatUint(uint64(d.(uint)), 10))
+		case float64:
+			params.Add(DSIDKey, strconv.FormatInt(int64(d.(float64)), 10))
+		case int:
+			params.Add(DSIDKey, strconv.FormatInt(int64(d.(int)), 10))
+		case string:
+			params.Add(DSKey, d.(string))
+		case tc.DeliveryServiceNullable:
+			if d.(tc.DeliveryServiceNullable).XMLID != nil {
+				params.Add(DSKey, *d.(tc.DeliveryServiceNullable).XMLID)
+			} else if d.(tc.DeliveryServiceNullable).ID != nil {
+				params.Add(DSIDKey, strconv.FormatInt(int64(*d.(tc.DeliveryServiceNullable).ID), 10))
+			} else {
+				return nil, ReqInf{}, errors.New("no non-nil identifier on passed Delivery Service")
 			}
+		default:
+			return nil, ReqInf{}, fmt.Errorf("invalid type for argument 'ds': %T*", t)
 		}
-
-		if user != nil {
-			u := *user
-			switch t := u.(type) {
-			case uint:
-				path += "userId=" + strconv.FormatUint(uint64(u.(uint)), 10)
-			case float64:
-				path += "userId=" + strconv.FormatInt(int64(u.(float64)), 10)
-			case int:
-				path += "userId=" + strconv.FormatInt(int64(u.(int64)), 10)
-			case string:
-				path += "createdBy=" + u.(string)
-			case tc.User:
-				if u.(tc.User).Username != nil {
-					path += "createdBy=" + *u.(tc.User).Username
-				} else if u.(tc.User).ID != nil {
-					path += "userId=" + strconv.FormatInt(int64(*u.(tc.User).ID), 10)
-				} else {
-					return nil, ReqInf{}, errors.New("No non-nil identifier on passed User!")
-				}
-			case tc.UserCurrent:
-				if u.(tc.UserCurrent).UserName != nil {
-					path += "createdBy=" + *u.(tc.UserCurrent).UserName
-				} else if u.(tc.UserCurrent).ID != nil {
-					path += "userId=" + strconv.FormatInt(int64(*u.(tc.UserCurrent).ID), 10)
-				} else {
-					return nil, ReqInf{}, errors.New("No non-nil identifier on passed UserCurrent!")
-				}
-			default:
-				return nil, ReqInf{}, fmt.Errorf("Invalid type for argument 'user': %T*", t)
+	}
+	if user != nil {
+		u := *user
+		switch t := u.(type) {
+		case uint:
+			params.Add(UserKey, strconv.FormatUint(uint64(u.(uint)), 10))
+		case float64:
+			params.Add(UserKey, strconv.FormatInt(int64(u.(float64)), 10))
+		case int:
+			params.Add(UserKey, strconv.FormatInt(u.(int64), 10))
+		case string:
+			params.Add(CreatedKey, u.(string))
+		case tc.User:
+			if u.(tc.User).Username != nil {
+				params.Add(CreatedKey, *u.(tc.User).Username)
+			} else if u.(tc.User).ID != nil {
+				params.Add(UserKey, strconv.FormatInt(int64(*u.(tc.User).ID), 10))
+			} else {
+				return nil, ReqInf{}, errors.New("no non-nil identifier on passed User")
 			}
+		case tc.UserCurrent:
+			if u.(tc.UserCurrent).UserName != nil {
+				params.Add(CreatedKey, *u.(tc.UserCurrent).UserName)
+			} else if u.(tc.UserCurrent).ID != nil {
+				params.Add(UserKey, strconv.FormatInt(int64(*u.(tc.UserCurrent).ID), 10))
+			} else {
+				return nil, ReqInf{}, errors.New("no non-nil identifier on passed UserCurrent")
+			}
+		default:
+			return nil, ReqInf{}, fmt.Errorf("invalid type for argument 'user': %T*", t)
 		}
 	}
-
-	resp, remoteAddr, err := to.request(http.MethodGet, path, nil, nil)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return nil, reqInf, err
+	path := apiBase + "/jobs"
+	if len(params) > 0 {
+		path += "?" + params.Encode()
 	}
-	defer resp.Body.Close()
 
 	data := struct {
 		Response []tc.InvalidationJob `json:"response"`
 	}{}
-	err = json.NewDecoder(resp.Body).Decode(&data)
+	reqInf, err := to.get(path, nil, &data)
 	return data.Response, reqInf, err
 }
diff --git a/traffic_ops/v3-client/log.go b/traffic_ops/v3-client/log.go
index 50e35f8..3290cf3 100644
--- a/traffic_ops/v3-client/log.go
+++ b/traffic_ops/v3-client/log.go
@@ -16,9 +16,7 @@
 package client
 
 import (
-	"encoding/json"
 	"fmt"
-	"net/http"
 
 	"github.com/apache/trafficcontrol/lib/go-tc"
 )
@@ -30,19 +28,9 @@ const (
 // GetLogsByQueryParams gets a list of logs filtered by query params.
 func (to *Session) GetLogsByQueryParams(queryParams string) ([]tc.Log, ReqInf, error) {
 	URI := API_LOGS + queryParams
-	resp, remoteAddr, err := to.request(http.MethodGet, URI, nil, nil)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	var data tc.LogsResponse
-	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
-		return nil, reqInf, err
-	}
-
-	return data.Response, reqInf, nil
+	reqInf, err := to.get(URI, nil, &data)
+	return data.Response, reqInf, err
 }
 
 // GetLogs gets a list of logs.
diff --git a/traffic_ops/v3-client/origin.go b/traffic_ops/v3-client/origin.go
index abe5741..668c4aa 100644
--- a/traffic_ops/v3-client/origin.go
+++ b/traffic_ops/v3-client/origin.go
@@ -16,7 +16,6 @@
 package client
 
 import (
-	"encoding/json"
 	"errors"
 	"fmt"
 	"net"
@@ -32,7 +31,7 @@ const (
 
 func originIDs(to *Session, origin *tc.Origin) error {
 	if origin.CachegroupID == nil && origin.Cachegroup != nil {
-		p, _, err := to.GetCacheGroupNullableByName(*origin.Cachegroup)
+		p, _, err := to.GetCacheGroupNullableByNameWithHdr(*origin.Cachegroup, nil)
 		if err != nil {
 			return err
 		}
@@ -43,7 +42,7 @@ func originIDs(to *Session, origin *tc.Origin) error {
 	}
 
 	if origin.DeliveryServiceID == nil && origin.DeliveryService != nil {
-		dses, _, err := to.GetDeliveryServiceByXMLIDNullable(*origin.DeliveryService)
+		dses, _, err := to.GetDeliveryServiceByXMLIDNullableWithHdr(*origin.DeliveryService, nil)
 		if err != nil {
 			return err
 		}
@@ -54,7 +53,7 @@ func originIDs(to *Session, origin *tc.Origin) error {
 	}
 
 	if origin.ProfileID == nil && origin.Profile != nil {
-		profiles, _, err := to.GetProfileByName(*origin.Profile)
+		profiles, _, err := to.GetProfileByNameWithHdr(*origin.Profile, nil)
 		if err != nil {
 			return err
 		}
@@ -65,7 +64,7 @@ func originIDs(to *Session, origin *tc.Origin) error {
 	}
 
 	if origin.CoordinateID == nil && origin.Coordinate != nil {
-		coordinates, _, err := to.GetCoordinateByName(*origin.Coordinate)
+		coordinates, _, err := to.GetCoordinateByNameWithHdr(*origin.Coordinate, nil)
 		if err != nil {
 			return err
 		}
@@ -76,7 +75,7 @@ func originIDs(to *Session, origin *tc.Origin) error {
 	}
 
 	if origin.TenantID == nil && origin.Tenant != nil {
-		tenant, _, err := to.TenantByName(*origin.Tenant)
+		tenant, _, err := to.TenantByNameWithHdr(*origin.Tenant, nil)
 		if err != nil {
 			return err
 		}
@@ -95,21 +94,9 @@ func (to *Session) CreateOrigin(origin tc.Origin) (*tc.OriginDetailResponse, Req
 	if err != nil {
 		return nil, reqInf, err
 	}
-
-	reqBody, err := json.Marshal(origin)
-	if err != nil {
-		return nil, reqInf, err
-	}
-	resp, remoteAddr, err := to.request(http.MethodPost, API_ORIGINS, reqBody, nil)
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
 	var originResp tc.OriginDetailResponse
-	if err = json.NewDecoder(resp.Body).Decode(&originResp); err != nil {
-		return nil, reqInf, err
-	}
-	return &originResp, reqInf, nil
+	reqInf, err = to.post(API_ORIGINS, origin, nil, &originResp)
+	return &originResp, reqInf, err
 }
 
 func (to *Session) UpdateOriginByIDWithHdr(id int, origin tc.Origin, header http.Header) (*tc.OriginDetailResponse, ReqInf, error) {
@@ -120,25 +107,10 @@ func (to *Session) UpdateOriginByIDWithHdr(id int, origin tc.Origin, header http
 	if err != nil {
 		return nil, reqInf, err
 	}
-
-	reqBody, err := json.Marshal(origin)
-	if err != nil {
-		return nil, reqInf, err
-	}
 	route := fmt.Sprintf("%s?id=%d", API_ORIGINS, id)
-	resp, remoteAddr, err := to.request(http.MethodPut, route, reqBody, header)
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
 	var originResp tc.OriginDetailResponse
-	if err = json.NewDecoder(resp.Body).Decode(&originResp); err != nil {
-		return nil, reqInf, err
-	}
-	return &originResp, reqInf, nil
+	reqInf, err = to.put(route, origin, header, &originResp)
+	return &originResp, reqInf, err
 }
 
 // Update an Origin by ID
@@ -150,19 +122,9 @@ func (to *Session) UpdateOriginByID(id int, origin tc.Origin) (*tc.OriginDetailR
 // GET a list of Origins by a query parameter string
 func (to *Session) GetOriginsByQueryParams(queryParams string) ([]tc.Origin, ReqInf, error) {
 	URI := API_ORIGINS + queryParams
-	resp, remoteAddr, err := to.request(http.MethodGet, URI, nil, nil)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	var data tc.OriginsResponse
-	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
-		return nil, reqInf, err
-	}
-
-	return data.Response, reqInf, nil
+	reqInf, err := to.get(URI, nil, &data)
+	return data.Response, reqInf, err
 }
 
 // Returns a list of Origins
@@ -188,15 +150,7 @@ func (to *Session) GetOriginsByDeliveryServiceID(id int) ([]tc.Origin, ReqInf, e
 // DELETE an Origin by ID
 func (to *Session) DeleteOriginByID(id int) (tc.Alerts, ReqInf, error) {
 	route := fmt.Sprintf("%s?id=%d", API_ORIGINS, id)
-	resp, remoteAddr, err := to.request(http.MethodDelete, route, nil, nil)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
 	var alerts tc.Alerts
-	if err = json.NewDecoder(resp.Body).Decode(&alerts); err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	return alerts, reqInf, nil
+	reqInf, err := to.del(route, nil, &alerts)
+	return alerts, reqInf, err
 }
diff --git a/traffic_ops/v3-client/parameter.go b/traffic_ops/v3-client/parameter.go
index 889401f..4a80acc 100644
--- a/traffic_ops/v3-client/parameter.go
+++ b/traffic_ops/v3-client/parameter.go
@@ -16,9 +16,7 @@
 package client
 
 import (
-	"encoding/json"
 	"fmt"
-	"net"
 	"net/http"
 	"net/url"
 
@@ -31,62 +29,23 @@ const (
 
 // CreateParameter performs a POST to create a Parameter.
 func (to *Session) CreateParameter(pl tc.Parameter) (tc.Alerts, ReqInf, error) {
-
-	var remoteAddr net.Addr
-	reqBody, err := json.Marshal(pl)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	resp, remoteAddr, err := to.request(http.MethodPost, API_PARAMETERS, reqBody, nil)
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
 	var alerts tc.Alerts
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
-	return alerts, reqInf, nil
+	reqInf, err := to.post(API_PARAMETERS, pl, nil, &alerts)
+	return alerts, reqInf, err
 }
 
 // CreateMultipleParameters performs a POST to create multiple Parameters at once.
 func (to *Session) CreateMultipleParameters(pls []tc.Parameter) (tc.Alerts, ReqInf, error) {
-
-	var remoteAddr net.Addr
-	reqBody, err := json.Marshal(pls)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	resp, remoteAddr, err := to.request(http.MethodPost, API_PARAMETERS, reqBody, nil)
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
 	var alerts tc.Alerts
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
-	return alerts, reqInf, nil
+	reqInf, err := to.post(API_PARAMETERS, pls, nil, &alerts)
+	return alerts, reqInf, err
 }
 
 func (to *Session) UpdateParameterByIDWithHdr(id int, pl tc.Parameter, header http.Header) (tc.Alerts, ReqInf, error) {
-
-	var remoteAddr net.Addr
-	reqBody, err := json.Marshal(pl)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
 	route := fmt.Sprintf("%s/%d", API_PARAMETERS, id)
-	resp, remoteAddr, err := to.request(http.MethodPut, route, reqBody, header)
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-	}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
 	var alerts tc.Alerts
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
-	return alerts, reqInf, nil
+	reqInf, err := to.put(route, pl, header, &alerts)
+	return alerts, reqInf, err
 }
 
 // UpdateParameterByID performs a PUT to update a Parameter by ID.
@@ -96,22 +55,9 @@ func (to *Session) UpdateParameterByID(id int, pl tc.Parameter) (tc.Alerts, ReqI
 }
 
 func (to *Session) GetParametersWithHdr(header http.Header) ([]tc.Parameter, ReqInf, error) {
-	resp, remoteAddr, err := to.request(http.MethodGet, API_PARAMETERS, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.Parameter{}, reqInf, nil
-		}
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	var data tc.ParametersResponse
-	err = json.NewDecoder(resp.Body).Decode(&data)
-	return data.Response, reqInf, nil
+	reqInf, err := to.get(API_PARAMETERS, header, &data)
+	return data.Response, reqInf, err
 }
 
 // GetParameters returns a list of Parameters.
@@ -122,25 +68,9 @@ func (to *Session) GetParameters() ([]tc.Parameter, ReqInf, error) {
 
 func (to *Session) GetParameterByIDWithHdr(id int, header http.Header) ([]tc.Parameter, ReqInf, error) {
 	route := fmt.Sprintf("%s?id=%d", API_PARAMETERS, id)
-	resp, remoteAddr, err := to.request(http.MethodGet, route, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.Parameter{}, reqInf, nil
-		}
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	var data tc.ParametersResponse
-	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
-		return nil, reqInf, err
-	}
-
-	return data.Response, reqInf, nil
+	reqInf, err := to.get(route, header, &data)
+	return data.Response, reqInf, err
 }
 
 // GetParameterByID GETs a Parameter by the Parameter ID.
@@ -151,25 +81,9 @@ func (to *Session) GetParameterByID(id int) ([]tc.Parameter, ReqInf, error) {
 
 func (to *Session) GetParameterByNameWithHdr(name string, header http.Header) ([]tc.Parameter, ReqInf, error) {
 	URI := API_PARAMETERS + "?name=" + url.QueryEscape(name)
-	resp, remoteAddr, err := to.request(http.MethodGet, URI, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.Parameter{}, reqInf, nil
-		}
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	var data tc.ParametersResponse
-	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
-		return nil, reqInf, err
-	}
-
-	return data.Response, reqInf, nil
+	reqInf, err := to.get(URI, header, &data)
+	return data.Response, reqInf, err
 }
 
 // GetParameterByName GETs a Parameter by the Parameter name.
@@ -180,25 +94,9 @@ func (to *Session) GetParameterByName(name string) ([]tc.Parameter, ReqInf, erro
 
 func (to *Session) GetParameterByConfigFileWithHdr(configFile string, header http.Header) ([]tc.Parameter, ReqInf, error) {
 	URI := API_PARAMETERS + "?configFile=" + url.QueryEscape(configFile)
-	resp, remoteAddr, err := to.request(http.MethodGet, URI, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.Parameter{}, reqInf, nil
-		}
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	var data tc.ParametersResponse
-	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
-		return nil, reqInf, err
-	}
-
-	return data.Response, reqInf, nil
+	reqInf, err := to.get(URI, header, &data)
+	return data.Response, reqInf, err
 }
 
 // GetParameterByConfigFile GETs a Parameter by the Parameter ConfigFile.
@@ -209,25 +107,9 @@ func (to *Session) GetParameterByConfigFile(configFile string) ([]tc.Parameter,
 
 func (to *Session) GetParameterByNameAndConfigFileWithHdr(name string, configFile string, header http.Header) ([]tc.Parameter, ReqInf, error) {
 	URI := fmt.Sprintf("%s?name=%s&configFile=%s", API_PARAMETERS, url.QueryEscape(name), url.QueryEscape(configFile))
-	resp, remoteAddr, err := to.request(http.MethodGet, URI, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.Parameter{}, reqInf, nil
-		}
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	var data tc.ParametersResponse
-	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
-		return nil, reqInf, err
-	}
-
-	return data.Response, reqInf, nil
+	reqInf, err := to.get(URI, header, &data)
+	return data.Response, reqInf, err
 }
 
 // GetParameterByNameAndConfigFile GETs a Parameter by the Parameter Name and ConfigFile.
@@ -263,13 +145,7 @@ func (to *Session) GetParameterByNameAndConfigFileAndValue(name, configFile, val
 // DeleteParameterByID DELETEs a Parameter by ID.
 func (to *Session) DeleteParameterByID(id int) (tc.Alerts, ReqInf, error) {
 	URI := fmt.Sprintf("%s/%d", API_PARAMETERS, id)
-	resp, remoteAddr, err := to.request(http.MethodDelete, URI, nil, nil)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
 	var alerts tc.Alerts
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
-	return alerts, reqInf, nil
+	reqInf, err := to.del(URI, nil, &alerts)
+	return alerts, reqInf, err
 }
diff --git a/traffic_ops/v3-client/phys_location.go b/traffic_ops/v3-client/phys_location.go
index 2f2cf23..fad0bb3 100644
--- a/traffic_ops/v3-client/phys_location.go
+++ b/traffic_ops/v3-client/phys_location.go
@@ -16,10 +16,8 @@
 package client
 
 import (
-	"encoding/json"
 	"errors"
 	"fmt"
-	"net"
 	"net/http"
 	"net/url"
 
@@ -33,7 +31,7 @@ const (
 // CreatePhysLocation creates a PhysLocation.
 func (to *Session) CreatePhysLocation(pl tc.PhysLocation) (tc.Alerts, ReqInf, error) {
 	if pl.RegionID == 0 && pl.RegionName != "" {
-		regions, _, err := to.GetRegionByName(pl.RegionName)
+		regions, _, err := to.GetRegionByNameWithHdr(pl.RegionName, nil)
 		if err != nil {
 			return tc.Alerts{}, ReqInf{}, err
 		}
@@ -42,42 +40,16 @@ func (to *Session) CreatePhysLocation(pl tc.PhysLocation) (tc.Alerts, ReqInf, er
 		}
 		pl.RegionID = regions[0].ID
 	}
-	var remoteAddr net.Addr
-	reqBody, err := json.Marshal(pl)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	resp, remoteAddr, err := to.request(http.MethodPost, API_PHYS_LOCATIONS, reqBody, nil)
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
 	var alerts tc.Alerts
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
-	return alerts, reqInf, nil
+	reqInf, err := to.post(API_PHYS_LOCATIONS, pl, nil, &alerts)
+	return alerts, reqInf, err
 }
 
 func (to *Session) UpdatePhysLocationByIDWithHdr(id int, pl tc.PhysLocation, header http.Header) (tc.Alerts, ReqInf, error) {
-
-	var remoteAddr net.Addr
-	reqBody, err := json.Marshal(pl)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
 	route := fmt.Sprintf("%s/%d", API_PHYS_LOCATIONS, id)
-	resp, remoteAddr, err := to.request(http.MethodPut, route, reqBody, header)
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-	}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
 	var alerts tc.Alerts
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
-	return alerts, reqInf, nil
+	reqInf, err := to.put(route, pl, header, &alerts)
+	return alerts, reqInf, err
 }
 
 // Update a PhysLocation by ID
@@ -88,22 +60,9 @@ func (to *Session) UpdatePhysLocationByID(id int, pl tc.PhysLocation) (tc.Alerts
 
 func (to *Session) GetPhysLocationsWithHdr(params map[string]string, header http.Header) ([]tc.PhysLocation, ReqInf, error) {
 	path := API_PHYS_LOCATIONS + mapToQueryParameters(params)
-	resp, remoteAddr, err := to.request(http.MethodGet, path, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.PhysLocation{}, reqInf, nil
-		}
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	var data tc.PhysLocationsResponse
-	err = json.NewDecoder(resp.Body).Decode(&data)
-	return data.Response, reqInf, nil
+	reqInf, err := to.get(path, header, &data)
+	return data.Response, reqInf, err
 }
 
 // Returns a list of PhysLocations with optional query parameters applied
@@ -114,25 +73,9 @@ func (to *Session) GetPhysLocations(params map[string]string) ([]tc.PhysLocation
 
 func (to *Session) GetPhysLocationByIDWithHdr(id int, header http.Header) ([]tc.PhysLocation, ReqInf, error) {
 	route := fmt.Sprintf("%s?id=%d", API_PHYS_LOCATIONS, id)
-	resp, remoteAddr, err := to.request(http.MethodGet, route, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.PhysLocation{}, reqInf, nil
-		}
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	var data tc.PhysLocationsResponse
-	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
-		return nil, reqInf, err
-	}
-
-	return data.Response, reqInf, nil
+	reqInf, err := to.get(route, header, &data)
+	return data.Response, reqInf, err
 }
 
 // GET a PhysLocation by the PhysLocation ID
@@ -142,26 +85,10 @@ func (to *Session) GetPhysLocationByID(id int) ([]tc.PhysLocation, ReqInf, error
 }
 
 func (to *Session) GetPhysLocationByNameWithHdr(name string, header http.Header) ([]tc.PhysLocation, ReqInf, error) {
-	url := fmt.Sprintf("%s?name=%s", API_PHYS_LOCATIONS, url.QueryEscape(name))
-	resp, remoteAddr, err := to.request(http.MethodGet, url, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.PhysLocation{}, reqInf, nil
-		}
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
+	route := fmt.Sprintf("%s?name=%s", API_PHYS_LOCATIONS, url.QueryEscape(name))
 	var data tc.PhysLocationsResponse
-	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
-		return nil, reqInf, err
-	}
-
-	return data.Response, reqInf, nil
+	reqInf, err := to.get(route, header, &data)
+	return data.Response, reqInf, err
 }
 
 // GET a PhysLocation by the PhysLocation name
@@ -173,13 +100,7 @@ func (to *Session) GetPhysLocationByName(name string) ([]tc.PhysLocation, ReqInf
 // DELETE a PhysLocation by ID
 func (to *Session) DeletePhysLocationByID(id int) (tc.Alerts, ReqInf, error) {
 	route := fmt.Sprintf("%s/%d", API_PHYS_LOCATIONS, id)
-	resp, remoteAddr, err := to.request(http.MethodDelete, route, nil, nil)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
 	var alerts tc.Alerts
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
-	return alerts, reqInf, nil
+	reqInf, err := to.del(route, nil, &alerts)
+	return alerts, reqInf, err
 }
diff --git a/traffic_ops/v3-client/ping.go b/traffic_ops/v3-client/ping.go
index ff898d5..e7f67d9 100644
--- a/traffic_ops/v3-client/ping.go
+++ b/traffic_ops/v3-client/ping.go
@@ -15,25 +15,13 @@
 
 package client
 
-import (
-	"encoding/json"
-	"net/http"
-)
-
 const (
 	API_PING = apiBase + "/ping"
 )
 
 // Ping returns a static json object to show that traffic_ops is responsive
 func (to *Session) Ping() (map[string]string, ReqInf, error) {
-	resp, remoteAddr, err := to.request(http.MethodGet, API_PING, nil, nil)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	var data map[string]string
-	err = json.NewDecoder(resp.Body).Decode(&data)
-	return data, reqInf, nil
+	reqInf, err := to.get(API_PING, nil, &data)
+	return data, reqInf, err
 }
diff --git a/traffic_ops/v3-client/profile.go b/traffic_ops/v3-client/profile.go
index 3e35bba..3ba6bc8 100644
--- a/traffic_ops/v3-client/profile.go
+++ b/traffic_ops/v3-client/profile.go
@@ -16,26 +16,22 @@
 package client
 
 import (
-	"encoding/json"
 	"fmt"
 	"net/http"
 	"net/url"
-	"strconv"
 
 	"github.com/apache/trafficcontrol/lib/go-tc"
 )
 
 const (
 	API_PROFILES                 = apiBase + "/profiles"
-	API_PROFILES_NAME_PARAMETERS = API_PROFILES + "/name/%v/parameters"
+	API_PROFILES_NAME_PARAMETERS = API_PROFILES + "/name/%s/parameters"
 )
 
 // CreateProfile creates a Profile.
 func (to *Session) CreateProfile(pl tc.Profile) (tc.Alerts, ReqInf, error) {
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss}
-
 	if pl.CDNID == 0 && pl.CDNName != "" {
-		cdns, _, err := to.GetCDNByName(pl.CDNName)
+		cdns, _, err := to.GetCDNByNameWithHdr(pl.CDNName, nil)
 		if err != nil {
 			return tc.Alerts{}, ReqInf{}, err
 		}
@@ -54,46 +50,15 @@ func (to *Session) CreateProfile(pl tc.Profile) (tc.Alerts, ReqInf, error) {
 		pl.CDNID = cdns[0].ID
 	}
 
-	reqBody, err := json.Marshal(pl)
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-
-	resp, remoteAddr, err := to.request(http.MethodPost, API_PROFILES, reqBody, nil)
-	reqInf.RemoteAddr = remoteAddr
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	var alerts tc.Alerts
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
-
+	reqInf, err := to.post(API_PROFILES, pl, nil, &alerts)
 	return alerts, reqInf, err
 }
 
 func (to *Session) UpdateProfileByIDWithHdr(id int, pl tc.Profile, header http.Header) (tc.Alerts, ReqInf, error) {
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss}
-
-	reqBody, err := json.Marshal(pl)
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-
 	route := fmt.Sprintf("%s/%d", API_PROFILES, id)
-	resp, remoteAddr, err := to.request(http.MethodPut, route, reqBody, header)
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-	}
-	reqInf.RemoteAddr = remoteAddr
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	var alerts tc.Alerts
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
-
+	reqInf, err := to.put(route, pl, header, &alerts)
 	return alerts, reqInf, err
 }
 
@@ -104,26 +69,10 @@ func (to *Session) UpdateProfileByID(id int, pl tc.Profile) (tc.Alerts, ReqInf,
 }
 
 func (to *Session) GetParametersByProfileNameWithHdr(profileName string, header http.Header) ([]tc.Parameter, ReqInf, error) {
-	url := fmt.Sprintf(API_PROFILES_NAME_PARAMETERS, profileName)
-	resp, remoteAddr, err := to.request(http.MethodGet, url, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.Parameter{}, reqInf, nil
-		}
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
+	route := fmt.Sprintf(API_PROFILES_NAME_PARAMETERS, profileName)
 	var data tc.ParametersResponse
-	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
-		return nil, reqInf, err
-	}
-
-	return data.Response, reqInf, nil
+	reqInf, err := to.get(route, header, &data)
+	return data.Response, reqInf, err
 }
 
 // GetParametersByProfileName gets all of the Parameters assigned to the Profile named 'profileName'.
@@ -133,24 +82,8 @@ func (to *Session) GetParametersByProfileName(profileName string) ([]tc.Paramete
 }
 
 func (to *Session) GetProfilesWithHdr(header http.Header) ([]tc.Profile, ReqInf, error) {
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss}
-
-	resp, remoteAddr, err := to.request(http.MethodGet, API_PROFILES, nil, header)
-	reqInf.RemoteAddr = remoteAddr
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.Profile{}, reqInf, nil
-		}
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	var data tc.ProfilesResponse
-	err = json.NewDecoder(resp.Body).Decode(&data)
-
+	reqInf, err := to.get(API_PROFILES, header, &data)
 	return data.Response, reqInf, err
 }
 
@@ -162,22 +95,8 @@ func (to *Session) GetProfiles() ([]tc.Profile, ReqInf, error) {
 
 func (to *Session) GetProfileByIDWithHdr(id int, header http.Header) ([]tc.Profile, ReqInf, error) {
 	route := fmt.Sprintf("%s?id=%d", API_PROFILES, id)
-	resp, remoteAddr, err := to.request(http.MethodGet, route, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.Profile{}, reqInf, nil
-		}
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	var data tc.ProfilesResponse
-	err = json.NewDecoder(resp.Body).Decode(&data)
-
+	reqInf, err := to.get(route, header, &data)
 	return data.Response, reqInf, err
 }
 
@@ -189,22 +108,8 @@ func (to *Session) GetProfileByID(id int) ([]tc.Profile, ReqInf, error) {
 
 func (to *Session) GetProfileByNameWithHdr(name string, header http.Header) ([]tc.Profile, ReqInf, error) {
 	URI := fmt.Sprintf("%s?name=%s", API_PROFILES, url.QueryEscape(name))
-	resp, remoteAddr, err := to.request(http.MethodGet, URI, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.Profile{}, reqInf, nil
-		}
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	var data tc.ProfilesResponse
-	err = json.NewDecoder(resp.Body).Decode(&data)
-
+	reqInf, err := to.get(URI, header, &data)
 	return data.Response, reqInf, err
 }
 
@@ -216,22 +121,8 @@ func (to *Session) GetProfileByName(name string) ([]tc.Profile, ReqInf, error) {
 
 func (to *Session) GetProfileByParameterWithHdr(param string, header http.Header) ([]tc.Profile, ReqInf, error) {
 	URI := fmt.Sprintf("%s?param=%s", API_PROFILES, url.QueryEscape(param))
-	resp, remoteAddr, err := to.request(http.MethodGet, URI, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.Profile{}, reqInf, nil
-		}
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	var data tc.ProfilesResponse
-	err = json.NewDecoder(resp.Body).Decode(&data)
-
+	reqInf, err := to.get(URI, header, &data)
 	return data.Response, reqInf, err
 }
 
@@ -242,23 +133,9 @@ func (to *Session) GetProfileByParameter(param string) ([]tc.Profile, ReqInf, er
 }
 
 func (to *Session) GetProfileByCDNIDWithHdr(cdnID int, header http.Header) ([]tc.Profile, ReqInf, error) {
-	URI := fmt.Sprintf("%s?cdn=%s", API_PROFILES, strconv.Itoa(cdnID))
-	resp, remoteAddr, err := to.request(http.MethodGet, URI, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.Profile{}, reqInf, nil
-		}
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
+	URI := fmt.Sprintf("%s?cdn=%d", API_PROFILES, cdnID)
 	var data tc.ProfilesResponse
-	err = json.NewDecoder(resp.Body).Decode(&data)
-
+	reqInf, err := to.get(URI, header, &data)
 	return data.Response, reqInf, err
 }
 
@@ -271,79 +148,31 @@ func (to *Session) GetProfileByCDNID(cdnID int) ([]tc.Profile, ReqInf, error) {
 // DeleteProfileByID DELETEs a Profile by ID.
 func (to *Session) DeleteProfileByID(id int) (tc.Alerts, ReqInf, error) {
 	URI := fmt.Sprintf("%s/%d", API_PROFILES, id)
-	resp, remoteAddr, err := to.request(http.MethodDelete, URI, nil, nil)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	var alerts tc.Alerts
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
-
+	reqInf, err := to.del(URI, nil, &alerts)
 	return alerts, reqInf, err
 }
 
 // ExportProfile Returns an exported Profile.
 func (to *Session) ExportProfile(id int) (*tc.ProfileExportResponse, ReqInf, error) {
 	route := fmt.Sprintf("%s/%d/export", API_PROFILES, id)
-	resp, remoteAddr, err := to.request(http.MethodGet, route, nil, nil)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	var data tc.ProfileExportResponse
-	err = json.NewDecoder(resp.Body).Decode(&data)
-
+	reqInf, err := to.get(route, nil, &data)
 	return &data, reqInf, err
 }
 
 // ImportProfile imports an exported Profile.
 func (to *Session) ImportProfile(importRequest *tc.ProfileImportRequest) (*tc.ProfileImportResponse, ReqInf, error) {
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss}
-
 	route := fmt.Sprintf("%s/import", API_PROFILES)
-	reqBody, err := json.Marshal(importRequest)
-	if err != nil {
-		return nil, reqInf, err
-	}
-
-	resp, remoteAddr, err := to.request(http.MethodPost, route, reqBody, nil)
-	reqInf.RemoteAddr = remoteAddr
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	var data tc.ProfileImportResponse
-	err = json.NewDecoder(resp.Body).Decode(&data)
-
+	reqInf, err := to.post(route, importRequest, nil, &data)
 	return &data, reqInf, err
 }
 
 // CopyProfile creates a new profile from an existing profile.
 func (to *Session) CopyProfile(p tc.ProfileCopy) (tc.ProfileCopyResponse, ReqInf, error) {
-	var (
-		path   = fmt.Sprintf("%s/name/%s/copy/%s", API_PROFILES, p.Name, p.ExistingName)
-		reqInf = ReqInf{CacheHitStatus: CacheHitStatusMiss}
-		resp   tc.ProfileCopyResponse
-	)
-
-	reqBody, err := json.Marshal(p)
-	if err != nil {
-		return tc.ProfileCopyResponse{}, ReqInf{}, err
-	}
-
-	httpResp, remoteAddr, err := to.request(http.MethodPost, path, reqBody, nil)
-	reqInf.RemoteAddr = remoteAddr
-	if err != nil {
-		return tc.ProfileCopyResponse{}, reqInf, err
-	}
-	defer httpResp.Body.Close()
-
-	err = json.NewDecoder(httpResp.Body).Decode(&resp)
-
+	path := fmt.Sprintf("%s/name/%s/copy/%s", API_PROFILES, p.Name, p.ExistingName)
+	resp := tc.ProfileCopyResponse{}
+	reqInf, err := to.post(path, p, nil, &resp)
 	return resp, reqInf, err
 }
diff --git a/traffic_ops/v3-client/profile_parameter.go b/traffic_ops/v3-client/profile_parameter.go
index 6aab10c..579294a 100644
--- a/traffic_ops/v3-client/profile_parameter.go
+++ b/traffic_ops/v3-client/profile_parameter.go
@@ -16,9 +16,7 @@
 package client
 
 import (
-	"encoding/json"
 	"fmt"
-	"net"
 	"net/http"
 
 	"github.com/apache/trafficcontrol/lib/go-tc"
@@ -32,59 +30,20 @@ const (
 
 // Create a ProfileParameter
 func (to *Session) CreateProfileParameter(pp tc.ProfileParameter) (tc.Alerts, ReqInf, error) {
-
-	var remoteAddr net.Addr
-	reqBody, err := json.Marshal(pp)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	resp, remoteAddr, err := to.request(http.MethodPost, API_PROFILE_PARAMETERS, reqBody, nil)
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
 	var alerts tc.Alerts
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
-	return alerts, reqInf, nil
+	reqInf, err := to.post(API_PROFILE_PARAMETERS, pp, nil, &alerts)
+	return alerts, reqInf, err
 }
 
 // CreateMultipleProfileParameters creates multiple ProfileParameters at once.
 func (to *Session) CreateMultipleProfileParameters(pps []tc.ProfileParameter) (tc.Alerts, ReqInf, error) {
-
-	var remoteAddr net.Addr
-	reqBody, err := json.Marshal(pps)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	resp, remoteAddr, err := to.request(http.MethodPost, API_PROFILE_PARAMETERS, reqBody, nil)
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
 	var alerts tc.Alerts
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
-	return alerts, reqInf, nil
+	reqInf, err := to.post(API_PROFILE_PARAMETERS, pps, nil, &alerts)
+	return alerts, reqInf, err
 }
 
 func (to *Session) GetProfileParametersWithHdr(header http.Header) ([]tc.ProfileParameter, ReqInf, error) {
-	resp, remoteAddr, err := to.request(http.MethodGet, API_PROFILE_PARAMETERS, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.ProfileParameter{}, reqInf, nil
-		}
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
-	var data tc.ProfileParametersResponse
-	err = json.NewDecoder(resp.Body).Decode(&data)
-	return data.Response, reqInf, nil
+	return to.GetProfileParameterByQueryParamsWithHdr("", header)
 }
 
 // Returns a list of Profile Parameters
@@ -95,25 +54,22 @@ func (to *Session) GetProfileParameters() ([]tc.ProfileParameter, ReqInf, error)
 
 func (to *Session) GetProfileParameterByQueryParamsWithHdr(queryParams string, header http.Header) ([]tc.ProfileParameter, ReqInf, error) {
 	URI := API_PROFILE_PARAMETERS + queryParams
-	resp, remoteAddr, err := to.request(http.MethodGet, URI, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.ProfileParameter{}, reqInf, nil
-		}
-	}
+	var data tc.ProfileParametersNullableResponse
+	reqInf, err := to.get(URI, header, &data)
 	if err != nil {
 		return nil, reqInf, err
 	}
-	defer resp.Body.Close()
-
-	var data tc.ProfileParametersResponse
-	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
-		return nil, reqInf, err
+	ret := make([]tc.ProfileParameter, len(data.Response))
+	for i, pp := range data.Response {
+		ret[i] = tc.ProfileParameter{}
+		if pp.Profile != nil {
+			ret[i].Profile = *pp.Profile
+		}
+		if pp.Parameter != nil {
+			ret[i].ParameterID = *pp.Parameter
+		}
 	}
-
-	return data.Response, reqInf, nil
+	return ret, reqInf, nil
 }
 
 // GET a Profile Parameter by the Parameter
@@ -125,13 +81,7 @@ func (to *Session) GetProfileParameterByQueryParams(queryParams string) ([]tc.Pr
 // DELETE a Parameter by Parameter
 func (to *Session) DeleteParameterByProfileParameter(profile int, parameter int) (tc.Alerts, ReqInf, error) {
 	URI := fmt.Sprintf("%s/%d/%d", API_PROFILE_PARAMETERS, profile, parameter)
-	resp, remoteAddr, err := to.request(http.MethodDelete, URI, nil, nil)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
 	var alerts tc.Alerts
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
-	return alerts, reqInf, nil
+	reqInf, err := to.del(URI, nil, &alerts)
+	return alerts, reqInf, err
 }
diff --git a/traffic_ops/v3-client/region.go b/traffic_ops/v3-client/region.go
index 0dfe240..6e69acc 100644
--- a/traffic_ops/v3-client/region.go
+++ b/traffic_ops/v3-client/region.go
@@ -16,10 +16,8 @@
 package client
 
 import (
-	"encoding/json"
 	"errors"
 	"fmt"
-	"net"
 	"net/http"
 	"net/url"
 	"strconv"
@@ -34,7 +32,7 @@ const (
 // CreateRegion creates a Region.
 func (to *Session) CreateRegion(region tc.Region) (tc.Alerts, ReqInf, error) {
 	if region.Division == 0 && region.DivisionName != "" {
-		divisions, _, err := to.GetDivisionByName(region.DivisionName)
+		divisions, _, err := to.GetDivisionByNameWithHdr(region.DivisionName, nil)
 		if err != nil {
 			return tc.Alerts{}, ReqInf{}, err
 		}
@@ -43,43 +41,16 @@ func (to *Session) CreateRegion(region tc.Region) (tc.Alerts, ReqInf, error) {
 		}
 		region.Division = divisions[0].ID
 	}
-
-	var remoteAddr net.Addr
-	reqBody, err := json.Marshal(region)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	resp, remoteAddr, err := to.request(http.MethodPost, API_REGIONS, reqBody, nil)
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
 	var alerts tc.Alerts
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
-	return alerts, reqInf, nil
+	reqInf, err := to.post(API_REGIONS, region, nil, &alerts)
+	return alerts, reqInf, err
 }
 
 func (to *Session) UpdateRegionByIDWithHdr(id int, region tc.Region, header http.Header) (tc.Alerts, ReqInf, error) {
-
-	var remoteAddr net.Addr
-	reqBody, err := json.Marshal(region)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
 	route := fmt.Sprintf("%s/%d", API_REGIONS, id)
-	resp, remoteAddr, err := to.request(http.MethodPut, route, reqBody, header)
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-	}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
 	var alerts tc.Alerts
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
-	return alerts, reqInf, nil
+	reqInf, err := to.put(route, region, header, &alerts)
+	return alerts, reqInf, err
 }
 
 // UpdateRegionByID updates a Region by ID.
@@ -89,22 +60,9 @@ func (to *Session) UpdateRegionByID(id int, region tc.Region) (tc.Alerts, ReqInf
 }
 
 func (to *Session) GetRegionsWithHdr(header http.Header) ([]tc.Region, ReqInf, error) {
-	resp, remoteAddr, err := to.request(http.MethodGet, API_REGIONS, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.Region{}, reqInf, nil
-		}
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	var data tc.RegionsResponse
-	err = json.NewDecoder(resp.Body).Decode(&data)
-	return data.Response, reqInf, nil
+	reqInf, err := to.get(API_REGIONS, header, &data)
+	return data.Response, reqInf, err
 }
 
 // GetRegions returns a list of regions.
@@ -115,25 +73,9 @@ func (to *Session) GetRegions() ([]tc.Region, ReqInf, error) {
 
 func (to *Session) GetRegionByIDWithHdr(id int, header http.Header) ([]tc.Region, ReqInf, error) {
 	route := fmt.Sprintf("%s?id=%d", API_REGIONS, id)
-	resp, remoteAddr, err := to.request(http.MethodGet, route, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.Region{}, reqInf, nil
-		}
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	var data tc.RegionsResponse
-	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
-		return nil, reqInf, err
-	}
-
-	return data.Response, reqInf, nil
+	reqInf, err := to.get(route, header, &data)
+	return data.Response, reqInf, err
 }
 
 // GetRegionByID GETs a Region by the Region ID.
@@ -143,26 +85,10 @@ func (to *Session) GetRegionByID(id int) ([]tc.Region, ReqInf, error) {
 }
 
 func (to *Session) GetRegionByNameWithHdr(name string, header http.Header) ([]tc.Region, ReqInf, error) {
-	url := fmt.Sprintf("%s?name=%s", API_REGIONS, url.QueryEscape(name))
-	resp, remoteAddr, err := to.request(http.MethodGet, url, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.Region{}, reqInf, nil
-		}
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
+	route := fmt.Sprintf("%s?name=%s", API_REGIONS, url.QueryEscape(name))
 	var data tc.RegionsResponse
-	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
-		return nil, reqInf, err
-	}
-
-	return data.Response, reqInf, nil
+	reqInf, err := to.get(route, header, &data)
+	return data.Response, reqInf, err
 }
 
 // GetRegionByName GETs a Region by the Region name.
@@ -174,15 +100,9 @@ func (to *Session) GetRegionByName(name string) ([]tc.Region, ReqInf, error) {
 // DeleteRegionByID DELETEs a Region by ID.
 func (to *Session) DeleteRegionByID(id int) (tc.Alerts, ReqInf, error) {
 	route := fmt.Sprintf("%s?id=%d", API_REGIONS, id)
-	resp, remoteAddr, err := to.request(http.MethodDelete, route, nil, nil)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
 	var alerts tc.Alerts
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
-	return alerts, reqInf, nil
+	reqInf, err := to.del(route, nil, &alerts)
+	return alerts, reqInf, err
 }
 
 // DeleteRegion lets you DELETE a Region. Only 1 parameter is required, not both.
@@ -199,13 +119,7 @@ func (to *Session) DeleteRegion(id *int, name *string) (tc.Alerts, ReqInf, error
 		URI = fmt.Sprintf("%s?%s", URI, qStr)
 	}
 
-	resp, remoteAddr, err := to.request(http.MethodDelete, URI, nil, nil)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
 	var alerts tc.Alerts
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
+	reqInf, err := to.del(URI, nil, &alerts)
 	return alerts, reqInf, err
 }
diff --git a/traffic_ops/v3-client/role.go b/traffic_ops/v3-client/role.go
index b13dcae..fb7e95c 100644
--- a/traffic_ops/v3-client/role.go
+++ b/traffic_ops/v3-client/role.go
@@ -16,9 +16,7 @@
 package client
 
 import (
-	"encoding/json"
 	"fmt"
-	"net"
 	"net/http"
 	"net/url"
 
@@ -30,73 +28,30 @@ const (
 )
 
 // CreateRole creates a Role.
-func (to *Session) CreateRole(region tc.Role) (tc.Alerts, ReqInf, int, error) {
-
-	var remoteAddr net.Addr
-	reqBody, err := json.Marshal(region)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, 0, err
-	}
-	resp, remoteAddr, errClient := to.RawRequest(http.MethodPost, API_ROLES, reqBody)
-	if resp != nil {
-		defer resp.Body.Close()
-		var alerts tc.Alerts
-		if err = json.NewDecoder(resp.Body).Decode(&alerts); err != nil {
-			return alerts, reqInf, resp.StatusCode, err
-		}
-		return alerts, reqInf, resp.StatusCode, errClient
-	}
-	return tc.Alerts{}, reqInf, 0, errClient
+func (to *Session) CreateRole(role tc.Role) (tc.Alerts, ReqInf, int, error) {
+	var alerts tc.Alerts
+	reqInf, err := to.post(API_ROLES, role, nil, &alerts)
+	return alerts, reqInf, reqInf.StatusCode, err
 }
 
-func (to *Session) UpdateRoleByIDWithHdr(id int, region tc.Role, header http.Header) (tc.Alerts, ReqInf, int, error) {
-
-	var remoteAddr net.Addr
-	reqBody, err := json.Marshal(region)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, 0, err
-	}
+func (to *Session) UpdateRoleByIDWithHdr(id int, role tc.Role, header http.Header) (tc.Alerts, ReqInf, int, error) {
 	route := fmt.Sprintf("%s/?id=%d", API_ROLES, id)
-	resp, remoteAddr, errClient := to.RawRequestWithHdr(http.MethodPut, route, reqBody, header)
-	if resp != nil {
-		defer resp.Body.Close()
-		var alerts tc.Alerts
-		if err = json.NewDecoder(resp.Body).Decode(&alerts); err != nil {
-			return alerts, reqInf, resp.StatusCode, err
-		}
-		return alerts, reqInf, resp.StatusCode, errClient
-	}
-	return tc.Alerts{}, reqInf, 0, errClient
+	var alerts tc.Alerts
+	reqInf, err := to.put(route, role, header, &alerts)
+	return alerts, reqInf, reqInf.StatusCode, err
 }
 
 // UpdateRoleByID updates a Role by ID.
 // Deprecated: UpdateRoleByID will be removed in 6.0. Use UpdateRoleByIDWithHdr.
-func (to *Session) UpdateRoleByID(id int, region tc.Role) (tc.Alerts, ReqInf, int, error) {
+func (to *Session) UpdateRoleByID(id int, role tc.Role) (tc.Alerts, ReqInf, int, error) {
 
-	return to.UpdateRoleByIDWithHdr(id, region, nil)
+	return to.UpdateRoleByIDWithHdr(id, role, nil)
 }
 
 func (to *Session) GetRolesWithHdr(header http.Header) ([]tc.Role, ReqInf, int, error) {
-	resp, remoteAddr, errClient := to.RawRequestWithHdr(http.MethodGet, API_ROLES, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.Role{}, reqInf, http.StatusNotModified, nil
-		}
-	}
-	if resp != nil {
-		defer resp.Body.Close()
-
-		var data tc.RolesResponse
-		if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
-			return data.Response, reqInf, resp.StatusCode, err
-		}
-		return data.Response, reqInf, resp.StatusCode, errClient
-	}
-	return []tc.Role{}, reqInf, 0, errClient
+	var data tc.RolesResponse
+	reqInf, err := to.get(API_ROLES, header, &data)
+	return data.Response, reqInf, reqInf.StatusCode, err
 }
 
 // GetRoles returns a list of roles.
@@ -107,24 +62,9 @@ func (to *Session) GetRoles() ([]tc.Role, ReqInf, int, error) {
 
 func (to *Session) GetRoleByIDWithHdr(id int, header http.Header) ([]tc.Role, ReqInf, int, error) {
 	route := fmt.Sprintf("%s/?id=%d", API_ROLES, id)
-	resp, remoteAddr, errClient := to.RawRequestWithHdr(http.MethodGet, route, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.Role{}, reqInf, http.StatusNotModified, nil
-		}
-	}
-	if resp != nil {
-		defer resp.Body.Close()
-
-		var data tc.RolesResponse
-		if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
-			return data.Response, reqInf, resp.StatusCode, err
-		}
-		return data.Response, reqInf, resp.StatusCode, errClient
-	}
-	return []tc.Role{}, reqInf, 0, errClient
+	var data tc.RolesResponse
+	reqInf, err := to.get(route, header, &data)
+	return data.Response, reqInf, reqInf.StatusCode, err
 }
 
 // GetRoleByID GETs a Role by the Role ID.
@@ -135,24 +75,9 @@ func (to *Session) GetRoleByID(id int) ([]tc.Role, ReqInf, int, error) {
 
 func (to *Session) GetRoleByNameWithHdr(name string, header http.Header) ([]tc.Role, ReqInf, int, error) {
 	route := fmt.Sprintf("%s?name=%s", API_ROLES, url.QueryEscape(name))
-	resp, remoteAddr, errClient := to.RawRequestWithHdr(http.MethodGet, route, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.Role{}, reqInf, http.StatusNotModified, nil
-		}
-	}
-	if resp != nil {
-		defer resp.Body.Close()
-
-		var data tc.RolesResponse
-		if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
-			return data.Response, reqInf, resp.StatusCode, err
-		}
-		return data.Response, reqInf, resp.StatusCode, errClient
-	}
-	return []tc.Role{}, reqInf, 0, errClient
+	var data tc.RolesResponse
+	reqInf, err := to.get(route, header, &data)
+	return data.Response, reqInf, reqInf.StatusCode, err
 }
 
 // GetRoleByName GETs a Role by the Role name.
@@ -162,28 +87,10 @@ func (to *Session) GetRoleByName(name string) ([]tc.Role, ReqInf, int, error) {
 }
 
 func (to *Session) GetRoleByQueryParamsWithHdr(queryParams map[string]string, header http.Header) ([]tc.Role, ReqInf, int, error) {
-	route := fmt.Sprintf("%s?", API_ROLES)
-	for param, val := range queryParams {
-		route += fmt.Sprintf("%s=%s&", url.QueryEscape(param), url.QueryEscape(val))
-	}
-	resp, remoteAddr, errClient := to.RawRequestWithHdr(http.MethodGet, route, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.Role{}, reqInf, http.StatusNotModified, nil
-		}
-	}
-	if resp != nil {
-		defer resp.Body.Close()
-
-		var data tc.RolesResponse
-		if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
-			return data.Response, reqInf, resp.StatusCode, err
-		}
-		return data.Response, reqInf, resp.StatusCode, errClient
-	}
-	return []tc.Role{}, reqInf, 0, errClient
+	route := fmt.Sprintf("%s%s", API_ROLES, mapToQueryParameters(queryParams))
+	var data tc.RolesResponse
+	reqInf, err := to.get(route, header, &data)
+	return data.Response, reqInf, reqInf.StatusCode, err
 }
 
 // GetRoleByQueryParams gets a Role by the Role query parameters.
@@ -195,16 +102,7 @@ func (to *Session) GetRoleByQueryParams(queryParams map[string]string) ([]tc.Rol
 // DeleteRoleByID DELETEs a Role by ID.
 func (to *Session) DeleteRoleByID(id int) (tc.Alerts, ReqInf, int, error) {
 	route := fmt.Sprintf("%s/?id=%d", API_ROLES, id)
-	resp, remoteAddr, errClient := to.RawRequest(http.MethodDelete, route, nil)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		defer resp.Body.Close()
-
-		var alerts tc.Alerts
-		if err := json.NewDecoder(resp.Body).Decode(&alerts); err != nil {
-			return alerts, reqInf, resp.StatusCode, err
-		}
-		return alerts, reqInf, resp.StatusCode, errClient
-	}
-	return tc.Alerts{}, reqInf, 0, errClient
+	var alerts tc.Alerts
+	reqInf, err := to.del(route, nil, &alerts)
+	return alerts, reqInf, reqInf.StatusCode, err
 }
diff --git a/traffic_ops/v3-client/server.go b/traffic_ops/v3-client/server.go
index b63deda..28fbd12 100644
--- a/traffic_ops/v3-client/server.go
+++ b/traffic_ops/v3-client/server.go
@@ -16,7 +16,6 @@
 package client
 
 import (
-	"encoding/json"
 	"errors"
 	"fmt"
 	"net"
@@ -24,7 +23,6 @@ import (
 	"net/url"
 	"strings"
 
-	"github.com/apache/trafficcontrol/lib/go-log"
 	"github.com/apache/trafficcontrol/lib/go-tc"
 )
 
@@ -57,7 +55,7 @@ func (to *Session) CreateServerWithHdr(server tc.ServerV30, hdr http.Header) (tc
 	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
 
 	if needAndCanFetch(server.CachegroupID, server.Cachegroup) {
-		cg, _, err := to.GetCacheGroupNullableByName(*server.Cachegroup)
+		cg, _, err := to.GetCacheGroupNullableByNameWithHdr(*server.Cachegroup, nil)
 		if err != nil {
 			return alerts, reqInf, fmt.Errorf("no cachegroup named %s: %v", *server.Cachegroup, err)
 		}
@@ -70,7 +68,7 @@ func (to *Session) CreateServerWithHdr(server tc.ServerV30, hdr http.Header) (tc
 		server.CachegroupID = cg[0].ID
 	}
 	if needAndCanFetch(server.CDNID, server.CDNName) {
-		c, _, err := to.GetCDNByName(*server.CDNName)
+		c, _, err := to.GetCDNByNameWithHdr(*server.CDNName, nil)
 		if err != nil {
 			return alerts, reqInf, fmt.Errorf("no CDN named %s: %v", *server.CDNName, err)
 		}
@@ -80,7 +78,7 @@ func (to *Session) CreateServerWithHdr(server tc.ServerV30, hdr http.Header) (tc
 		server.CDNID = &c[0].ID
 	}
 	if needAndCanFetch(server.PhysLocationID, server.PhysLocation) {
-		ph, _, err := to.GetPhysLocationByName(*server.PhysLocation)
+		ph, _, err := to.GetPhysLocationByNameWithHdr(*server.PhysLocation, nil)
 		if err != nil {
 			return alerts, reqInf, fmt.Errorf("no physlocation named %s: %v", *server.PhysLocation, err)
 		}
@@ -90,7 +88,7 @@ func (to *Session) CreateServerWithHdr(server tc.ServerV30, hdr http.Header) (tc
 		server.PhysLocationID = &ph[0].ID
 	}
 	if needAndCanFetch(server.ProfileID, server.Profile) {
-		pr, _, err := to.GetProfileByName(*server.Profile)
+		pr, _, err := to.GetProfileByNameWithHdr(*server.Profile, nil)
 		if err != nil {
 			return alerts, reqInf, fmt.Errorf("no profile named %s: %v", *server.Profile, err)
 		}
@@ -100,7 +98,7 @@ func (to *Session) CreateServerWithHdr(server tc.ServerV30, hdr http.Header) (tc
 		server.ProfileID = &pr[0].ID
 	}
 	if needAndCanFetch(server.StatusID, server.Status) {
-		st, _, err := to.GetStatusByName(*server.Status)
+		st, _, err := to.GetStatusByNameWithHdr(*server.Status, nil)
 		if err != nil {
 			return alerts, reqInf, fmt.Errorf("no status named %s: %v", *server.Status, err)
 		}
@@ -110,7 +108,7 @@ func (to *Session) CreateServerWithHdr(server tc.ServerV30, hdr http.Header) (tc
 		server.StatusID = &st[0].ID
 	}
 	if (server.TypeID == nil || *server.TypeID == 0) && server.Type != "" {
-		ty, _, err := to.GetTypeByName(server.Type)
+		ty, _, err := to.GetTypeByNameWithHdr(server.Type, nil)
 		if err != nil {
 			return alerts, reqInf, fmt.Errorf("no type named %s: %v", server.Type, err)
 		}
@@ -120,48 +118,14 @@ func (to *Session) CreateServerWithHdr(server tc.ServerV30, hdr http.Header) (tc
 		server.TypeID = &ty[0].ID
 	}
 
-	reqBody, err := json.Marshal(server)
-	if err != nil {
-		return alerts, reqInf, err
-	}
-
-	resp, remoteAddr, err := to.request(http.MethodPost, API_SERVERS, reqBody, hdr)
-	reqInf.RemoteAddr = remoteAddr
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-	}
-	if err != nil {
-		return alerts, reqInf, err
-	}
-	defer resp.Body.Close()
-
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
+	reqInf, err := to.post(API_SERVERS, server, hdr, &alerts)
 	return alerts, reqInf, err
 }
 
 func (to *Session) UpdateServerByIDWithHdr(id int, server tc.ServerV30, header http.Header) (tc.Alerts, ReqInf, error) {
 	var alerts tc.Alerts
-	var remoteAddr net.Addr
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-
-	reqBody, err := json.Marshal(server)
-	if err != nil {
-		return alerts, reqInf, err
-	}
-
 	route := fmt.Sprintf("%s/%d", API_SERVERS, id)
-	resp, remoteAddr, err := to.request(http.MethodPut, route, reqBody, header)
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-	}
-	reqInf.RemoteAddr = remoteAddr
-	reqInf.StatusCode = resp.StatusCode
-	if err != nil {
-		return alerts, reqInf, err
-	}
-	defer resp.Body.Close()
-
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
+	reqInf, err := to.put(route, server, header, &alerts)
 	return alerts, reqInf, err
 }
 
@@ -184,21 +148,7 @@ func (to *Session) GetServersWithHdr(params *url.Values, header http.Header) (tc
 	}
 
 	var data tc.ServersV3Response
-
-	resp, remoteAddr, err := to.request(http.MethodGet, route, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return tc.ServersV3Response{}, reqInf, nil
-		}
-	}
-	if err != nil {
-		return data, reqInf, err
-	}
-	defer resp.Body.Close()
-
-	err = json.NewDecoder(resp.Body).Decode(&data)
+	reqInf, err := to.get(route, header, &data)
 	return data, reqInf, err
 }
 
@@ -233,7 +183,7 @@ func (to *Session) GetServers(params *url.Values) ([]tc.Server, ReqInf, error) {
 // It returns, in order, the API response that Traffic Ops returned, a request
 // info object, and any error that occurred.
 func (to *Session) GetFirstServer(params *url.Values, header http.Header) (tc.ServerV30, ReqInf, error) {
-	serversResponse, reqInf, err := to.GetServersWithHdr(params, nil)
+	serversResponse, reqInf, err := to.GetServersWithHdr(params, header)
 	var firstServer tc.ServerV30
 	if err != nil || reqInf.StatusCode == http.StatusNotModified {
 		return firstServer, reqInf, err
@@ -249,27 +199,10 @@ func (to *Session) GetFirstServer(params *url.Values, header http.Header) (tc.Se
 func (to *Session) GetServerDetailsByHostNameWithHdr(hostName string, header http.Header) ([]tc.ServerDetailV30, ReqInf, error) {
 	v := url.Values{}
 	v.Add("hostName", hostName)
-	url := API_SERVERS_DETAILS + "?" + v.Encode()
-
-	resp, remoteAddr, err := to.request(http.MethodGet, url, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.ServerDetailV30{}, reqInf, nil
-		}
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
+	route := API_SERVERS_DETAILS + "?" + v.Encode()
 	var data tc.ServersV3DetailResponse
-	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
-		return nil, reqInf, err
-	}
-
-	return data.Response, reqInf, nil
+	reqInf, err := to.get(route, header, &data)
+	return data.Response, reqInf, err
 }
 
 // GetServerDetailsByHostName GETs Servers by the Server hostname.
@@ -281,18 +214,9 @@ func (to *Session) GetServerDetailsByHostName(hostName string) ([]tc.ServerDetai
 // DeleteServerByID DELETEs a Server by ID.
 func (to *Session) DeleteServerByID(id int) (tc.Alerts, ReqInf, error) {
 	route := fmt.Sprintf("%s/%d", API_SERVERS, id)
-	resp, remoteAddr, err := to.request(http.MethodDelete, route, nil, nil)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-	}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
 	var alerts tc.Alerts
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
-	return alerts, reqInf, nil
+	reqInf, err := to.del(route, nil, &alerts)
+	return alerts, reqInf, err
 }
 
 func (to *Session) GetServerFQDNWithHdr(n string, header http.Header) (string, tc.Alerts, ReqInf, error) {
@@ -300,7 +224,7 @@ func (to *Session) GetServerFQDNWithHdr(n string, header http.Header) (string, t
 	params := url.Values{}
 	params.Add("hostName", n)
 
-	resp, reqInf, err := to.GetServersWithHdr(&params, nil)
+	resp, reqInf, err := to.GetServersWithHdr(&params, header)
 	if err != nil {
 		return "", resp.Alerts, reqInf, err
 	}
@@ -328,7 +252,7 @@ func (to *Session) GetServerFQDN(n string) (string, tc.Alerts, ReqInf, error) {
 
 func (to *Session) GetServersShortNameSearchWithHdr(shortname string, header http.Header) ([]string, tc.Alerts, ReqInf, error) {
 	var serverlst []string
-	resp, reqInf, err := to.GetServersWithHdr(nil, nil)
+	resp, reqInf, err := to.GetServersWithHdr(nil, header)
 	if err != nil {
 		return serverlst, resp.Alerts, reqInf, err
 	}
@@ -360,46 +284,16 @@ func (to *Session) GetServersShortNameSearch(shortname string) ([]string, tc.Ale
 // assignments to the server will be replaced.
 func (to *Session) AssignDeliveryServiceIDsToServerID(server int, dsIDs []int, replace bool) (tc.Alerts, ReqInf, error) {
 	// datatypes here match the library tc.Server's and tc.DeliveryService's ID fields
-
-	var remoteAddr net.Addr
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-
 	endpoint := fmt.Sprintf(API_SERVER_ASSIGN_DELIVERY_SERVICES, server, replace)
-
-	reqBody, err := json.Marshal(dsIDs)
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-
-	resp, remoteAddr, err := to.request(http.MethodPost, endpoint, reqBody, nil)
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-	}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer log.Close(resp.Body, "unable to close response body")
-	reqInf.RemoteAddr = remoteAddr
 	var alerts tc.Alerts
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
+	reqInf, err := to.post(endpoint, dsIDs, nil, &alerts)
 	return alerts, reqInf, err
 }
 
 func (to *Session) GetServerIDDeliveryServicesWithHdr(server int, header http.Header) ([]tc.DeliveryServiceNullable, ReqInf, error) {
 	endpoint := fmt.Sprintf(API_SERVER_DELIVERY_SERVICES, server)
-
-	resp, remoteAddr, err := to.request(http.MethodGet, endpoint, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	var data tc.DeliveryServicesNullableResponse
-	err = json.NewDecoder(resp.Body).Decode(&data)
+	reqInf, err := to.get(endpoint, header, &data)
 	return data.Response, reqInf, err
 }
 
@@ -412,15 +306,9 @@ func (to *Session) GetServerIDDeliveryServices(server int) ([]tc.DeliveryService
 
 func (to *Session) GetServerUpdateStatusWithHdr(hostName string, header http.Header) (tc.ServerUpdateStatus, ReqInf, error) {
 	path := API_SERVERS + `/` + hostName + `/update_status`
-	resp, remoteAddr, err := to.request(http.MethodGet, path, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.ServerUpdateStatus{}, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	data := []tc.ServerUpdateStatus{}
-	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
+	reqInf, err := to.get(path, header, &data)
+	if err != nil {
 		return tc.ServerUpdateStatus{}, reqInf, err
 	}
 	if len(data) == 0 {
diff --git a/traffic_ops/v3-client/server_server_capabilities.go b/traffic_ops/v3-client/server_server_capabilities.go
index 10e9385..2f3eea6 100644
--- a/traffic_ops/v3-client/server_server_capabilities.go
+++ b/traffic_ops/v3-client/server_server_capabilities.go
@@ -16,9 +16,7 @@
 package client
 
 import (
-	"encoding/json"
 	"fmt"
-	"net"
 	"net/http"
 	"net/url"
 	"strconv"
@@ -33,13 +31,7 @@ const (
 // CreateServerServerCapability assigns a Server Capability to a Server
 func (to *Session) CreateServerServerCapability(ssc tc.ServerServerCapability) (tc.Alerts, ReqInf, error) {
 	var alerts tc.Alerts
-	var remoteAddr net.Addr
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	reqBody, err := json.Marshal(ssc)
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	reqInf, err = post(to, API_SERVER_SERVER_CAPABILITIES, reqBody, &alerts)
+	reqInf, err := to.post(API_SERVER_SERVER_CAPABILITIES, ssc, nil, &alerts)
 	return alerts, reqInf, err
 }
 
@@ -51,7 +43,7 @@ func (to *Session) DeleteServerServerCapability(serverID int, serverCapability s
 	v.Add("serverCapability", serverCapability)
 	qStr := v.Encode()
 	queryURL := fmt.Sprintf("%s?%s", API_SERVER_SERVER_CAPABILITIES, qStr)
-	reqInf, err := del(to, queryURL, &alerts)
+	reqInf, err := to.del(queryURL, nil, &alerts)
 	return alerts, reqInf, err
 }
 
@@ -74,11 +66,8 @@ func (to *Session) GetServerServerCapabilitiesWithHdr(serverID *int, serverHostN
 	resp := struct {
 		Response []tc.ServerServerCapability `json:"response"`
 	}{}
-	reqInf, err := get(to, queryURL, &resp, header)
-	if err != nil {
-		return nil, reqInf, err
-	}
-	return resp.Response, reqInf, nil
+	reqInf, err := to.get(queryURL, header, &resp)
+	return resp.Response, reqInf, err
 }
 
 // GetServerServerCapabilities retrieves a list of Server Capabilities that are assigned to a Server
diff --git a/traffic_ops/v3-client/server_update_status.go b/traffic_ops/v3-client/server_update_status.go
index 9e74aec..a47f7ae 100644
--- a/traffic_ops/v3-client/server_update_status.go
+++ b/traffic_ops/v3-client/server_update_status.go
@@ -16,10 +16,8 @@
 package client
 
 import (
-	"encoding/json"
 	"errors"
 	"fmt"
-	"net/http"
 	"strconv"
 	"strings"
 
@@ -28,26 +26,12 @@ import (
 
 // UpdateServerStatus updates a server's status and returns the response.
 func (to *Session) UpdateServerStatus(serverID int, req tc.ServerPutStatus) (*tc.Alerts, ReqInf, error) {
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss}
-
-	reqBody, err := json.Marshal(req)
-	if err != nil {
-		return nil, reqInf, err
-	}
-
 	path := fmt.Sprintf("%s/servers/%d/status", apiBase, serverID)
-	resp, remoteAddr, err := to.request(http.MethodPut, path, reqBody, nil)
-	reqInf.RemoteAddr = remoteAddr
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	alerts := tc.Alerts{}
-	if err = json.NewDecoder(resp.Body).Decode(&alerts); err != nil {
+	reqInf, err := to.put(path, req, nil, &alerts)
+	if err != nil {
 		return nil, reqInf, err
 	}
-
 	return &alerts, reqInf, nil
 }
 
@@ -58,27 +42,10 @@ var queueUpdateActions = map[bool]string{
 
 // SetServerQueueUpdate updates a server's status and returns the response.
 func (to *Session) SetServerQueueUpdate(serverID int, queueUpdate bool) (tc.ServerQueueUpdateResponse, ReqInf, error) {
-	var (
-		req    = tc.ServerQueueUpdateRequest{Action: queueUpdateActions[queueUpdate]}
-		reqInf = ReqInf{CacheHitStatus: CacheHitStatusMiss}
-		resp   tc.ServerQueueUpdateResponse
-	)
-
-	reqBody, err := json.Marshal(req)
-	if err != nil {
-		return resp, reqInf, err
-	}
-
+	req := tc.ServerQueueUpdateRequest{Action: queueUpdateActions[queueUpdate]}
+	resp := tc.ServerQueueUpdateResponse{}
 	path := fmt.Sprintf("%s/servers/%d/queue_update", apiBase, serverID)
-	httpResp, remoteAddr, err := to.request(http.MethodPost, path, reqBody, nil)
-	reqInf.RemoteAddr = remoteAddr
-	if err != nil {
-		return resp, reqInf, err
-	}
-	defer httpResp.Body.Close()
-
-	err = json.NewDecoder(httpResp.Body).Decode(&resp)
-
+	reqInf, err := to.post(path, req, nil, &resp)
 	return resp, reqInf, err
 }
 
@@ -99,12 +66,7 @@ func (to *Session) SetUpdateServerStatuses(serverName string, updateStatus *bool
 		queryParams = append(queryParams, `reval_updated=`+strconv.FormatBool(*revalStatus))
 	}
 	path += strings.Join(queryParams, `&`)
-
-	resp, remoteAddr, err := to.request(http.MethodPost, path, nil, nil)
-	reqInf.RemoteAddr = remoteAddr
-	if err != nil {
-		return reqInf, err
-	}
-	resp.Body.Close()
-	return reqInf, nil
+	alerts := tc.Alerts{}
+	reqInf, err := to.post(path, nil, nil, &alerts)
+	return reqInf, err
 }
diff --git a/traffic_ops/v3-client/servercapability.go b/traffic_ops/v3-client/servercapability.go
index 0593708..4bce48d 100644
--- a/traffic_ops/v3-client/servercapability.go
+++ b/traffic_ops/v3-client/servercapability.go
@@ -16,9 +16,7 @@
 package client
 
 import (
-	"encoding/json"
 	"fmt"
-	"net"
 	"net/http"
 	"net/url"
 
@@ -31,44 +29,18 @@ const (
 
 // CreateServerCapability creates a server capability and returns the response.
 func (to *Session) CreateServerCapability(sc tc.ServerCapability) (*tc.ServerCapabilityDetailResponse, ReqInf, error) {
-	var remoteAddr net.Addr
-	reqBody, err := json.Marshal(sc)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	resp, remoteAddr, err := to.request(http.MethodPost, API_SERVER_CAPABILITIES, reqBody, nil)
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
 	var scResp tc.ServerCapabilityDetailResponse
-	if err = json.NewDecoder(resp.Body).Decode(&scResp); err != nil {
+	reqInf, err := to.post(API_SERVER_CAPABILITIES, sc, nil, &scResp)
+	if err != nil {
 		return nil, reqInf, err
 	}
 	return &scResp, reqInf, nil
 }
 
 func (to *Session) GetServerCapabilitiesWithHdr(header http.Header) ([]tc.ServerCapability, ReqInf, error) {
-	resp, remoteAddr, err := to.request(http.MethodGet, API_SERVER_CAPABILITIES, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.ServerCapability{}, reqInf, nil
-		}
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	var data tc.ServerCapabilitiesResponse
-	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
-		return nil, reqInf, err
-	}
-
-	return data.Response, reqInf, nil
+	reqInf, err := to.get(API_SERVER_CAPABILITIES, header, &data)
+	return data.Response, reqInf, err
 }
 
 // GetServerCapabilities returns all the server capabilities.
@@ -79,24 +51,11 @@ func (to *Session) GetServerCapabilities() ([]tc.ServerCapability, ReqInf, error
 
 func (to *Session) GetServerCapabilityWithHdr(name string, header http.Header) (*tc.ServerCapability, ReqInf, error) {
 	reqUrl := fmt.Sprintf("%s?name=%s", API_SERVER_CAPABILITIES, url.QueryEscape(name))
-	resp, remoteAddr, err := to.request(http.MethodGet, reqUrl, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return nil, reqInf, nil
-		}
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	var data tc.ServerCapabilitiesResponse
-	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
+	reqInf, err := to.get(reqUrl, header, &data)
+	if err != nil {
 		return nil, reqInf, err
 	}
-
 	if len(data.Response) == 1 {
 		return &data.Response[0], reqInf, nil
 	}
@@ -112,15 +71,7 @@ func (to *Session) GetServerCapability(name string) (*tc.ServerCapability, ReqIn
 // DeleteServerCapability deletes the given server capability by name.
 func (to *Session) DeleteServerCapability(name string) (tc.Alerts, ReqInf, error) {
 	reqUrl := fmt.Sprintf("%s?name=%s", API_SERVER_CAPABILITIES, url.QueryEscape(name))
-	resp, remoteAddr, err := to.request(http.MethodDelete, reqUrl, nil, nil)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
 	var alerts tc.Alerts
-	if err = json.NewDecoder(resp.Body).Decode(&alerts); err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	return alerts, reqInf, nil
+	reqInf, err := to.del(reqUrl, nil, &alerts)
+	return alerts, reqInf, err
 }
diff --git a/traffic_ops/v3-client/servercheck.go b/traffic_ops/v3-client/servercheck.go
index 9d981f4..b08f3a7 100644
--- a/traffic_ops/v3-client/servercheck.go
+++ b/traffic_ops/v3-client/servercheck.go
@@ -16,9 +16,6 @@
 package client
 
 import (
-	"encoding/json"
-	"net"
-
 	"github.com/apache/trafficcontrol/lib/go-tc"
 )
 
@@ -27,14 +24,8 @@ const API_SERVERCHECK = apiBase + "/servercheck"
 // InsertServerCheckStatus Will insert/update the servercheck value based on if it already exists or not.
 func (to *Session) InsertServerCheckStatus(status tc.ServercheckRequestNullable) (*tc.ServercheckPostResponse, ReqInf, error) {
 	uri := API_SERVERCHECK
-	var remoteAddr net.Addr
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	jsonReq, err := json.Marshal(status)
-	if err != nil {
-		return nil, reqInf, err
-	}
 	resp := tc.ServercheckPostResponse{}
-	reqInf, err = post(to, uri, jsonReq, &resp)
+	reqInf, err := to.post(uri, status, nil, &resp)
 	if err != nil {
 		return nil, reqInf, err
 	}
@@ -47,7 +38,6 @@ func (to *Session) GetServersChecks() ([]tc.GenericServerCheck, tc.Alerts, ReqIn
 		tc.Alerts
 		Response []tc.GenericServerCheck `json:"response"`
 	}
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss}
-	reqInf, err := get(to, API_SERVERCHECK, &response, nil)
+	reqInf, err := to.get(API_SERVERCHECK, nil, &response)
 	return response.Response, response.Alerts, reqInf, err
 }
diff --git a/traffic_ops/v3-client/servercheckextensions.go b/traffic_ops/v3-client/servercheckextensions.go
index 8676da1..5d21011 100644
--- a/traffic_ops/v3-client/servercheckextensions.go
+++ b/traffic_ops/v3-client/servercheckextensions.go
@@ -13,10 +13,7 @@
 package client
 
 import (
-	"encoding/json"
 	"fmt"
-	"net"
-	"net/http"
 
 	"github.com/apache/trafficcontrol/lib/go-tc"
 )
@@ -25,45 +22,22 @@ const API_TO_EXTENSION = apiBase + "/servercheck/extensions"
 
 // CreateServerCheckExtension creates a servercheck extension.
 func (to *Session) CreateServerCheckExtension(ServerCheckExtension tc.ServerCheckExtensionNullable) (tc.Alerts, ReqInf, error) {
-	var remoteAddr net.Addr
-	reqBody, err := json.Marshal(ServerCheckExtension)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	resp, remoteAddr, err := to.request(http.MethodPost, API_TO_EXTENSION, reqBody, nil)
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
 	var alerts tc.Alerts
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
+	reqInf, err := to.post(API_TO_EXTENSION, ServerCheckExtension, nil, &alerts)
 	return alerts, reqInf, err
 }
 
 // DeleteServerCheckExtension deletes a servercheck extension.
 func (to *Session) DeleteServerCheckExtension(id int) (tc.Alerts, ReqInf, error) {
 	URI := fmt.Sprintf("%s/%d", API_TO_EXTENSION, id)
-	resp, remoteAddr, err := to.request(http.MethodDelete, URI, nil, nil)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
 	var alerts tc.Alerts
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
+	reqInf, err := to.del(URI, nil, &alerts)
 	return alerts, reqInf, err
 }
 
 // GetServerCheckExtensions gets all servercheck extensions.
 func (to *Session) GetServerCheckExtensions() (tc.ServerCheckExtensionResponse, ReqInf, error) {
-	resp, remoteAddr, err := to.request(http.MethodGet, API_TO_EXTENSION, nil, nil)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.ServerCheckExtensionResponse{}, reqInf, err
-	}
-	defer resp.Body.Close()
 	var toExtResp tc.ServerCheckExtensionResponse
-	err = json.NewDecoder(resp.Body).Decode(&toExtResp)
+	reqInf, err := to.get(API_TO_EXTENSION, nil, &toExtResp)
 	return toExtResp, reqInf, err
 }
diff --git a/traffic_ops/v3-client/serviceCategory.go b/traffic_ops/v3-client/serviceCategory.go
index 9330bb6..6f0374d 100644
--- a/traffic_ops/v3-client/serviceCategory.go
+++ b/traffic_ops/v3-client/serviceCategory.go
@@ -16,9 +16,7 @@
 package client
 
 import (
-	"encoding/json"
 	"fmt"
-	"net"
 	"net/http"
 	"net/url"
 
@@ -31,71 +29,25 @@ const (
 
 // CreateServiceCategory performs a post to create a service category.
 func (to *Session) CreateServiceCategory(serviceCategory tc.ServiceCategory) (tc.Alerts, ReqInf, error) {
-
-	var remoteAddr net.Addr
-	reqBody, err := json.Marshal(serviceCategory)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	resp, remoteAddr, err := to.request(http.MethodPost, API_SERVICE_CATEGORIES, reqBody, nil)
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
 	var alerts tc.Alerts
-	if err := json.NewDecoder(resp.Body).Decode(&alerts); err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	return alerts, reqInf, nil
+	reqInf, err := to.post(API_SERVICE_CATEGORIES, serviceCategory, nil, &alerts)
+	return alerts, reqInf, err
 }
 
 // UpdateServiceCategoryByName updates a service category by its unique name.
 func (to *Session) UpdateServiceCategoryByName(name string, serviceCategory tc.ServiceCategory, header http.Header) (tc.Alerts, ReqInf, error) {
-	var remoteAddr net.Addr
-	reqBody, err := json.Marshal(serviceCategory)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
 	route := fmt.Sprintf("%s/%s", API_SERVICE_CATEGORIES, name)
-	resp, remoteAddr, err := to.request(http.MethodPut, route, reqBody, header)
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		defer resp.Body.Close()
-	}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
 	var alerts tc.Alerts
-	if err := json.NewDecoder(resp.Body).Decode(&alerts); err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	return alerts, reqInf, nil
+	reqInf, err := to.put(route, serviceCategory, header, &alerts)
+	return alerts, reqInf, err
 }
 
 // GetServiceCategoriesWithHdr gets a list of service categories by the passed in url values and http headers.
 func (to *Session) GetServiceCategoriesWithHdr(values *url.Values, header http.Header) ([]tc.ServiceCategory, ReqInf, error) {
 	path := fmt.Sprintf("%s?%s", API_SERVICE_CATEGORIES, values.Encode())
-	resp, remoteAddr, err := to.request(http.MethodGet, path, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.ServiceCategory{}, reqInf, nil
-		}
-	}
-	defer resp.Body.Close()
-
 	var data tc.ServiceCategoriesResponse
-	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
-		return nil, reqInf, err
-	}
-
-	return data.Response, reqInf, nil
+	reqInf, err := to.get(path, header, &data)
+	return data.Response, reqInf, err
 }
 
 // GetServiceCategories gets a list of service categories by the passed in url values.
@@ -107,15 +59,7 @@ func (to *Session) GetServiceCategories(values *url.Values) ([]tc.ServiceCategor
 // category's unique name.
 func (to *Session) DeleteServiceCategoryByName(name string) (tc.Alerts, ReqInf, error) {
 	route := fmt.Sprintf("%s/%s", API_SERVICE_CATEGORIES, name)
-	resp, remoteAddr, err := to.request(http.MethodDelete, route, nil, nil)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
 	var alerts tc.Alerts
-	if err := json.NewDecoder(resp.Body).Decode(&alerts); err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	return alerts, reqInf, nil
+	reqInf, err := to.del(route, nil, &alerts)
+	return alerts, reqInf, err
 }
diff --git a/traffic_ops/v3-client/session.go b/traffic_ops/v3-client/session.go
index 632020d..8193e43 100644
--- a/traffic_ops/v3-client/session.go
+++ b/traffic_ops/v3-client/session.go
@@ -32,6 +32,7 @@ import (
 	"sync"
 	"time"
 
+	log "github.com/apache/trafficcontrol/lib/go-log"
 	tc "github.com/apache/trafficcontrol/lib/go-tc"
 
 	"golang.org/x/net/publicsuffix"
@@ -124,8 +125,8 @@ func (to *Session) login() (net.Addr, error) {
 	}
 
 	path := apiBase + "/user/login"
-	resp, remoteAddr, err := to.RawRequest("POST", path, credentials)
-	resp, remoteAddr, err = to.ErrUnlessOKOrNotModified(resp, remoteAddr, err, path)
+	resp, remoteAddr, err := to.RawRequestWithHdr("POST", path, credentials, nil)
+	resp, remoteAddr, err = to.errUnlessOKOrNotModified(resp, remoteAddr, err, path)
 	if err != nil {
 		return remoteAddr, errors.New("requesting: " + err.Error())
 	}
@@ -153,8 +154,8 @@ func (to *Session) login() (net.Addr, error) {
 
 func (to *Session) loginWithToken(token []byte) (net.Addr, error) {
 	path := apiBase + "/user/login/token"
-	resp, remoteAddr, err := to.RawRequest(http.MethodPost, path, token)
-	resp, remoteAddr, err = to.ErrUnlessOKOrNotModified(resp, remoteAddr, err, path)
+	resp, remoteAddr, err := to.RawRequestWithHdr(http.MethodPost, path, token, nil)
+	resp, remoteAddr, err = to.errUnlessOKOrNotModified(resp, remoteAddr, err, path)
 	if err != nil {
 		return remoteAddr, fmt.Errorf("requesting: %v", err)
 	}
@@ -182,8 +183,8 @@ func (to *Session) logout() (net.Addr, error) {
 	}
 
 	path := apiBase + "/user/logout"
-	resp, remoteAddr, err := to.RawRequest("POST", path, credentials)
-	resp, remoteAddr, err = to.ErrUnlessOKOrNotModified(resp, remoteAddr, err, path)
+	resp, remoteAddr, err := to.RawRequestWithHdr("POST", path, credentials, nil)
+	resp, remoteAddr, err = to.errUnlessOKOrNotModified(resp, remoteAddr, err, path)
 	if err != nil {
 		return remoteAddr, errors.New("requesting: " + err.Error())
 	}
@@ -307,10 +308,10 @@ func NewNoAuthSession(toURL string, insecure bool, userAgent string, useCache bo
 	}, useCache)
 }
 
-// ErrUnlessOKOrNotModified returns the response, the remote address, and an error if the given Response's status code is anything
+// errUnlessOKOrNotModified returns the response, the remote address, and an error if the given Response's status code is anything
 // but 200 OK/ 304 Not Modified. This includes reading the Response.Body and Closing it. Otherwise, the given response, the remote
 // address, and a nil error are returned.
-func (to *Session) ErrUnlessOKOrNotModified(resp *http.Response, remoteAddr net.Addr, err error, path string) (*http.Response, net.Addr, error) {
+func (to *Session) errUnlessOKOrNotModified(resp *http.Response, remoteAddr net.Addr, err error, path string) (*http.Response, net.Addr, error) {
 	if err != nil {
 		return resp, remoteAddr, err
 	}
@@ -333,6 +334,53 @@ func (to *Session) ErrUnlessOKOrNotModified(resp *http.Response, remoteAddr net.
 
 func (to *Session) getURL(path string) string { return to.URL + path }
 
+// makeRequestWithHeader marshals the response body (if non-nil), performs the HTTP request,
+// and decodes the response into the given response pointer.
+func (to *Session) makeRequestWithHeader(method, path string, body interface{}, header http.Header, response interface{}) (ReqInf, error) {
+	var remoteAddr net.Addr
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	var reqBody []byte
+	var err error
+	if body != nil {
+		reqBody, err = json.Marshal(body)
+		if err != nil {
+			return reqInf, errors.New("marshalling request body: " + err.Error())
+		}
+	}
+	resp, remoteAddr, err := to.request(method, path, reqBody, header)
+	reqInf.RemoteAddr = remoteAddr
+	if resp != nil {
+		reqInf.StatusCode = resp.StatusCode
+		if reqInf.StatusCode == http.StatusNotModified {
+			return reqInf, nil
+		}
+		defer log.Close(resp.Body, "unable to close response body")
+	}
+	if err != nil {
+		return reqInf, errors.New("requesting from Traffic Ops: " + err.Error())
+	}
+	if err := json.NewDecoder(resp.Body).Decode(response); err != nil {
+		return reqInf, errors.New("decoding response body: " + err.Error())
+	}
+	return reqInf, nil
+}
+
+func (to *Session) get(path string, header http.Header, response interface{}) (ReqInf, error) {
+	return to.makeRequestWithHeader(http.MethodGet, path, nil, header, response)
+}
+
+func (to *Session) post(path string, body interface{}, header http.Header, response interface{}) (ReqInf, error) {
+	return to.makeRequestWithHeader(http.MethodPost, path, body, header, response)
+}
+
+func (to *Session) put(path string, body interface{}, header http.Header, response interface{}) (ReqInf, error) {
+	return to.makeRequestWithHeader(http.MethodPut, path, body, header, response)
+}
+
+func (to *Session) del(path string, header http.Header, response interface{}) (ReqInf, error) {
+	return to.makeRequestWithHeader(http.MethodDelete, path, nil, header, response)
+}
+
 // request performs the HTTP request to Traffic Ops, trying to refresh the cookie if an Unauthorized or Forbidden code is received. It only tries once. If the login fails, the original Unauthorized/Forbidden response is returned. If the login succeeds and the subsequent re-request fails, the re-request's response is returned even if it's another Unauthorized/Forbidden.
 // Returns the response, the remote address of the Traffic Ops instance used, and any error.
 // The returned net.Addr is guaranteed to be either nil or valid, even if the returned error is not nil. Callers are encouraged to check and use the net.Addr if an error is returned, and use the remote address in their own error messages. This violates the Go idiom that a non-nil error implies all other values are undefined, but it's more straightforward than alternatives like typecasting.
@@ -342,15 +390,15 @@ func (to *Session) request(method, path string, body []byte, header http.Header)
 		return r, remoteAddr, err
 	}
 	if r.StatusCode != http.StatusUnauthorized && r.StatusCode != http.StatusForbidden {
-		return to.ErrUnlessOKOrNotModified(r, remoteAddr, err, path)
+		return to.errUnlessOKOrNotModified(r, remoteAddr, err, path)
 	}
 	if _, lerr := to.login(); lerr != nil {
-		return to.ErrUnlessOKOrNotModified(r, remoteAddr, err, path) // if re-logging-in fails, return the original request's response
+		return to.errUnlessOKOrNotModified(r, remoteAddr, err, path) // if re-logging-in fails, return the original request's response
 	}
 
 	// return second request, even if it's another Unauthorized or Forbidden.
 	r, remoteAddr, err = to.RawRequestWithHdr(method, path, body, header)
-	return to.ErrUnlessOKOrNotModified(r, remoteAddr, err, path)
+	return to.errUnlessOKOrNotModified(r, remoteAddr, err, path)
 }
 
 func (to *Session) RawRequestWithHdr(method, path string, body []byte, header http.Header) (*http.Response, net.Addr, error) {
@@ -387,11 +435,7 @@ func (to *Session) RawRequestWithHdr(method, path string, body []byte, header ht
 	req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace))
 	req.Header.Set("User-Agent", to.UserAgentStr)
 	resp, err := to.Client.Do(req)
-	if err != nil {
-		return resp, remoteAddr, err
-	}
-
-	return resp, remoteAddr, nil
+	return resp, remoteAddr, err
 }
 
 // RawRequest performs the actual HTTP request to Traffic Ops, simply, without trying to refresh the cookie if an Unauthorized code is returned.
diff --git a/traffic_ops/v3-client/staticdnsentry.go b/traffic_ops/v3-client/staticdnsentry.go
index 3315113..8a4ff61 100644
--- a/traffic_ops/v3-client/staticdnsentry.go
+++ b/traffic_ops/v3-client/staticdnsentry.go
@@ -16,11 +16,10 @@
 package client
 
 import (
-	"encoding/json"
 	"errors"
 	"fmt"
-	"net"
 	"net/http"
+	"net/url"
 
 	"github.com/apache/trafficcontrol/lib/go-tc"
 )
@@ -31,7 +30,7 @@ const (
 
 func staticDNSEntryIDs(to *Session, sdns *tc.StaticDNSEntry) error {
 	if sdns.CacheGroupID == 0 && sdns.CacheGroupName != "" {
-		p, _, err := to.GetCacheGroupNullableByName(sdns.CacheGroupName)
+		p, _, err := to.GetCacheGroupNullableByNameWithHdr(sdns.CacheGroupName, nil)
 		if err != nil {
 			return err
 		}
@@ -45,7 +44,7 @@ func staticDNSEntryIDs(to *Session, sdns *tc.StaticDNSEntry) error {
 	}
 
 	if sdns.DeliveryServiceID == 0 && sdns.DeliveryService != "" {
-		dses, _, err := to.GetDeliveryServiceByXMLIDNullable(sdns.DeliveryService)
+		dses, _, err := to.GetDeliveryServiceByXMLIDNullableWithHdr(sdns.DeliveryService, nil)
 		if err != nil {
 			return err
 		}
@@ -59,7 +58,7 @@ func staticDNSEntryIDs(to *Session, sdns *tc.StaticDNSEntry) error {
 	}
 
 	if sdns.TypeID == 0 && sdns.Type != "" {
-		types, _, err := to.GetTypeByName(sdns.Type)
+		types, _, err := to.GetTypeByNameWithHdr(sdns.Type, nil)
 		if err != nil {
 			return err
 		}
@@ -75,43 +74,25 @@ func staticDNSEntryIDs(to *Session, sdns *tc.StaticDNSEntry) error {
 // CreateStaticDNSEntry creates a Static DNS Entry.
 func (to *Session) CreateStaticDNSEntry(sdns tc.StaticDNSEntry) (tc.Alerts, ReqInf, error) {
 	// fill in missing IDs from names
-	staticDNSEntryIDs(to, &sdns)
-	var remoteAddr net.Addr
-	reqBody, err := json.Marshal(sdns)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	resp, remoteAddr, err := to.request(http.MethodPost, API_STATIC_DNS_ENTRIES, reqBody, nil)
+	var alerts tc.Alerts
+	err := staticDNSEntryIDs(to, &sdns)
 	if err != nil {
-		return tc.Alerts{}, reqInf, err
+		return alerts, ReqInf{CacheHitStatus: CacheHitStatusMiss}, err
 	}
-	defer resp.Body.Close()
-	var alerts tc.Alerts
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
-	return alerts, reqInf, nil
+	reqInf, err := to.post(API_STATIC_DNS_ENTRIES, sdns, nil, &alerts)
+	return alerts, reqInf, err
 }
 
 func (to *Session) UpdateStaticDNSEntryByIDWithHdr(id int, sdns tc.StaticDNSEntry, header http.Header) (tc.Alerts, ReqInf, int, error) {
 	// fill in missing IDs from names
-	staticDNSEntryIDs(to, &sdns)
-	var remoteAddr net.Addr
-	reqBody, err := json.Marshal(sdns)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	var alerts tc.Alerts
+	err := staticDNSEntryIDs(to, &sdns)
 	if err != nil {
-		return tc.Alerts{}, reqInf, 0, err
+		return alerts, ReqInf{CacheHitStatus: CacheHitStatusMiss}, 0, err
 	}
 	route := fmt.Sprintf("%s?id=%d", API_STATIC_DNS_ENTRIES, id)
-	resp, remoteAddr, errClient := to.RawRequestWithHdr(http.MethodPut, route, reqBody, header)
-	if resp != nil {
-		defer resp.Body.Close()
-		var alerts tc.Alerts
-		if err = json.NewDecoder(resp.Body).Decode(&alerts); err != nil {
-			return alerts, reqInf, resp.StatusCode, err
-		}
-		return alerts, reqInf, resp.StatusCode, errClient
-	}
-	return tc.Alerts{}, reqInf, 0, errClient
+	reqInf, err := to.put(route, sdns, header, &alerts)
+	return tc.Alerts{}, reqInf, reqInf.StatusCode, err
 }
 
 // UpdateStaticDNSEntryByID updates a Static DNS Entry by ID.
@@ -121,22 +102,9 @@ func (to *Session) UpdateStaticDNSEntryByID(id int, sdns tc.StaticDNSEntry) (tc.
 }
 
 func (to *Session) GetStaticDNSEntriesWithHdr(header http.Header) ([]tc.StaticDNSEntry, ReqInf, error) {
-	resp, remoteAddr, err := to.request(http.MethodGet, API_STATIC_DNS_ENTRIES, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.StaticDNSEntry{}, reqInf, nil
-		}
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	var data tc.StaticDNSEntriesResponse
-	err = json.NewDecoder(resp.Body).Decode(&data)
-	return data.Response, reqInf, nil
+	reqInf, err := to.get(API_STATIC_DNS_ENTRIES, header, &data)
+	return data.Response, reqInf, err
 }
 
 // GetStaticDNSEntries returns a list of Static DNS Entrys.
@@ -147,25 +115,9 @@ func (to *Session) GetStaticDNSEntries() ([]tc.StaticDNSEntry, ReqInf, error) {
 
 func (to *Session) GetStaticDNSEntryByIDWithHdr(id int, header http.Header) ([]tc.StaticDNSEntry, ReqInf, error) {
 	route := fmt.Sprintf("%s?id=%d", API_STATIC_DNS_ENTRIES, id)
-	resp, remoteAddr, err := to.request(http.MethodGet, route, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.StaticDNSEntry{}, reqInf, nil
-		}
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	var data tc.StaticDNSEntriesResponse
-	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
-		return nil, reqInf, err
-	}
-
-	return data.Response, reqInf, nil
+	reqInf, err := to.get(route, header, &data)
+	return data.Response, reqInf, err
 }
 
 // GetStaticDNSEntryByID GETs a Static DNS Entry by the Static DNS Entry's ID.
@@ -175,26 +127,10 @@ func (to *Session) GetStaticDNSEntryByID(id int) ([]tc.StaticDNSEntry, ReqInf, e
 }
 
 func (to *Session) GetStaticDNSEntriesByHostWithHdr(host string, header http.Header) ([]tc.StaticDNSEntry, ReqInf, error) {
-	url := fmt.Sprintf("%s?host=%s", API_STATIC_DNS_ENTRIES, host)
-	resp, remoteAddr, err := to.request(http.MethodGet, url, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.StaticDNSEntry{}, reqInf, nil
-		}
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
+	route := fmt.Sprintf("%s?host=%s", API_STATIC_DNS_ENTRIES, url.QueryEscape(host))
 	var data tc.StaticDNSEntriesResponse
-	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
-		return nil, reqInf, err
-	}
-
-	return data.Response, reqInf, nil
+	reqInf, err := to.get(route, header, &data)
+	return data.Response, reqInf, err
 }
 
 // GetStaticDNSEntriesByHost GETs a Static DNS Entry by the Static DNS Entry's host.
@@ -206,13 +142,7 @@ func (to *Session) GetStaticDNSEntriesByHost(host string) ([]tc.StaticDNSEntry,
 // DeleteStaticDNSEntryByID DELETEs a Static DNS Entry by ID.
 func (to *Session) DeleteStaticDNSEntryByID(id int) (tc.Alerts, ReqInf, error) {
 	route := fmt.Sprintf("%s?id=%d", API_STATIC_DNS_ENTRIES, id)
-	resp, remoteAddr, err := to.request(http.MethodDelete, route, nil, nil)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
 	var alerts tc.Alerts
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
-	return alerts, reqInf, nil
+	reqInf, err := to.del(route, nil, &alerts)
+	return alerts, reqInf, err
 }
diff --git a/traffic_ops/v3-client/stats_summary.go b/traffic_ops/v3-client/stats_summary.go
index c7e09a2..41a8ae7 100644
--- a/traffic_ops/v3-client/stats_summary.go
+++ b/traffic_ops/v3-client/stats_summary.go
@@ -13,9 +13,7 @@
 package client
 
 import (
-	"encoding/json"
 	"fmt"
-	"net"
 	"net/url"
 
 	tc "github.com/apache/trafficcontrol/lib/go-tc"
@@ -40,11 +38,11 @@ func (to *Session) GetSummaryStats(cdn, deliveryService, statName *string) (tc.S
 		param.Add("statName", *statName)
 	}
 
-	url := API_STATS_SUMMARY
+	route := API_STATS_SUMMARY
 	if len(param) > 0 {
-		url = fmt.Sprintf("%s?%s", API_STATS_SUMMARY, param.Encode())
+		route = fmt.Sprintf("%s?%s", API_STATS_SUMMARY, param.Encode())
 	}
-	reqInf, err := get(to, url, &resp, nil)
+	reqInf, err := to.get(route, nil, &resp)
 	return resp, reqInf, err
 }
 
@@ -57,21 +55,15 @@ func (to *Session) GetSummaryStatsLastUpdated(statName *string) (tc.StatsSummary
 	if statName != nil {
 		param.Add("statName", *statName)
 	}
-	url := fmt.Sprintf("%s?%s", API_STATS_SUMMARY, param.Encode())
+	route := fmt.Sprintf("%s?%s", API_STATS_SUMMARY, param.Encode())
 
-	reqInf, err := get(to, url, &resp, nil)
+	reqInf, err := to.get(route, nil, &resp)
 	return resp, reqInf, err
 }
 
 // CreateSummaryStats creates a stats summary
 func (to *Session) CreateSummaryStats(statsSummary tc.StatsSummary) (tc.Alerts, ReqInf, error) {
 	var alerts tc.Alerts
-	var remoteAddr net.Addr
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	reqBody, err := json.Marshal(statsSummary)
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	reqInf, err = post(to, API_STATS_SUMMARY, reqBody, &alerts)
+	reqInf, err := to.post(API_STATS_SUMMARY, statsSummary, nil, &alerts)
 	return alerts, reqInf, err
 }
diff --git a/traffic_ops/v3-client/status.go b/traffic_ops/v3-client/status.go
index 8ec0ba8..a7ec127 100644
--- a/traffic_ops/v3-client/status.go
+++ b/traffic_ops/v3-client/status.go
@@ -16,10 +16,9 @@
 package client
 
 import (
-	"encoding/json"
 	"fmt"
-	"net"
 	"net/http"
+	"net/url"
 
 	"github.com/apache/trafficcontrol/lib/go-tc"
 )
@@ -30,43 +29,16 @@ const (
 
 // CreateStatusNullable creates a new status, using the tc.StatusNullable structure.
 func (to *Session) CreateStatusNullable(status tc.StatusNullable) (tc.Alerts, ReqInf, error) {
-
-	var remoteAddr net.Addr
-	reqBody, err := json.Marshal(status)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	resp, remoteAddr, err := to.request(http.MethodPost, API_STATUSES, reqBody, nil)
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
 	var alerts tc.Alerts
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
-	return alerts, reqInf, nil
+	reqInf, err := to.post(API_STATUSES, status, nil, &alerts)
+	return alerts, reqInf, err
 }
 
 func (to *Session) UpdateStatusByIDWithHdr(id int, status tc.Status, header http.Header) (tc.Alerts, ReqInf, error) {
-
-	var remoteAddr net.Addr
-	reqBody, err := json.Marshal(status)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
 	route := fmt.Sprintf("%s/%d", API_STATUSES, id)
-	resp, remoteAddr, err := to.request(http.MethodPut, route, reqBody, header)
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-	}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
 	var alerts tc.Alerts
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
-	return alerts, reqInf, nil
+	reqInf, err := to.put(route, status, header, &alerts)
+	return alerts, reqInf, err
 }
 
 // UpdateStatusByID updates a Status by ID.
@@ -76,22 +48,9 @@ func (to *Session) UpdateStatusByID(id int, status tc.Status) (tc.Alerts, ReqInf
 }
 
 func (to *Session) GetStatusesWithHdr(header http.Header) ([]tc.Status, ReqInf, error) {
-	resp, remoteAddr, err := to.request(http.MethodGet, API_STATUSES, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.Status{}, reqInf, nil
-		}
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	var data tc.StatusesResponse
-	err = json.NewDecoder(resp.Body).Decode(&data)
-	return data.Response, reqInf, nil
+	reqInf, err := to.get(API_STATUSES, header, &data)
+	return data.Response, reqInf, err
 }
 
 // GetStatuses returns a list of Statuses.
@@ -102,25 +61,9 @@ func (to *Session) GetStatuses() ([]tc.Status, ReqInf, error) {
 
 func (to *Session) GetStatusByIDWithHdr(id int, header http.Header) ([]tc.Status, ReqInf, error) {
 	route := fmt.Sprintf("%s?id=%d", API_STATUSES, id)
-	resp, remoteAddr, err := to.request(http.MethodGet, route, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.Status{}, reqInf, nil
-		}
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	var data tc.StatusesResponse
-	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
-		return nil, reqInf, err
-	}
-
-	return data.Response, reqInf, nil
+	reqInf, err := to.get(route, header, &data)
+	return data.Response, reqInf, err
 }
 
 // GetStatusByID GETs a Status by the Status ID.
@@ -130,26 +73,10 @@ func (to *Session) GetStatusByID(id int) ([]tc.Status, ReqInf, error) {
 }
 
 func (to *Session) GetStatusByNameWithHdr(name string, header http.Header) ([]tc.Status, ReqInf, error) {
-	url := fmt.Sprintf("%s?name=%s", API_STATUSES, name)
-	resp, remoteAddr, err := to.request(http.MethodGet, url, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.Status{}, reqInf, nil
-		}
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
+	route := fmt.Sprintf("%s?name=%s", API_STATUSES, url.QueryEscape(name))
 	var data tc.StatusesResponse
-	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
-		return nil, reqInf, err
-	}
-
-	return data.Response, reqInf, nil
+	reqInf, err := to.get(route, header, &data)
+	return data.Response, reqInf, err
 }
 
 // GetStatusByName GETs a Status by the Status name.
@@ -161,13 +88,7 @@ func (to *Session) GetStatusByName(name string) ([]tc.Status, ReqInf, error) {
 // DeleteStatusByID DELETEs a Status by ID.
 func (to *Session) DeleteStatusByID(id int) (tc.Alerts, ReqInf, error) {
 	route := fmt.Sprintf("%s/%d", API_STATUSES, id)
-	resp, remoteAddr, err := to.request(http.MethodDelete, route, nil, nil)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
 	var alerts tc.Alerts
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
-	return alerts, reqInf, nil
+	reqInf, err := to.del(route, nil, &alerts)
+	return alerts, reqInf, err
 }
diff --git a/traffic_ops/v3-client/steering.go b/traffic_ops/v3-client/steering.go
index 9966a70..0602252 100644
--- a/traffic_ops/v3-client/steering.go
+++ b/traffic_ops/v3-client/steering.go
@@ -16,30 +16,16 @@
 package client
 
 import (
-	"encoding/json"
 	"net/http"
 
 	"github.com/apache/trafficcontrol/lib/go-tc"
 )
 
 func (to *Session) SteeringWithHdr(header http.Header) ([]tc.Steering, ReqInf, error) {
-	resp, remoteAddr, err := to.request(http.MethodGet, apiBase+`/steering`, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.Steering{}, reqInf, nil
-		}
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	data := struct {
 		Response []tc.Steering `json:"response"`
 	}{}
-	err = json.NewDecoder(resp.Body).Decode(&data)
+	reqInf, err := to.get(apiBase+`/steering`, header, &data)
 	return data.Response, reqInf, err
 }
 
diff --git a/traffic_ops/v3-client/steeringtarget.go b/traffic_ops/v3-client/steeringtarget.go
index c440382..807e5e2 100644
--- a/traffic_ops/v3-client/steeringtarget.go
+++ b/traffic_ops/v3-client/steeringtarget.go
@@ -16,31 +16,20 @@
 package client
 
 import (
-	"encoding/json"
 	"errors"
+	"fmt"
 	"net/http"
-	"strconv"
 
 	"github.com/apache/trafficcontrol/lib/go-tc"
 )
 
 func (to *Session) CreateSteeringTarget(st tc.SteeringTargetNullable) (tc.Alerts, ReqInf, error) {
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss}
 	if st.DeliveryServiceID == nil {
-		return tc.Alerts{}, reqInf, errors.New("missing delivery service id")
-	}
-	reqBody, err := json.Marshal(st)
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
+		return tc.Alerts{}, ReqInf{CacheHitStatus: CacheHitStatusMiss}, errors.New("missing delivery service id")
 	}
-
-	resp := (*http.Response)(nil)
-	if resp, reqInf.RemoteAddr, err = to.request(http.MethodPost, apiBase+`/steering/`+strconv.Itoa(int(*st.DeliveryServiceID))+`/targets`, reqBody, nil); err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
 	alerts := tc.Alerts{}
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
+	route := fmt.Sprintf("%s/steering/%d/targets", apiBase, *st.DeliveryServiceID)
+	reqInf, err := to.post(route, st, nil, &alerts)
 	return alerts, reqInf, err
 }
 
@@ -52,22 +41,9 @@ func (to *Session) UpdateSteeringTargetWithHdr(st tc.SteeringTargetNullable, hea
 	if st.TargetID == nil {
 		return tc.Alerts{}, reqInf, errors.New("missing target id")
 	}
-
-	reqBody, err := json.Marshal(st)
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	resp := (*http.Response)(nil)
-	resp, reqInf.RemoteAddr, err = to.request(http.MethodPut, apiBase+`/steering/`+strconv.Itoa(int(*st.DeliveryServiceID))+`/targets/`+strconv.Itoa(int(*st.TargetID)), reqBody, header)
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-	}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
+	route := fmt.Sprintf("%s/steering/%d/targets/%d", apiBase, *st.DeliveryServiceID, *st.TargetID)
 	alerts := tc.Alerts{}
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
+	reqInf, err := to.put(route, st, header, &alerts)
 	return alerts, reqInf, err
 }
 
@@ -77,28 +53,17 @@ func (to *Session) UpdateSteeringTarget(st tc.SteeringTargetNullable) (tc.Alerts
 }
 
 func (to *Session) GetSteeringTargets(dsID int) ([]tc.SteeringTargetNullable, ReqInf, error) {
-	resp, remoteAddr, err := to.request(http.MethodGet, apiBase+`/steering/`+strconv.Itoa(dsID)+`/targets`, nil, nil)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
+	route := fmt.Sprintf("%s/steering/%d/targets", apiBase, dsID)
 	data := struct {
 		Response []tc.SteeringTargetNullable `json:"response"`
 	}{}
-	err = json.NewDecoder(resp.Body).Decode(&data)
+	reqInf, err := to.get(route, nil, &data)
 	return data.Response, reqInf, err
 }
 
 func (to *Session) DeleteSteeringTarget(dsID int, targetID int) (tc.Alerts, ReqInf, error) {
-	resp, remoteAddr, err := to.request(http.MethodDelete, apiBase+`/steering/`+strconv.Itoa(dsID)+`/targets/`+strconv.Itoa(targetID), nil, nil)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
+	route := fmt.Sprintf("%s/steering/%d/targets/%d", apiBase, dsID, targetID)
 	alerts := tc.Alerts{}
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
+	reqInf, err := to.del(route, nil, &alerts)
 	return alerts, reqInf, err
 }
diff --git a/traffic_ops/v3-client/tenant.go b/traffic_ops/v3-client/tenant.go
index 49e021c..932a6a6 100644
--- a/traffic_ops/v3-client/tenant.go
+++ b/traffic_ops/v3-client/tenant.go
@@ -16,7 +16,6 @@
 package client
 
 import (
-	"encoding/json"
 	"errors"
 	"fmt"
 	"net/http"
@@ -26,19 +25,12 @@ import (
 )
 
 const API_TENANTS = apiBase + "/tenants"
-const API_TENANT_ID = API_TENANTS + "/%v"
+const API_TENANT_ID = API_TENANTS + "/%s"
 
 func (to *Session) TenantsWithHdr(header http.Header) ([]tc.Tenant, ReqInf, error) {
 	var data tc.GetTenantsResponse
-	reqInf, err := get(to, API_TENANTS, &data, header)
-	if reqInf.StatusCode == http.StatusNotModified {
-		return []tc.Tenant{}, reqInf, nil
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-
-	return data.Response, reqInf, nil
+	reqInf, err := to.get(API_TENANTS, header, &data)
+	return data.Response, reqInf, err
 }
 
 // Tenants gets an array of Tenants.
@@ -49,14 +41,13 @@ func (to *Session) Tenants() ([]tc.Tenant, ReqInf, error) {
 
 func (to *Session) TenantWithHdr(id string, header http.Header) (*tc.Tenant, ReqInf, error) {
 	var data tc.GetTenantsResponse
-	reqInf, err := get(to, fmt.Sprintf("%s?id=%v", API_TENANTS, id), &data, header)
-	if reqInf.StatusCode == http.StatusNotModified {
-		return nil, reqInf, nil
-	}
+	reqInf, err := to.get(fmt.Sprintf("%s?id=%v", API_TENANTS, id), header, &data)
 	if err != nil {
 		return nil, reqInf, err
 	}
-
+	if reqInf.StatusCode == http.StatusNotModified {
+		return nil, reqInf, nil
+	}
 	return &data.Response[0], reqInf, nil
 }
 
@@ -70,21 +61,18 @@ func (to *Session) Tenant(id string) (*tc.Tenant, ReqInf, error) {
 func (to *Session) TenantByNameWithHdr(name string, header http.Header) (*tc.Tenant, ReqInf, error) {
 	var data tc.GetTenantsResponse
 	query := API_TENANTS + "?name=" + url.QueryEscape(name)
-	reqInf, err := get(to, query, &data, header)
-	if reqInf.StatusCode == http.StatusNotModified {
-		return nil, reqInf, nil
-	}
+	reqInf, err := to.get(query, header, &data)
 	if err != nil {
 		return nil, reqInf, err
 	}
-
-	var ten *tc.Tenant
+	if reqInf.StatusCode == http.StatusNotModified {
+		return nil, reqInf, nil
+	}
 	if len(data.Response) > 0 {
-		ten = &data.Response[0]
+		return &data.Response[0], reqInf, nil
 	} else {
-		err = errors.New("no tenant found with name " + name)
+		return nil, reqInf, errors.New("no tenant found with name " + name)
 	}
-	return ten, reqInf, err
 }
 
 // TenantByName gets the Tenant with the name it's passed.
@@ -96,7 +84,7 @@ func (to *Session) TenantByName(name string) (*tc.Tenant, ReqInf, error) {
 // CreateTenant creates the Tenant it's passed.
 func (to *Session) CreateTenant(t *tc.Tenant) (*tc.TenantResponse, error) {
 	if t.ParentID == 0 && t.ParentName != "" {
-		tenant, _, err := to.TenantByName(t.ParentName)
+		tenant, _, err := to.TenantByNameWithHdr(t.ParentName, nil)
 		if err != nil {
 			return nil, err
 		}
@@ -107,29 +95,19 @@ func (to *Session) CreateTenant(t *tc.Tenant) (*tc.TenantResponse, error) {
 	}
 
 	var data tc.TenantResponse
-	jsonReq, err := json.Marshal(t)
-	if err != nil {
-		return nil, err
-	}
-	_, err = post(to, API_TENANTS, jsonReq, &data)
+	_, err := to.post(API_TENANTS, t, nil, &data)
 	if err != nil {
 		return nil, err
 	}
-
 	return &data, nil
 }
 
 func (to *Session) UpdateTenantWithHdr(id string, t *tc.Tenant, header http.Header) (*tc.TenantResponse, ReqInf, error) {
 	var data tc.TenantResponse
-	jsonReq, err := json.Marshal(t)
-	if err != nil {
-		return nil, ReqInf{}, err
-	}
-	reqInf, err := put(to, fmt.Sprintf(API_TENANT_ID, id), jsonReq, &data, header)
+	reqInf, err := to.put(fmt.Sprintf(API_TENANT_ID, id), t, header, &data)
 	if err != nil {
 		return nil, reqInf, err
 	}
-
 	return &data, reqInf, nil
 }
 
@@ -144,10 +122,9 @@ func (to *Session) UpdateTenant(id string, t *tc.Tenant) (*tc.TenantResponse, er
 // DeleteTenant deletes the Tenant matching the ID it's passed.
 func (to *Session) DeleteTenant(id string) (*tc.DeleteTenantResponse, error) {
 	var data tc.DeleteTenantResponse
-	_, err := del(to, fmt.Sprintf(API_TENANT_ID, id), &data)
+	_, err := to.del(fmt.Sprintf(API_TENANT_ID, id), nil, &data)
 	if err != nil {
 		return nil, err
 	}
-
 	return &data, nil
 }
diff --git a/traffic_ops/v3-client/topology.go b/traffic_ops/v3-client/topology.go
index 2a139c1..37c54ae 100644
--- a/traffic_ops/v3-client/topology.go
+++ b/traffic_ops/v3-client/topology.go
@@ -16,13 +16,10 @@
 package client
 
 import (
-	"encoding/json"
 	"fmt"
-	"net"
 	"net/http"
 	"net/url"
 
-	"github.com/apache/trafficcontrol/lib/go-log"
 	"github.com/apache/trafficcontrol/lib/go-tc"
 )
 
@@ -30,44 +27,15 @@ const ApiTopologies = apiBase + "/topologies"
 
 // CreateTopology creates a topology and returns the response.
 func (to *Session) CreateTopology(top tc.Topology) (*tc.TopologyResponse, ReqInf, error) {
-	var remoteAddr net.Addr
-	reqBody, err := json.Marshal(top)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	resp, remoteAddr, err := to.request(http.MethodPost, ApiTopologies, reqBody, nil)
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer log.Close(resp.Body, "unable to close response")
-	var topResp tc.TopologyResponse
-	if err = json.NewDecoder(resp.Body).Decode(&topResp); err != nil {
-		return nil, reqInf, err
-	}
-	return &topResp, reqInf, nil
+	resp := new(tc.TopologyResponse)
+	reqInf, err := to.post(ApiTopologies, top, nil, resp)
+	return resp, reqInf, err
 }
 
 func (to *Session) GetTopologiesWithHdr(header http.Header) ([]tc.Topology, ReqInf, error) {
-	resp, remoteAddr, err := to.request(http.MethodGet, ApiTopologies, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer log.Close(resp.Body, "unable to close response")
-
 	var data tc.TopologiesResponse
-	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
-		return nil, reqInf, err
-	}
-
-	return data.Response, reqInf, nil
+	reqInf, err := to.get(ApiTopologies, header, &data)
+	return data.Response, reqInf, err
 }
 
 // GetTopologies returns all topologies.
@@ -78,25 +46,15 @@ func (to *Session) GetTopologies() ([]tc.Topology, ReqInf, error) {
 
 func (to *Session) GetTopologyWithHdr(name string, header http.Header) (*tc.Topology, ReqInf, error) {
 	reqUrl := fmt.Sprintf("%s?name=%s", ApiTopologies, url.QueryEscape(name))
-	resp, remoteAddr, err := to.request(http.MethodGet, reqUrl, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer log.Close(resp.Body, "unable to close response")
-
 	var data tc.TopologiesResponse
-	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
+	reqInf, err := to.get(reqUrl, header, &data)
+	if err != nil {
 		return nil, reqInf, err
 	}
-
 	if len(data.Response) == 1 {
 		return &data.Response[0], reqInf, nil
 	}
-	return nil, reqInf, fmt.Errorf("expected one topology in response, instead got: %+v", data.Response)
+	return nil, reqInf, fmt.Errorf("expected one topology in response, instead got %d", len(data.Response))
 }
 
 // GetTopology returns the given topology by name.
@@ -107,43 +65,16 @@ func (to *Session) GetTopology(name string) (*tc.Topology, ReqInf, error) {
 
 // UpdateTopology updates a Topology by name.
 func (to *Session) UpdateTopology(name string, t tc.Topology) (*tc.TopologyResponse, ReqInf, error) {
-	var remoteAddr net.Addr
-	reqBody, err := json.Marshal(t)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return nil, reqInf, err
-	}
 	route := fmt.Sprintf("%s?name=%s", ApiTopologies, name)
-	resp, remoteAddr, err := to.request(http.MethodPut, route, reqBody, nil)
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer log.Close(resp.Body, "unable to close response")
-
 	var response = new(tc.TopologyResponse)
-	err = json.NewDecoder(resp.Body).Decode(response)
+	reqInf, err := to.put(route, t, nil, &response)
 	return response, reqInf, err
 }
 
 // DeleteTopology deletes the given topology by name.
 func (to *Session) DeleteTopology(name string) (tc.Alerts, ReqInf, error) {
 	reqUrl := fmt.Sprintf("%s?name=%s", ApiTopologies, url.QueryEscape(name))
-	resp, remoteAddr, err := to.request(http.MethodDelete, reqUrl, nil, nil)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-	}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer log.Close(resp.Body, "unable to close response")
-
 	var alerts tc.Alerts
-	if err = json.NewDecoder(resp.Body).Decode(&alerts); err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	return alerts, reqInf, nil
+	reqInf, err := to.del(reqUrl, nil, &alerts)
+	return alerts, reqInf, err
 }
diff --git a/traffic_ops/v3-client/topology_queue_updates.go b/traffic_ops/v3-client/topology_queue_updates.go
index b269d99..255d0e4 100644
--- a/traffic_ops/v3-client/topology_queue_updates.go
+++ b/traffic_ops/v3-client/topology_queue_updates.go
@@ -20,34 +20,14 @@
 package client
 
 import (
-	"encoding/json"
 	"fmt"
-	"net/http"
 
-	"github.com/apache/trafficcontrol/lib/go-log"
 	"github.com/apache/trafficcontrol/lib/go-tc"
 )
 
 func (to *Session) TopologiesQueueUpdate(topologyName tc.TopologyName, req tc.TopologiesQueueUpdateRequest) (tc.TopologiesQueueUpdateResponse, ReqInf, error) {
 	path := fmt.Sprintf(ApiTopologies+"/%s/queue_update", topologyName)
-	var reqInf ReqInf
 	var resp tc.TopologiesQueueUpdateResponse
-
-	reqBody, err := json.Marshal(req)
-	if err != nil {
-		return resp, reqInf, err
-	}
-
-	httpResp, remoteAddr, err := to.request(http.MethodPost, path, reqBody, nil)
-	if httpResp != nil {
-		reqInf.StatusCode = httpResp.StatusCode
-		reqInf.RemoteAddr = remoteAddr
-	}
-	if err != nil {
-		return resp, reqInf, err
-	}
-	defer log.Close(httpResp.Body, "unable to close response")
-
-	err = json.NewDecoder(httpResp.Body).Decode(&resp)
+	reqInf, err := to.post(path, req, nil, &resp)
 	return resp, reqInf, err
 }
diff --git a/traffic_ops/v3-client/traffic_monitor.go b/traffic_ops/v3-client/traffic_monitor.go
index 5d9e268..ae3e4bd 100644
--- a/traffic_ops/v3-client/traffic_monitor.go
+++ b/traffic_ops/v3-client/traffic_monitor.go
@@ -1,7 +1,6 @@
 package client
 
 import (
-	"encoding/json"
 	"fmt"
 
 	"github.com/apache/trafficcontrol/lib/go-tc"
@@ -48,18 +47,8 @@ func (to *Session) GetTrafficMonitorConfigMap(cdn string) (*tc.TrafficMonitorCon
 
 // GetTrafficMonitorConfig returns the monitoring configuration for the CDN named by 'cdn'.
 func (to *Session) GetTrafficMonitorConfig(cdn string) (*tc.TrafficMonitorConfig, ReqInf, error) {
-	url := fmt.Sprintf(API_CDN_MONITORING_CONFIG, cdn)
-	resp, remoteAddr, err := to.request("GET", url, nil, nil)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
+	route := fmt.Sprintf(API_CDN_MONITORING_CONFIG, cdn)
 	var data tc.TMConfigResponse
-	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
-		return nil, reqInf, err
-	}
-
-	return &data.Response, reqInf, nil
+	reqInf, err := to.get(route, nil, &data)
+	return &data.Response, reqInf, err
 }
diff --git a/traffic_ops/v3-client/traffic_stats.go b/traffic_ops/v3-client/traffic_stats.go
index 7c1ad48..50e8626 100644
--- a/traffic_ops/v3-client/traffic_stats.go
+++ b/traffic_ops/v3-client/traffic_stats.go
@@ -21,9 +21,6 @@ import (
 // GetCurrentStats gets current stats for each CDNs and a total across them
 func (to *Session) GetCurrentStats() (tc.TrafficStatsCDNStatsResponse, ReqInf, error) {
 	resp := tc.TrafficStatsCDNStatsResponse{}
-	reqInf, err := get(to, apiBase+"/current_stats", &resp, nil)
-	if err != nil {
-		return resp, reqInf, err
-	}
-	return resp, reqInf, nil
+	reqInf, err := to.get(apiBase+"/current_stats", nil, &resp)
+	return resp, reqInf, err
 }
diff --git a/traffic_ops/v3-client/type.go b/traffic_ops/v3-client/type.go
index 6e9a0c9..615e33b 100644
--- a/traffic_ops/v3-client/type.go
+++ b/traffic_ops/v3-client/type.go
@@ -16,10 +16,8 @@
 package client
 
 import (
-	"encoding/json"
 	"errors"
 	"fmt"
-	"net"
 	"net/http"
 
 	"github.com/apache/trafficcontrol/lib/go-tc"
@@ -31,49 +29,21 @@ const (
 
 // CreateType creates a Type. There should be a very good reason for doing this.
 func (to *Session) CreateType(typ tc.Type) (tc.Alerts, ReqInf, error) {
-
-	var remoteAddr net.Addr
-	reqBody, err := json.Marshal(typ)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	resp, remoteAddr, err := to.request(http.MethodPost, API_TYPES, reqBody, nil)
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
 	var alerts tc.Alerts
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
-	return alerts, reqInf, nil
+	reqInf, err := to.post(API_TYPES, typ, nil, &alerts)
+	return alerts, reqInf, err
 }
 
 func (to *Session) UpdateTypeByIDWithHdr(id int, typ tc.Type, header http.Header) (tc.Alerts, ReqInf, error) {
-
-	var remoteAddr net.Addr
-	reqBody, err := json.Marshal(typ)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
 	route := fmt.Sprintf("%s/%d", API_TYPES, id)
-	resp, remoteAddr, err := to.request(http.MethodPut, route, reqBody, header)
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-	}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
 	var alerts tc.Alerts
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
-	return alerts, reqInf, nil
+	reqInf, err := to.put(route, typ, header, &alerts)
+	return alerts, reqInf, err
 }
 
 // UpdateTypeByID updates a Type by ID.
 // Deprecated: UpdateTypeByID will be removed in 6.0. Use UpdateTypeByIDWithHdr.
 func (to *Session) UpdateTypeByID(id int, typ tc.Type) (tc.Alerts, ReqInf, error) {
-
 	return to.UpdateTypeByIDWithHdr(id, typ, nil)
 }
 
@@ -83,24 +53,11 @@ func (to *Session) UpdateTypeByID(id int, typ tc.Type) (tc.Alerts, ReqInf, error
 // be passed; passing more will result in an error being returned.
 func (to *Session) GetTypesWithHdr(header http.Header, useInTable ...string) ([]tc.Type, ReqInf, error) {
 	if len(useInTable) > 1 {
-		return nil, ReqInf{}, errors.New("Please pass in a single value for the 'useInTable' parameter")
-	}
-
-	resp, remoteAddr, err := to.request("GET", API_TYPES, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.Type{}, reqInf, nil
-		}
+		return nil, ReqInf{}, errors.New("please pass in a single value for the 'useInTable' parameter")
 	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	var data tc.TypesResponse
-	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
+	reqInf, err := to.get(API_TYPES, header, &data)
+	if err != nil {
 		return nil, reqInf, err
 	}
 
@@ -129,25 +86,9 @@ func (to *Session) GetTypes(useInTable ...string) ([]tc.Type, ReqInf, error) {
 // GetTypeByID GETs a Type by the Type ID, and filters by http header params in the request.
 func (to *Session) GetTypeByIDWithHdr(id int, header http.Header) ([]tc.Type, ReqInf, error) {
 	route := fmt.Sprintf("%s?id=%d", API_TYPES, id)
-	resp, remoteAddr, err := to.request(http.MethodGet, route, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.Type{}, reqInf, nil
-		}
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	var data tc.TypesResponse
-	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
-		return nil, reqInf, err
-	}
-
-	return data.Response, reqInf, nil
+	reqInf, err := to.get(route, header, &data)
+	return data.Response, reqInf, err
 }
 
 // GetTypeByID GETs a Type by the Type ID.
@@ -157,26 +98,10 @@ func (to *Session) GetTypeByID(id int) ([]tc.Type, ReqInf, error) {
 }
 
 func (to *Session) GetTypeByNameWithHdr(name string, header http.Header) ([]tc.Type, ReqInf, error) {
-	url := fmt.Sprintf("%s?name=%s", API_TYPES, name)
-	resp, remoteAddr, err := to.request(http.MethodGet, url, nil, header)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return []tc.Type{}, reqInf, nil
-		}
-	}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
+	route := fmt.Sprintf("%s?name=%s", API_TYPES, name)
 	var data tc.TypesResponse
-	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
-		return nil, reqInf, err
-	}
-
-	return data.Response, reqInf, nil
+	reqInf, err := to.get(route, header, &data)
+	return data.Response, reqInf, err
 }
 
 // GetTypeByName GETs a Type by the Type name.
@@ -188,13 +113,7 @@ func (to *Session) GetTypeByName(name string) ([]tc.Type, ReqInf, error) {
 // DeleteTypeByID DELETEs a Type by ID.
 func (to *Session) DeleteTypeByID(id int) (tc.Alerts, ReqInf, error) {
 	route := fmt.Sprintf("%s/%d", API_TYPES, id)
-	resp, remoteAddr, err := to.request(http.MethodDelete, route, nil, nil)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
 	var alerts tc.Alerts
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
-	return alerts, reqInf, nil
+	reqInf, err := to.del(route, nil, &alerts)
+	return alerts, reqInf, err
 }
diff --git a/traffic_ops/v3-client/user.go b/traffic_ops/v3-client/user.go
index 2dc5d71..bece5ec 100644
--- a/traffic_ops/v3-client/user.go
+++ b/traffic_ops/v3-client/user.go
@@ -16,10 +16,8 @@ package client
 */
 
 import (
-	"encoding/json"
 	"errors"
 	"fmt"
-	"net"
 	"net/http"
 	"net/url"
 	"strconv"
@@ -31,7 +29,7 @@ import (
 func (to *Session) GetUsersWithHdr(header http.Header) ([]tc.User, ReqInf, error) {
 	data := tc.UsersResponse{}
 	route := fmt.Sprintf("%s/users", apiBase)
-	inf, err := get(to, route, &data, header)
+	inf, err := to.get(route, header, &data)
 	return data.Response, inf, err
 }
 
@@ -44,7 +42,7 @@ func (to *Session) GetUsers() ([]tc.User, ReqInf, error) {
 func (to *Session) GetUsersByRoleWithHdr(roleName string, header http.Header) ([]tc.User, ReqInf, error) {
 	data := tc.UsersResponse{}
 	route := fmt.Sprintf("%s/users?role=%s", apiBase, url.QueryEscape(roleName))
-	inf, err := get(to, route, &data, header)
+	inf, err := to.get(route, header, &data)
 	return data.Response, inf, err
 }
 
@@ -57,7 +55,7 @@ func (to *Session) GetUsersByRole(roleName string) ([]tc.User, ReqInf, error) {
 func (to *Session) GetUserByIDWithHdr(id int, header http.Header) ([]tc.User, ReqInf, error) {
 	data := tc.UsersResponse{}
 	route := fmt.Sprintf("%s/users/%d", apiBase, id)
-	inf, err := get(to, route, &data, header)
+	inf, err := to.get(route, header, &data)
 	return data.Response, inf, err
 }
 
@@ -68,8 +66,8 @@ func (to *Session) GetUserByID(id int) ([]tc.User, ReqInf, error) {
 
 func (to *Session) GetUserByUsernameWithHdr(username string, header http.Header) ([]tc.User, ReqInf, error) {
 	data := tc.UsersResponse{}
-	route := fmt.Sprintf("%s/users?username=%s", apiBase, username)
-	inf, err := get(to, route, &data, header)
+	route := fmt.Sprintf("%s/users?username=%s", apiBase, url.QueryEscape(username))
+	inf, err := to.get(route, header, &data)
 	return data.Response, inf, err
 }
 
@@ -81,7 +79,7 @@ func (to *Session) GetUserByUsername(username string) ([]tc.User, ReqInf, error)
 func (to *Session) GetUserCurrentWithHdr(header http.Header) (*tc.UserCurrent, ReqInf, error) {
 	route := apiBase + `/user/current`
 	resp := tc.UserCurrentResponse{}
-	reqInf, err := get(to, route, &resp, header)
+	reqInf, err := to.get(route, header, &resp)
 	if err != nil {
 		return nil, reqInf, err
 	}
@@ -96,132 +94,69 @@ func (to *Session) GetUserCurrent() (*tc.UserCurrent, ReqInf, error) {
 
 // UpdateCurrentUser replaces the current user data with the provided tc.User structure.
 func (to *Session) UpdateCurrentUser(u tc.User) (*tc.UpdateUserResponse, ReqInf, error) {
-	var a net.Addr
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: a}
-
 	user := struct {
 		User tc.User `json:"user"`
 	}{u}
-	reqBody, err := json.Marshal(user)
-	if err != nil {
-		return nil, reqInf, err
-	}
-
-	var resp *http.Response
-	resp, reqInf.RemoteAddr, err = to.request(http.MethodPut, apiBase+"/user/current", reqBody, nil)
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
 	var clientResp tc.UpdateUserResponse
-	err = json.NewDecoder(resp.Body).Decode(&clientResp)
+	reqInf, err := to.put(apiBase+"/user/current", user, nil, &clientResp)
 	return &clientResp, reqInf, err
 }
 
 // CreateUser creates a user
 func (to *Session) CreateUser(user *tc.User) (*tc.CreateUserResponse, ReqInf, error) {
 	if user.TenantID == nil && user.Tenant != nil {
-		tenant, _, err := to.TenantByName(*user.Tenant)
+		tenant, _, err := to.TenantByNameWithHdr(*user.Tenant, nil)
 		if err != nil {
 			return nil, ReqInf{}, err
 		}
 		if tenant == nil {
 			return nil, ReqInf{}, errors.New("no tenant with name " + *user.Tenant)
 		}
-		if err != nil {
-			return nil, ReqInf{}, err
-		}
 		user.TenantID = &tenant.ID
 	}
 
 	if user.RoleName != nil && *user.RoleName != "" {
-		roles, _, _, err := to.GetRoleByName(*user.RoleName)
+		roles, _, _, err := to.GetRoleByNameWithHdr(*user.RoleName, nil)
 		if err != nil {
 			return nil, ReqInf{}, err
 		}
 		if len(roles) == 0 || roles[0].ID == nil {
 			return nil, ReqInf{}, errors.New("no role with name " + *user.RoleName)
 		}
-		if err != nil {
-			return nil, ReqInf{}, err
-		}
 		user.Role = roles[0].ID
 	}
 
-	var remoteAddr net.Addr
-	reqBody, err := json.Marshal(user)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return nil, reqInf, err
-	}
 	route := apiBase + "/users"
-	resp, remoteAddr, err := to.request(http.MethodPost, route, reqBody, nil)
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
 	var clientResp tc.CreateUserResponse
-	err = json.NewDecoder(resp.Body).Decode(&clientResp)
-	return &clientResp, reqInf, nil
+	reqInf, err := to.post(route, user, nil, &clientResp)
+	return &clientResp, reqInf, err
 }
 
 // UpdateUserByID updates user with the given id
 func (to *Session) UpdateUserByID(id int, u *tc.User) (*tc.UpdateUserResponse, ReqInf, error) {
-
-	var remoteAddr net.Addr
-	reqBody, err := json.Marshal(u)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return nil, reqInf, err
-	}
 	route := apiBase + "/users/" + strconv.Itoa(id)
-	resp, remoteAddr, err := to.request(http.MethodPut, route, reqBody, nil)
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
 	var clientResp tc.UpdateUserResponse
-	err = json.NewDecoder(resp.Body).Decode(&clientResp)
-	return &clientResp, reqInf, nil
+	reqInf, err := to.put(route, u, nil, &clientResp)
+	return &clientResp, reqInf, err
 }
 
 // DeleteUserByID updates user with the given id
 func (to *Session) DeleteUserByID(id int) (tc.Alerts, ReqInf, error) {
 	route := apiBase + "/users/" + strconv.Itoa(id)
-	resp, remoteAddr, err := to.request(http.MethodDelete, route, nil, nil)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return tc.Alerts{}, reqInf, err
-	}
-	defer resp.Body.Close()
 	var alerts tc.Alerts
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
-	return alerts, reqInf, nil
+	reqInf, err := to.del(route, nil, &alerts)
+	return alerts, reqInf, err
 }
 
 // RegisterNewUser requests the registration of a new user with the given tenant ID and role ID,
 // through their email.
 func (to *Session) RegisterNewUser(tenantID uint, roleID uint, email rfc.EmailAddress) (tc.Alerts, ReqInf, error) {
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss}
 	var alerts tc.Alerts
-
-	reqBody, err := json.Marshal(tc.UserRegistrationRequest{
+	reqBody := tc.UserRegistrationRequest{
 		Email:    email,
 		TenantID: tenantID,
 		Role:     roleID,
-	})
-	if err != nil {
-		return alerts, reqInf, err
 	}
-
-	resp, remoteAddr, err := to.request(http.MethodPost, apiBase+"/users/register", reqBody, nil)
-	reqInf.RemoteAddr = remoteAddr
-	if err != nil {
-		return alerts, reqInf, err
-	}
-	defer resp.Body.Close()
-
-	err = json.NewDecoder(resp.Body).Decode(&alerts)
+	reqInf, err := to.post(apiBase+"/users/register", reqBody, nil, &alerts)
 	return alerts, reqInf, err
 }
diff --git a/traffic_ops/v3-client/util.go b/traffic_ops/v3-client/util.go
index 5ec2be1..9653c3a 100644
--- a/traffic_ops/v3-client/util.go
+++ b/traffic_ops/v3-client/util.go
@@ -16,65 +16,13 @@
 package client
 
 import (
-	"encoding/json"
-	"errors"
-	"io/ioutil"
-	"net/http"
-
-	"github.com/apache/trafficcontrol/lib/go-log"
+	"net/url"
 )
 
-func get(to *Session, endpoint string, respStruct interface{}, header http.Header) (ReqInf, error) {
-	return makeReq(to, "GET", endpoint, nil, respStruct, header)
-}
-
-func post(to *Session, endpoint string, body []byte, respStruct interface{}) (ReqInf, error) {
-	return makeReq(to, "POST", endpoint, body, respStruct, nil)
-}
-
-func put(to *Session, endpoint string, body []byte, respStruct interface{}, header http.Header) (ReqInf, error) {
-	return makeReq(to, "PUT", endpoint, body, respStruct, header)
-}
-
-func del(to *Session, endpoint string, respStruct interface{}) (ReqInf, error) {
-	return makeReq(to, "DELETE", endpoint, nil, respStruct, nil)
-}
-
-func makeReq(to *Session, method, endpoint string, body []byte, respStruct interface{}, header http.Header) (ReqInf, error) {
-	resp, remoteAddr, err := to.request(method, endpoint, body, header) // TODO change to getBytesWithTTL
-	reqInf := ReqInf{RemoteAddr: remoteAddr, CacheHitStatus: CacheHitStatusMiss}
-	if resp != nil {
-		reqInf.StatusCode = resp.StatusCode
-		if reqInf.StatusCode == http.StatusNotModified {
-			return reqInf, nil
-		}
-	}
-	if err != nil {
-		return reqInf, err
-	}
-	defer log.Close(resp.Body, "unable to close response body")
-
-	bts, err := ioutil.ReadAll(resp.Body)
-	if err != nil {
-		return reqInf, errors.New("reading body: " + err.Error())
-	}
-
-	if err := json.Unmarshal(bts, respStruct); err != nil {
-		return reqInf, errors.New("unmarshalling body '" + string(body) + "': " + err.Error())
-	}
-
-	return reqInf, nil
-}
-
-func mapToQueryParameters(params map[string]string) string {
-	path := ""
-	for key, value := range params {
-		if path == "" {
-			path += "?"
-		} else {
-			path += "&"
-		}
-		path += key + "=" + value
+func mapToQueryParameters(paramsMap map[string]string) string {
+	params := url.Values{}
+	for key, value := range paramsMap {
+		params.Add(key, value)
 	}
-	return path
+	return "?" + params.Encode()
 }