You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficcontrol.apache.org by da...@apache.org on 2018/02/08 15:52:12 UTC

[incubator-trafficcontrol] 01/03: refactor url parameter handling, along with where clause and orderBy construction

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

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

commit 98d91f96fbc442bc7660216560ffd6bb095772f1
Author: Dylan Volz <Dy...@comcast.com>
AuthorDate: Wed Jan 24 11:48:42 2018 -0700

    refactor url parameter handling, along with where clause and orderBy construction
---
 lib/go-tc/alerts.go                                |  14 +++
 .../traffic_ops_golang/api/shared_handlers.go      | 115 +++++++++------------
 .../traffic_ops_golang/api/shared_interfaces.go    |   4 +-
 traffic_ops/traffic_ops_golang/asns.go             |  51 +++++----
 traffic_ops/traffic_ops_golang/asns_test.go        |  10 +-
 traffic_ops/traffic_ops_golang/cdn/cdns.go         |  30 +++---
 .../traffic_ops_golang/dbhelpers/db_helpers.go     |  70 +++++++++----
 .../traffic_ops_golang/deliveryservice/handlers.go |  49 ++++-----
 traffic_ops/traffic_ops_golang/divisions.go        |  44 +++++---
 traffic_ops/traffic_ops_golang/divisions_test.go   |  10 +-
 traffic_ops/traffic_ops_golang/hwinfo.go           |  52 ++++++----
 traffic_ops/traffic_ops_golang/hwinfo_test.go      |  10 +-
 traffic_ops/traffic_ops_golang/monitoring.go       |  26 ++---
 traffic_ops/traffic_ops_golang/monitoring_test.go  |   4 +-
 traffic_ops/traffic_ops_golang/parameters.go       |  49 +++++----
 traffic_ops/traffic_ops_golang/parameters_test.go  |  10 +-
 traffic_ops/traffic_ops_golang/phys_locations.go   |  51 +++++----
 .../traffic_ops_golang/phys_locations_test.go      |  10 +-
 traffic_ops/traffic_ops_golang/regions.go          |  52 +++++-----
 traffic_ops/traffic_ops_golang/regions_test.go     |  10 +-
 traffic_ops/traffic_ops_golang/routing.go          |   2 +-
 traffic_ops/traffic_ops_golang/servers.go          |  69 ++++++-------
 .../traffic_ops_golang/servers_assignment.go       |  12 +--
 traffic_ops/traffic_ops_golang/servers_test.go     |  10 +-
 .../traffic_ops_golang/servers_update_status.go    |   8 +-
 traffic_ops/traffic_ops_golang/statuses.go         |  63 +++++------
 traffic_ops/traffic_ops_golang/statuses_test.go    |  10 +-
 traffic_ops/traffic_ops_golang/tenant/tenancy.go   |   3 +-
 28 files changed, 432 insertions(+), 416 deletions(-)

diff --git a/lib/go-tc/alerts.go b/lib/go-tc/alerts.go
index 5dd4b08..52066b4 100644
--- a/lib/go-tc/alerts.go
+++ b/lib/go-tc/alerts.go
@@ -75,4 +75,18 @@ func GetHandleErrorsFunc(w http.ResponseWriter, r *http.Request) func(status int
 	}
 }
 
+func HandleErrorsWithType(errs []error, errType ApiErrorType, handleErrs func(status int, errs ...error)) {
+		switch errType {
+		case SystemError:
+			handleErrs(http.StatusInternalServerError, errs...)
+		case DataConflictError:
+			handleErrs(http.StatusBadRequest, errs...)
+		case DataMissingError:
+			handleErrs(http.StatusNotFound, errs...)
+		default:
+			log.Errorf("received unknown ApiErrorType from read: %s\n", errType.String())
+			handleErrs(http.StatusInternalServerError, errs...)
+		}
+}
+
 var StatusKey = "status"
\ No newline at end of file
diff --git a/traffic_ops/traffic_ops_golang/api/shared_handlers.go b/traffic_ops/traffic_ops_golang/api/shared_handlers.go
index ce5e5d7..58fe3b4 100644
--- a/traffic_ops/traffic_ops_golang/api/shared_handlers.go
+++ b/traffic_ops/traffic_ops_golang/api/shared_handlers.go
@@ -35,23 +35,57 @@ import (
 	"github.com/jmoiron/sqlx"
 )
 
-type PathParams map[string]string
-
 const PathParamsKey = "pathParams"
 
-func GetPathParams(ctx context.Context) (PathParams, error) {
+func GetPathParams(ctx context.Context) (map[string]string, error) {
 	val := ctx.Value(PathParamsKey)
 	if val != nil {
 		switch v := val.(type) {
-		case PathParams:
+		case map[string]string:
 			return v, nil
 		default:
-			return nil, fmt.Errorf("PathParams found with bad type: %T", v)
+			return nil, fmt.Errorf("path parameters found with bad type: %T", v)
 		}
 	}
 	return nil, errors.New("no PathParams found in Context")
 }
 
+func IsInt(s string) error {
+	_, err := strconv.Atoi(s)
+	if err != nil {
+		err = errors.New("cannot parse to integer")
+	}
+	return err
+}
+
+func IsBool(s string) error {
+	_, err := strconv.ParseBool(s)
+	if err != nil {
+		err = errors.New("cannot parse to boolean")
+	}
+	return err
+}
+
+func GetCombinedParams(r *http.Request) (map[string]string, error) {
+	combinedParams := make(map[string]string)
+	q := r.URL.Query()
+	for k, v := range q {
+		combinedParams[k] = v[0] //we take the first value and do not support multiple keys in query parameters
+	}
+
+	ctx := r.Context()
+	pathParams, err := GetPathParams(ctx)
+	if err != nil {
+		return combinedParams, fmt.Errorf("no path parameters: %s", err)
+	}
+	//path parameters will overwrite query parameters
+	for k, v := range pathParams {
+		combinedParams[k] = v
+	}
+
+	return combinedParams, nil
+}
+
 //decodes and validates a pointer to a struct implementing the Validator interface
 //      we lose the ability to unmarshal the struct if a struct implementing the interface is passed in,
 //      because when when it is de-referenced it is a pointer to an interface. A new copy is created so that
@@ -80,23 +114,12 @@ func ReadHandler(typeRef Reader, db *sqlx.DB) http.HandlerFunc {
 		handleErrs := tc.GetHandleErrorsFunc(w, r)
 
 		ctx := r.Context()
-		pathParams, err := GetPathParams(ctx)
-		if err != nil {
-			handleErrs(http.StatusInternalServerError, err)
-			return
-		}
 
 		// Load the PathParams into the query parameters for pass through
-		q := r.URL.Query()
-		for k, v := range pathParams {
-			if k == `id` {
-				if _, err := strconv.Atoi(v); err != nil {
-					log.Errorf("Expected {id} to be an integer: %s", v)
-					handleErrs(http.StatusNotFound, errors.New("Resource not found.")) //matches perl response
-					return
-				}
-			}
-			q.Set(k, v)
+		params, err := GetCombinedParams(r)
+		if err != nil {
+			log.Errorf("unable to get parameters from request: %s", err)
+			handleErrs(http.StatusInternalServerError, err)
 		}
 
 		user, err := auth.GetCurrentUser(ctx)
@@ -105,19 +128,9 @@ func ReadHandler(typeRef Reader, db *sqlx.DB) http.HandlerFunc {
 			handleErrs(http.StatusInternalServerError, err)
 		}
 
-		results, err, errType := typeRef.Read(db, q, *user)
-		if err != nil {
-			switch errType {
-			case tc.SystemError:
-				handleErrs(http.StatusInternalServerError, err)
-			case tc.DataConflictError:
-				handleErrs(http.StatusBadRequest, err)
-			case tc.DataMissingError:
-				handleErrs(http.StatusNotFound, err)
-			default:
-				log.Errorf("received unknown ApiErrorType from read: %s\n", errType.String())
-				handleErrs(http.StatusInternalServerError, err)
-			}
+		results, errs, errType := typeRef.Read(db, params, *user)
+		if len(errs) > 0 {
+			tc.HandleErrorsWithType(errs, errType, handleErrs)
 			return
 		}
 		resp := struct {
@@ -184,17 +197,7 @@ func UpdateHandler(typeRef Updater, db *sqlx.DB) http.HandlerFunc {
 		//run the update and handle any error
 		err, errType := u.Update(db, *user)
 		if err != nil {
-			switch errType {
-			case tc.SystemError:
-				handleErrs(http.StatusInternalServerError, err)
-			case tc.DataConflictError:
-				handleErrs(http.StatusBadRequest, err)
-			case tc.DataMissingError:
-				handleErrs(http.StatusNotFound, err)
-			default:
-				log.Errorf("received unknown ApiErrorType from update: %s, updating: %s id: %d\n", errType.String(), u.GetType(), u.GetID())
-				handleErrs(http.StatusInternalServerError, err)
-			}
+			tc.HandleErrorsWithType([]error{err}, errType, handleErrs)
 			return
 		}
 		//auditing here
@@ -250,17 +253,7 @@ func DeleteHandler(typeRef Deleter, db *sqlx.DB) http.HandlerFunc {
 		log.Debugf("calling delete on object: %++v", d) //should have id set now
 		err, errType := d.Delete(db, *user)
 		if err != nil {
-			switch errType {
-			case tc.SystemError:
-				handleErrs(http.StatusInternalServerError, err)
-			case tc.DataConflictError:
-				handleErrs(http.StatusBadRequest, err)
-			case tc.DataMissingError:
-				handleErrs(http.StatusNotFound, err)
-			default:
-				log.Errorf("received unknown ApiErrorType from delete: %s, deleting: %s id: %d\n", errType.String(), d.GetType(), d.GetID())
-				handleErrs(http.StatusInternalServerError, err)
-			}
+			tc.HandleErrorsWithType([]error{err}, errType, handleErrs)
 			return
 		}
 		//audit here
@@ -312,17 +305,7 @@ func CreateHandler(typeRef Inserter, db *sqlx.DB) http.HandlerFunc {
 
 		err, errType := i.Insert(db, *user)
 		if err != nil {
-			switch errType {
-			case tc.SystemError:
-				handleErrs(http.StatusInternalServerError, err)
-			case tc.DataConflictError:
-				handleErrs(http.StatusBadRequest, err)
-			case tc.DataMissingError:
-				handleErrs(http.StatusNotFound, err)
-			default:
-				log.Errorf("received unknown ApiErrorType from insert: %s, inserting: %s id: %d\n", errType.String(), i.GetType(), i.GetID())
-				handleErrs(http.StatusInternalServerError, err)
-			}
+			tc.HandleErrorsWithType([]error{err}, errType, handleErrs)
 			return
 		}
 
diff --git a/traffic_ops/traffic_ops_golang/api/shared_interfaces.go b/traffic_ops/traffic_ops_golang/api/shared_interfaces.go
index 7c4d0bd..7d51ce1 100644
--- a/traffic_ops/traffic_ops_golang/api/shared_interfaces.go
+++ b/traffic_ops/traffic_ops_golang/api/shared_interfaces.go
@@ -20,8 +20,6 @@ package api
  */
 
 import (
-	"net/url"
-
 	"github.com/apache/incubator-trafficcontrol/lib/go-tc"
 	"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/auth"
 	"github.com/jmoiron/sqlx"
@@ -61,5 +59,5 @@ type Tenantable interface {
 }
 
 type Reader interface {
-	Read(db *sqlx.DB, v url.Values, user auth.CurrentUser) ([]interface{}, error, tc.ApiErrorType)
+	Read(db *sqlx.DB, parameters map[string]string, user auth.CurrentUser) ([]interface{}, []error, tc.ApiErrorType)
 }
diff --git a/traffic_ops/traffic_ops_golang/asns.go b/traffic_ops/traffic_ops_golang/asns.go
index 8d0ea23..86a2fa7 100644
--- a/traffic_ops/traffic_ops_golang/asns.go
+++ b/traffic_ops/traffic_ops_golang/asns.go
@@ -23,8 +23,8 @@ import (
 	"encoding/json"
 	"fmt"
 	"net/http"
-	"net/url"
 
+	"github.com/apache/incubator-trafficcontrol/lib/go-log"
 	"github.com/apache/incubator-trafficcontrol/lib/go-tc"
 	"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/api"
 	"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/dbhelpers"
@@ -39,21 +39,15 @@ func ASNsHandler(db *sqlx.DB) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		handleErrs := tc.GetHandleErrorsFunc(w, r)
 
-		ctx := r.Context()
-		pathParams, err := api.GetPathParams(ctx)
+		params, err := api.GetCombinedParams(r)
 		if err != nil {
+			log.Errorf("unable to get parameters from request: %s", err)
 			handleErrs(http.StatusInternalServerError, err)
-			return
 		}
 
-		// Load the PathParams into the query parameters for pass through
-		q := r.URL.Query()
-		for k, v := range pathParams {
-			q.Set(k, v)
-		}
-		resp, err := getASNsResponse(q, db)
-		if err != nil {
-			handleErrs(http.StatusInternalServerError, err)
+		resp, errs, errType := getASNsResponse(params, db)
+		if len(errs) > 0 {
+			tc.HandleErrorsWithType(errs, errType, handleErrs)
 			return
 		}
 
@@ -68,35 +62,40 @@ func ASNsHandler(db *sqlx.DB) http.HandlerFunc {
 	}
 }
 
-func getASNsResponse(q url.Values, db *sqlx.DB) (*tc.ASNsResponse, error) {
-	asns, err := getASNs(q, db)
-	if err != nil {
-		return nil, fmt.Errorf("getting asns response: %v", err)
+func getASNsResponse(parameters map[string]string, db *sqlx.DB) (*tc.ASNsResponse, []error, tc.ApiErrorType) {
+	asns, errs, errType := getASNs(parameters, db)
+	if len(errs) > 0 {
+		return nil, errs, errType
 	}
 
 	resp := tc.ASNsResponse{
 		Response: asns,
 	}
-	return &resp, nil
+	return &resp, nil, tc.NoError
 }
 
-func getASNs(v url.Values, db *sqlx.DB) ([]tc.ASN, error) {
+func getASNs(parameters map[string]string, db *sqlx.DB) ([]tc.ASN, []error, tc.ApiErrorType) {
 	var rows *sqlx.Rows
 	var err error
 
 	// Query Parameters to Database Query column mappings
 	// see the fields mapped in the SQL query
-	queryParamsToQueryCols := map[string]string{
-		"asn":        "a.asn",
-		"id":         "a.id",
-		"cachegroup": "cg.id",
+	queryParamsToQueryCols := map[string]dbhelpers.WhereColumnInfo{
+		"asn":        dbhelpers.WhereColumnInfo{"a.asn", api.IsInt},
+		"id":         dbhelpers.WhereColumnInfo{"a.id", api.IsInt},
+		"cachegroup": dbhelpers.WhereColumnInfo{"cg.id", api.IsInt},
 	}
 
-	query, queryValues := dbhelpers.BuildQuery(v, selectASNsQuery(), queryParamsToQueryCols)
+	where, orderBy, queryValues, errs := dbhelpers.BuildWhereAndOrderBy(parameters, queryParamsToQueryCols)
+	if len(errs) > 0 {
+		return nil, errs, tc.DataConflictError
+	}
+	query := selectASNsQuery() + where + orderBy
+	log.Debugln("Query is ", query)
 
 	rows, err = db.NamedQuery(query, queryValues)
 	if err != nil {
-		return nil, err
+		return nil, []error{err}, tc.SystemError
 	}
 	defer rows.Close()
 
@@ -104,11 +103,11 @@ func getASNs(v url.Values, db *sqlx.DB) ([]tc.ASN, error) {
 	for rows.Next() {
 		var s tc.ASN
 		if err = rows.StructScan(&s); err != nil {
-			return nil, fmt.Errorf("getting ASNs: %v", err)
+			return nil, []error{fmt.Errorf("getting ASNs: %v", err)}, tc.SystemError
 		}
 		ASNs = append(ASNs, s)
 	}
-	return ASNs, nil
+	return ASNs, nil, tc.NoError
 }
 
 func selectASNsQuery() string {
diff --git a/traffic_ops/traffic_ops_golang/asns_test.go b/traffic_ops/traffic_ops_golang/asns_test.go
index 94b8950..64101c0 100644
--- a/traffic_ops/traffic_ops_golang/asns_test.go
+++ b/traffic_ops/traffic_ops_golang/asns_test.go
@@ -20,7 +20,6 @@ package main
  */
 
 import (
-	"net/url"
 	"testing"
 	"time"
 
@@ -72,12 +71,11 @@ func TestGetASNs(t *testing.T) {
 		)
 	}
 	mock.ExpectQuery("SELECT").WillReturnRows(rows)
-	v := url.Values{}
-	v.Set("dsId", "1")
+	v := map[string]string{"dsId": "1"}
 
-	servers, err := getASNs(v, db)
-	if err != nil {
-		t.Errorf("getASNs expected: nil error, actual: %v", err)
+	servers, errs, errType := getASNs(v, db)
+	if len(errs) > 0 {
+		t.Errorf("getASNs expected: no errors, actual: %v with type %s", errs, errType.String())
 	}
 
 	if len(servers) != 2 {
diff --git a/traffic_ops/traffic_ops_golang/cdn/cdns.go b/traffic_ops/traffic_ops_golang/cdn/cdns.go
index dd52654..ca02d09 100644
--- a/traffic_ops/traffic_ops_golang/cdn/cdns.go
+++ b/traffic_ops/traffic_ops_golang/cdn/cdns.go
@@ -22,11 +22,11 @@ package cdn
 import (
 	"errors"
 	"fmt"
-	"net/url"
 
 	"github.com/apache/incubator-trafficcontrol/lib/go-log"
 	"github.com/apache/incubator-trafficcontrol/lib/go-tc"
 
+	"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/api"
 	"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/auth"
 	"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/dbhelpers"
 	"github.com/jmoiron/sqlx"
@@ -71,25 +71,29 @@ func (cdn *TOCDN) Validate(db *sqlx.DB) []error {
 	return errs
 }
 
-func (cdn *TOCDN) Read(db *sqlx.DB, v url.Values, user auth.CurrentUser) ([]interface{}, error, tc.ApiErrorType) {
+func (cdn *TOCDN) Read(db *sqlx.DB, parameters map[string]string, user auth.CurrentUser) ([]interface{}, []error, tc.ApiErrorType) {
 	var rows *sqlx.Rows
-	var err error
 
 	// Query Parameters to Database Query column mappings
 	// see the fields mapped in the SQL query
-	queryParamsToQueryCols := map[string]string{
-		"domainName":    "domain_name",
-		"dnssecEnabled": "dnssec_enabled",
-		"id":            "id",
-		"name":          "name",
+	queryParamsToQueryCols := map[string]dbhelpers.WhereColumnInfo{
+		"domainName":    dbhelpers.WhereColumnInfo{"domain_name", nil},
+		"dnssecEnabled": dbhelpers.WhereColumnInfo{"dnssec_enabled", nil},
+		"id":            dbhelpers.WhereColumnInfo{"id", api.IsInt},
+		"name":          dbhelpers.WhereColumnInfo{"name", nil},
+	}
+	where, orderBy, queryValues, errs := dbhelpers.BuildWhereAndOrderBy(parameters, queryParamsToQueryCols)
+	if len(errs) > 0 {
+		return nil, errs, tc.DataConflictError
 	}
 
-	query, queryValues := dbhelpers.BuildQuery(v, selectCDNsQuery(), queryParamsToQueryCols)
+	query := selectCDNsQuery() + where + orderBy
+	log.Debugln("Query is ", query)
 
-	rows, err = db.NamedQuery(query, queryValues)
+	rows, err := db.NamedQuery(query, queryValues)
 	if err != nil {
 		log.Errorf("Error querying CDNs: %v", err)
-		return nil, tc.DBError, tc.SystemError
+		return nil, []error{tc.DBError}, tc.SystemError
 	}
 	defer rows.Close()
 
@@ -98,12 +102,12 @@ func (cdn *TOCDN) Read(db *sqlx.DB, v url.Values, user auth.CurrentUser) ([]inte
 		var s tc.CDN
 		if err = rows.StructScan(&s); err != nil {
 			log.Errorf("error parsing CDN rows: %v", err)
-			return nil, tc.DBError, tc.SystemError
+			return nil, []error{tc.DBError}, tc.SystemError
 		}
 		CDNs = append(CDNs, s)
 	}
 
-	return CDNs, nil, tc.NoError
+	return CDNs, []error{}, tc.NoError
 }
 
 func selectCDNsQuery() string {
diff --git a/traffic_ops/traffic_ops_golang/dbhelpers/db_helpers.go b/traffic_ops/traffic_ops_golang/dbhelpers/db_helpers.go
index c5d9237..24f0f7c 100644
--- a/traffic_ops/traffic_ops_golang/dbhelpers/db_helpers.go
+++ b/traffic_ops/traffic_ops_golang/dbhelpers/db_helpers.go
@@ -21,7 +21,6 @@ package dbhelpers
 
 import (
 	"errors"
-	"net/url"
 	"strings"
 
 	"github.com/apache/incubator-trafficcontrol/lib/go-log"
@@ -29,47 +28,74 @@ import (
 	"github.com/lib/pq"
 )
 
-func BuildQuery(v url.Values, selectStmt string, queryParamsToSQLCols map[string]string) (string, map[string]interface{}) {
-	var sqlQuery string
+type WhereColumnInfo struct {
+	Column  string
+	Checker func(string) error
+}
+
+const baseWhere = "\nWHERE"
+const baseOrderBy = "\nORDER BY"
+
+func BuildWhereAndOrderBy(parameters map[string]string, queryParamsToSQLCols map[string]WhereColumnInfo) (string, string, map[string]interface{}, []error) {
+	whereClause := baseWhere
+	orderBy := baseOrderBy
 	var criteria string
 	var queryValues map[string]interface{}
-	sqlQuery = selectStmt
-	criteria, queryValues = parseCriteriaAndQueryValues(queryParamsToSQLCols, v)
+	var errs []error
+	criteria, queryValues, errs = parseCriteriaAndQueryValues(queryParamsToSQLCols, parameters)
 
 	if len(queryValues) > 0 {
-		sqlQuery += "\nWHERE " + criteria
+		whereClause += " " + criteria
+	}
+	if len(errs) > 0 {
+		return "", "", queryValues, errs
 	}
 
-	if orderby, ok := v["orderby"]; ok {
-		log.Debugln("orderby: ", orderby[0])
-		if col, ok := queryParamsToSQLCols[orderby[0]]; ok {
-			log.Debugln("orderby column ", col)
-			sqlQuery += "\nORDER BY " + col
+	if orderby, ok := parameters["orderby"]; ok {
+		log.Debugln("orderby: ", orderby)
+		if colInfo, ok := queryParamsToSQLCols[orderby]; ok {
+			log.Debugln("orderby column ", colInfo)
+			orderBy += " " + colInfo.Column
 		} else {
-			log.Debugln("Incorrect name for orderby: ", orderby[0])
+			log.Debugln("Incorrect name for orderby: ", orderby)
 		}
 	}
-	log.Debugln("\n--\n" + sqlQuery)
-	return sqlQuery, queryValues
+	if whereClause == baseWhere {
+		whereClause = ""
+	}
+	if orderBy == baseOrderBy {
+		orderBy = ""
+	}
+	log.Debugf("\n--\n Where: %s \n Order By: %s", whereClause, orderBy)
+	return whereClause, orderBy, queryValues, errs
 }
 
-func parseCriteriaAndQueryValues(queryParamsToSQLCols map[string]string, v url.Values) (string, map[string]interface{}) {
+func parseCriteriaAndQueryValues(queryParamsToSQLCols map[string]WhereColumnInfo, parameters map[string]string) (string, map[string]interface{}, []error) {
 	m := make(map[string]interface{})
 	var criteria string
 
 	var criteriaArgs []string
+	errs := []error{}
 	queryValues := make(map[string]interface{})
-	for key, val := range queryParamsToSQLCols {
-		if urlValue, ok := v[key]; ok {
-			m[key] = urlValue[0]
-			criteria = val + "=:" + key
-			criteriaArgs = append(criteriaArgs, criteria)
-			queryValues[key] = urlValue[0]
+	for key, colInfo := range queryParamsToSQLCols {
+		if urlValue, ok := parameters[key]; ok {
+			var err error
+			if colInfo.Checker != nil {
+				err = colInfo.Checker(urlValue)
+			}
+			if err != nil {
+				errs = append(errs, errors.New(key+" "+err.Error()))
+			} else {
+				m[key] = urlValue
+				criteria = colInfo.Column + "=:" + key
+				criteriaArgs = append(criteriaArgs, criteria)
+				queryValues[key] = urlValue
+			}
 		}
 	}
 	criteria = strings.Join(criteriaArgs, " AND ")
 
-	return criteria, queryValues
+	return criteria, queryValues, errs
 }
 
 //parses pq errors for uniqueness constraint violations
diff --git a/traffic_ops/traffic_ops_golang/deliveryservice/handlers.go b/traffic_ops/traffic_ops_golang/deliveryservice/handlers.go
index 6fd7323..5584873 100644
--- a/traffic_ops/traffic_ops_golang/deliveryservice/handlers.go
+++ b/traffic_ops/traffic_ops_golang/deliveryservice/handlers.go
@@ -23,8 +23,8 @@ import (
 	"encoding/json"
 	"fmt"
 	"net/http"
-	"net/url"
 
+	"github.com/apache/incubator-trafficcontrol/lib/go-log"
 	"github.com/apache/incubator-trafficcontrol/lib/go-tc"
 	"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/api"
 	"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/dbhelpers"
@@ -37,24 +37,15 @@ func Handler(db *sqlx.DB) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		handleErrs := tc.GetHandleErrorsFunc(w, r)
 
-		ctx := r.Context()
-		pathParams, err := api.GetPathParams(ctx)
+		// Load the the query and path params with path params overriding query params
+		params, err := api.GetCombinedParams(r)
 		if err != nil {
+			log.Errorf("unable to get parameters from request: %s", err)
 			handleErrs(http.StatusInternalServerError, err)
-			return
-		}
-
-		q := r.URL.Query()
-		for k, v := range pathParams {
-			q.Set(k, v)
 		}
 
-		resp, err := getDeliveryServicesResponse(q, db)
-
-		if err != nil {
-			handleErrs(http.StatusInternalServerError, err)
-			return
-		}
+		resp, errs, errType := getDeliveryServicesResponse(params, db)
+		tc.HandleErrorsWithType(errs, errType, handleErrs)
 
 		respBts, err := json.Marshal(resp)
 		if err != nil {
@@ -67,35 +58,39 @@ func Handler(db *sqlx.DB) http.HandlerFunc {
 	}
 }
 
-func getDeliveryServicesResponse(q url.Values, db *sqlx.DB) (*tc.DeliveryServicesResponse, error) {
-	dses, err := getDeliveryServices(q, db)
-	if err != nil {
-		return nil, fmt.Errorf("getting DeliveryServices response: %v", err)
+func getDeliveryServicesResponse(parameters map[string]string, db *sqlx.DB) (*tc.DeliveryServicesResponse, []error, tc.ApiErrorType) {
+	dses, errs, errType := getDeliveryServices(parameters, db)
+	if len(errs) > 0 {
+		return nil, errs, errType
 	}
 
 	resp := tc.DeliveryServicesResponse{
 		Response: dses,
 	}
-	return &resp, nil
+	return &resp, nil, tc.NoError
 }
 
-func getDeliveryServices(v url.Values, db *sqlx.DB) ([]tc.DeliveryService, error) {
+func getDeliveryServices(parameters map[string]string, db *sqlx.DB) ([]tc.DeliveryService, []error, tc.ApiErrorType) {
 	var rows *sqlx.Rows
 	var err error
 
 	// Query Parameters to Database Query column mappings
 	// see the fields mapped in the SQL query
-	queryParamsToQueryCols := map[string]string{
-		"xmlId": "xml_id",
+	queryParamsToQueryCols := map[string]dbhelpers.WhereColumnInfo{
+		"xmlId": dbhelpers.WhereColumnInfo{"xml_id", nil},
 	}
 
-	query, queryValues := dbhelpers.BuildQuery(v, selectDSesQuery(), queryParamsToQueryCols)
+	where, orderBy, queryValues, errs := dbhelpers.BuildWhereAndOrderBy(parameters, queryParamsToQueryCols)
+	if len(errs) > 0 {
+		return nil, errs, tc.DataConflictError
+	}
+	query := selectDSesQuery() + where + orderBy
 
 	rows, err = db.NamedQuery(query, queryValues)
 	fmt.Printf("rows ---> %v\n", rows)
 	fmt.Printf("err ---> %v\n", err)
 	if err != nil {
-		return nil, err
+		return nil, []error{err}, tc.SystemError
 	}
 	defer rows.Close()
 
@@ -103,11 +98,11 @@ func getDeliveryServices(v url.Values, db *sqlx.DB) ([]tc.DeliveryService, error
 	for rows.Next() {
 		var s tc.DeliveryService
 		if err = rows.StructScan(&s); err != nil {
-			return nil, fmt.Errorf("getting Delivery Services: %v", err)
+			return nil, []error{fmt.Errorf("getting Delivery Services: %v", err)}, tc.SystemError
 		}
 		dses = append(dses, s)
 	}
-	return dses, nil
+	return dses, nil, tc.NoError
 }
 
 func selectDSesQuery() string {
diff --git a/traffic_ops/traffic_ops_golang/divisions.go b/traffic_ops/traffic_ops_golang/divisions.go
index 556a22a..10eac0b 100644
--- a/traffic_ops/traffic_ops_golang/divisions.go
+++ b/traffic_ops/traffic_ops_golang/divisions.go
@@ -23,9 +23,10 @@ import (
 	"encoding/json"
 	"fmt"
 	"net/http"
-	"net/url"
 
+	"github.com/apache/incubator-trafficcontrol/lib/go-log"
 	"github.com/apache/incubator-trafficcontrol/lib/go-tc"
+	"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/api"
 	"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/dbhelpers"
 	"github.com/jmoiron/sqlx"
 )
@@ -34,10 +35,15 @@ func divisionsHandler(db *sqlx.DB) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		handleErrs := tc.GetHandleErrorsFunc(w, r)
 
-		q := r.URL.Query()
-		resp, err := getDivisionsResponse(q, db)
+		params, err := api.GetCombinedParams(r)
 		if err != nil {
+			log.Errorf("unable to get parameters from request: %s", err)
 			handleErrs(http.StatusInternalServerError, err)
+		}
+
+		resp, errs, errType := getDivisionsResponse(params, db)
+		if len(errs) > 0 {
+			tc.HandleErrorsWithType(errs, errType, handleErrs)
 			return
 		}
 
@@ -52,34 +58,40 @@ func divisionsHandler(db *sqlx.DB) http.HandlerFunc {
 	}
 }
 
-func getDivisionsResponse(q url.Values, db *sqlx.DB) (*tc.DivisionsResponse, error) {
-	divisions, err := getDivisions(q, db)
-	if err != nil {
-		return nil, fmt.Errorf("getting divisions response: %v", err)
+func getDivisionsResponse(params map[string]string, db *sqlx.DB) (*tc.DivisionsResponse, []error, tc.ApiErrorType) {
+	divisions, errs, errType := getDivisions(params, db)
+	if len(errs) > 0 {
+		return nil, errs, errType
 	}
 
 	resp := tc.DivisionsResponse{
 		Response: divisions,
 	}
-	return &resp, nil
+	return &resp, nil, tc.NoError
 }
 
-func getDivisions(v url.Values, db *sqlx.DB) ([]tc.Division, error) {
+func getDivisions(params map[string]string, db *sqlx.DB) ([]tc.Division, []error, tc.ApiErrorType) {
 	var rows *sqlx.Rows
 	var err error
 
 	// Query Parameters to Database Query column mappings
 	// see the fields mapped in the SQL query
-	queryParamsToSQLCols := map[string]string{
-		"id":   "id",
-		"name": "name",
+	queryParamsToSQLCols := map[string]dbhelpers.WhereColumnInfo{
+		"id":   dbhelpers.WhereColumnInfo{"id", api.IsInt},
+		"name": dbhelpers.WhereColumnInfo{"name", nil},
+	}
+
+	where, orderBy, queryValues, errs := dbhelpers.BuildWhereAndOrderBy(params, queryParamsToSQLCols)
+	if len(errs) > 0 {
+		return nil, errs, tc.DataConflictError
 	}
 
-	query, queryValues := dbhelpers.BuildQuery(v, selectDivisionsQuery(), queryParamsToSQLCols)
+	query := selectDivisionsQuery() + where + orderBy
+	log.Debugln("Query is ", query)
 
 	rows, err = db.NamedQuery(query, queryValues)
 	if err != nil {
-		return nil, err
+		return nil, []error{err}, tc.SystemError
 	}
 	defer rows.Close()
 
@@ -87,11 +99,11 @@ func getDivisions(v url.Values, db *sqlx.DB) ([]tc.Division, error) {
 	for rows.Next() {
 		var d tc.Division
 		if err = rows.StructScan(&d); err != nil {
-			return nil, fmt.Errorf("getting divisions: %v", err)
+			return nil, []error{fmt.Errorf("getting divisions: %v", err)}, tc.SystemError
 		}
 		o = append(o, d)
 	}
-	return o, nil
+	return o, nil, tc.NoError
 }
 
 func selectDivisionsQuery() string {
diff --git a/traffic_ops/traffic_ops_golang/divisions_test.go b/traffic_ops/traffic_ops_golang/divisions_test.go
index 15fcba1..636b3fb5 100644
--- a/traffic_ops/traffic_ops_golang/divisions_test.go
+++ b/traffic_ops/traffic_ops_golang/divisions_test.go
@@ -20,7 +20,6 @@ package main
  */
 
 import (
-	"net/url"
 	"testing"
 	"time"
 
@@ -69,12 +68,11 @@ func TestGetDivisions(t *testing.T) {
 		)
 	}
 	mock.ExpectQuery("SELECT").WillReturnRows(rows)
-	v := url.Values{}
-	v.Set("dsId", "1")
+	v := map[string]string{"dsId": "1"}
 
-	servers, err := getDivisions(v, db)
-	if err != nil {
-		t.Errorf("getDivisions expected: nil error, actual: %v", err)
+	servers, errs, errType := getDivisions(v, db)
+	if len(errs) > 0 {
+		t.Errorf("getDivisions expected: no errors, actual: %v with error type: %s", errs, errType.String())
 	}
 
 	if len(servers) != 2 {
diff --git a/traffic_ops/traffic_ops_golang/hwinfo.go b/traffic_ops/traffic_ops_golang/hwinfo.go
index a50b949..2502dbf 100644
--- a/traffic_ops/traffic_ops_golang/hwinfo.go
+++ b/traffic_ops/traffic_ops_golang/hwinfo.go
@@ -23,9 +23,10 @@ import (
 	"encoding/json"
 	"fmt"
 	"net/http"
-	"net/url"
 
+	"github.com/apache/incubator-trafficcontrol/lib/go-log"
 	"github.com/apache/incubator-trafficcontrol/lib/go-tc"
+	"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/api"
 	"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/dbhelpers"
 	"github.com/jmoiron/sqlx"
 )
@@ -34,10 +35,15 @@ func hwInfoHandler(db *sqlx.DB) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		handleErrs := tc.GetHandleErrorsFunc(w, r)
 
-		q := r.URL.Query()
-		resp, err := getHWInfoResponse(q, db)
+		params, err := api.GetCombinedParams(r)
 		if err != nil {
+			log.Errorf("unable to get parameters from request: %s", err)
 			handleErrs(http.StatusInternalServerError, err)
+		}
+
+		resp, errs, errType := getHWInfoResponse(params, db)
+		if len(errs) > 0 {
+			tc.HandleErrorsWithType(errs, errType, handleErrs)
 			return
 		}
 
@@ -52,38 +58,44 @@ func hwInfoHandler(db *sqlx.DB) http.HandlerFunc {
 	}
 }
 
-func getHWInfoResponse(q url.Values, db *sqlx.DB) (*tc.HWInfoResponse, error) {
-	hwInfo, err := getHWInfo(q, db)
-	if err != nil {
-		return nil, fmt.Errorf("getting hwInfo response: %v", err)
+func getHWInfoResponse(params map[string]string, db *sqlx.DB) (*tc.HWInfoResponse, []error, tc.ApiErrorType) {
+	hwInfo, errs, errType := getHWInfo(params, db)
+	if len(errs) > 0 {
+		return nil, errs, errType
 	}
 
 	resp := tc.HWInfoResponse{
 		Response: hwInfo,
 	}
-	return &resp, nil
+	return &resp, nil, tc.NoError
 }
 
-func getHWInfo(v url.Values, db *sqlx.DB) ([]tc.HWInfo, error) {
+func getHWInfo(params map[string]string, db *sqlx.DB) ([]tc.HWInfo, []error, tc.ApiErrorType) {
 	var rows *sqlx.Rows
 	var err error
 
 	// Query Parameters to Database Query column mappings
 	// see the fields mapped in the SQL query
-	queryParamsToSQLCols := map[string]string{
-		"id":             "h.id",
-		"serverHostName": "s.serverHostName",
-		"serverId":       "s.serverid",
-		"description":    "h.description",
-		"val":            "h.val",
-		"lastUpdated":    "h.last_updated",
+	queryParamsToSQLCols := map[string]dbhelpers.WhereColumnInfo{
+		"id":             dbhelpers.WhereColumnInfo{"h.id", api.IsInt},
+		"serverHostName": dbhelpers.WhereColumnInfo{"s.host_name", nil},
+		"serverId":       dbhelpers.WhereColumnInfo{"s.id", api.IsInt}, // TODO: this can be either s.id or h.serverid not sure what makes the most sense
+		"description":    dbhelpers.WhereColumnInfo{"h.description", nil},
+		"val":            dbhelpers.WhereColumnInfo{"h.val", nil},
+		"lastUpdated":    dbhelpers.WhereColumnInfo{"h.last_updated", nil}, //TODO: this doesn't appear to work needs debugging
+	}
+
+	where, orderBy, queryValues, errs := dbhelpers.BuildWhereAndOrderBy(params, queryParamsToSQLCols)
+	if len(errs) > 0 {
+		return nil, errs, tc.DataConflictError
 	}
 
-	query, queryValues := dbhelpers.BuildQuery(v, selectHWInfoQuery(), queryParamsToSQLCols)
+	query := selectHWInfoQuery() + where + orderBy
+	log.Debugln("Query is ", query)
 
 	rows, err = db.NamedQuery(query, queryValues)
 	if err != nil {
-		return nil, err
+		return nil, []error{err}, tc.SystemError
 	}
 	defer rows.Close()
 
@@ -91,11 +103,11 @@ func getHWInfo(v url.Values, db *sqlx.DB) ([]tc.HWInfo, error) {
 	for rows.Next() {
 		var s tc.HWInfo
 		if err = rows.StructScan(&s); err != nil {
-			return nil, fmt.Errorf("getting hwInfo: %v", err)
+			return nil, []error{fmt.Errorf("getting hwInfo: %v", err)}, tc.SystemError
 		}
 		hwInfo = append(hwInfo, s)
 	}
-	return hwInfo, nil
+	return hwInfo, nil, tc.NoError
 }
 
 func selectHWInfoQuery() string {
diff --git a/traffic_ops/traffic_ops_golang/hwinfo_test.go b/traffic_ops/traffic_ops_golang/hwinfo_test.go
index 507dd8c..0a2a4f8 100644
--- a/traffic_ops/traffic_ops_golang/hwinfo_test.go
+++ b/traffic_ops/traffic_ops_golang/hwinfo_test.go
@@ -22,7 +22,6 @@ package main
 import (
 	"encoding/json"
 	"fmt"
-	"net/url"
 	"testing"
 	"time"
 
@@ -82,12 +81,11 @@ func TestGetHWInfo(t *testing.T) {
 		)
 	}
 	mock.ExpectQuery("SELECT").WillReturnRows(rows)
-	v := url.Values{}
-	v.Set("ServerId", "1")
+	v := map[string]string{"ServerId": "1"}
 
-	hwinfos, err := getHWInfo(v, db)
-	if err != nil {
-		t.Errorf("getHWInfo expected: nil error, actual: %v", err)
+	hwinfos, errs, errType := getHWInfo(v, db)
+	if len(errs) > 0 {
+		t.Errorf("getHWInfo expected: no errors, actual: %v with error type: %s", errs, errType.String())
 	}
 
 	if len(hwinfos) != 2 {
diff --git a/traffic_ops/traffic_ops_golang/monitoring.go b/traffic_ops/traffic_ops_golang/monitoring.go
index fd3ba8c..57f1de8 100644
--- a/traffic_ops/traffic_ops_golang/monitoring.go
+++ b/traffic_ops/traffic_ops_golang/monitoring.go
@@ -30,6 +30,7 @@ import (
 	"github.com/jmoiron/sqlx"
 	"github.com/lib/pq"
 
+	"github.com/apache/incubator-trafficcontrol/lib/go-log"
 	"github.com/apache/incubator-trafficcontrol/lib/go-tc"
 	"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/api"
 )
@@ -133,18 +134,17 @@ func monitoringHandler(db *sqlx.DB) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		handleErrs := tc.GetHandleErrorsFunc(w, r)
 
-		ctx := r.Context()
-		pathParams, err := api.GetPathParams(ctx)
+		params, err := api.GetCombinedParams(r)
 		if err != nil {
+			log.Errorf("unable to get parameters from request: %s", err)
 			handleErrs(http.StatusInternalServerError, err)
-			return
 		}
 
-		cdnName := pathParams["name"]
+		cdnName := params["name"]
 
-		resp, err := getMonitoringJSON(cdnName, db)
+		resp, err, errType := getMonitoringJSON(cdnName, db)
 		if err != nil {
-			handleErrs(http.StatusInternalServerError, err)
+			tc.HandleErrorsWithType([]error{err}, errType, handleErrs)
 			return
 		}
 
@@ -416,30 +416,30 @@ WHERE pr.config_file = '%s'
 	return cfg, nil
 }
 
-func getMonitoringJSON(cdnName string, db *sqlx.DB) (*MonitoringResponse, error) {
+func getMonitoringJSON(cdnName string, db *sqlx.DB) (*MonitoringResponse, error, tc.ApiErrorType) {
 	monitors, caches, routers, err := getMonitoringServers(db, cdnName)
 	if err != nil {
-		return nil, fmt.Errorf("error getting servers: %v", err)
+		return nil, fmt.Errorf("error getting servers: %v", err), tc.SystemError
 	}
 
 	cachegroups, err := getCachegroups(db, cdnName)
 	if err != nil {
-		return nil, fmt.Errorf("error getting cachegroups: %v", err)
+		return nil, fmt.Errorf("error getting cachegroups: %v", err), tc.SystemError
 	}
 
 	profiles, err := getProfiles(db, caches, routers)
 	if err != nil {
-		return nil, fmt.Errorf("error getting profiles: %v", err)
+		return nil, fmt.Errorf("error getting profiles: %v", err), tc.SystemError
 	}
 
 	deliveryServices, err := getDeliveryServices(db, routers)
 	if err != nil {
-		return nil, fmt.Errorf("error getting deliveryservices: %v", err)
+		return nil, fmt.Errorf("error getting deliveryservices: %v", err), tc.SystemError
 	}
 
 	config, err := getConfig(db)
 	if err != nil {
-		return nil, fmt.Errorf("error getting config: %v", err)
+		return nil, fmt.Errorf("error getting config: %v", err), tc.SystemError
 	}
 
 	resp := MonitoringResponse{
@@ -452,5 +452,5 @@ func getMonitoringJSON(cdnName string, db *sqlx.DB) (*MonitoringResponse, error)
 			Config:           config,
 		},
 	}
-	return &resp, nil
+	return &resp, nil, tc.NoError
 }
diff --git a/traffic_ops/traffic_ops_golang/monitoring_test.go b/traffic_ops/traffic_ops_golang/monitoring_test.go
index d31171b..f7dbc36 100644
--- a/traffic_ops/traffic_ops_golang/monitoring_test.go
+++ b/traffic_ops/traffic_ops_golang/monitoring_test.go
@@ -615,9 +615,9 @@ func TestGetMonitoringJSON(t *testing.T) {
 		resp.Response.Config = config
 	}
 
-	sqlResp, err := getMonitoringJSON(cdn, db)
+	sqlResp, err, errType := getMonitoringJSON(cdn, db)
 	if err != nil {
-		t.Errorf("getMonitoringJSON expected: nil error, actual: %v", err)
+		t.Errorf("getMonitoringJSON expected: nil error, actual: %v with error type: %s", err, errType.String())
 	}
 
 	resp.Response.TrafficServers = sortCaches(resp.Response.TrafficServers)
diff --git a/traffic_ops/traffic_ops_golang/parameters.go b/traffic_ops/traffic_ops_golang/parameters.go
index 8025403..bbba922 100644
--- a/traffic_ops/traffic_ops_golang/parameters.go
+++ b/traffic_ops/traffic_ops_golang/parameters.go
@@ -23,10 +23,10 @@ import (
 	"encoding/json"
 	"fmt"
 	"net/http"
-	"net/url"
 
 	"github.com/apache/incubator-trafficcontrol/lib/go-log"
 	"github.com/apache/incubator-trafficcontrol/lib/go-tc"
+	"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/api"
 	"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/auth"
 	"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/dbhelpers"
 
@@ -45,10 +45,15 @@ func parametersHandler(db *sqlx.DB) http.HandlerFunc {
 		}
 		privLevel := user.PrivLevel
 
-		q := r.URL.Query()
-		resp, err := getParametersResponse(q, db, privLevel)
+		params, err := api.GetCombinedParams(r)
 		if err != nil {
+			log.Errorf("unable to get parameters from request: %s", err)
 			handleErrs(http.StatusInternalServerError, err)
+		}
+
+		resp, errs, errType := getParametersResponse(params, db, privLevel)
+		if len(errs) > 0 {
+			tc.HandleErrorsWithType(errs, errType, handleErrs)
 			return
 		}
 
@@ -63,40 +68,44 @@ func parametersHandler(db *sqlx.DB) http.HandlerFunc {
 	}
 }
 
-func getParametersResponse(q url.Values, db *sqlx.DB, privLevel int) (*tc.ParametersResponse, error) {
-	parameters, err := getParameters(q, db, privLevel)
-	if err != nil {
-		return nil, fmt.Errorf("getting parameters response: %v", err)
+func getParametersResponse(params map[string]string, db *sqlx.DB, privLevel int) (*tc.ParametersResponse, []error, tc.ApiErrorType) {
+	parameters, errs, errType := getParameters(params, db, privLevel)
+	if len(errs) > 0 {
+		return nil, errs, errType
 	}
 
 	resp := tc.ParametersResponse{
 		Response: parameters,
 	}
-	return &resp, nil
+	return &resp, nil, tc.NoError
 }
 
-func getParameters(v url.Values, db *sqlx.DB, privLevel int) ([]tc.Parameter, error) {
+func getParameters(params map[string]string, db *sqlx.DB, privLevel int) ([]tc.Parameter, []error, tc.ApiErrorType) {
 
 	var rows *sqlx.Rows
 	var err error
 
 	// Query Parameters to Database Query column mappings
 	// see the fields mapped in the SQL query
-	queryParamsToSQLCols := map[string]string{
-		"config_file":  "p.config_file",
-		"id":           "p.id",
-		"last_updated": "p.last_updated",
-		"name":         "p.name",
-		"secure":       "p.secure",
+	queryParamsToSQLCols := map[string]dbhelpers.WhereColumnInfo{
+		"config_file":  dbhelpers.WhereColumnInfo{"p.config_file", nil},
+		"id":           dbhelpers.WhereColumnInfo{"p.id", api.IsInt},
+		"last_updated": dbhelpers.WhereColumnInfo{"p.last_updated", nil},
+		"name":         dbhelpers.WhereColumnInfo{"p.name", nil},
+		"secure":       dbhelpers.WhereColumnInfo{"p.secure", api.IsBool},
 	}
 
-	query, queryValues := dbhelpers.BuildQuery(v, selectParametersQuery(), queryParamsToSQLCols)
+	where, orderBy, queryValues, errs := dbhelpers.BuildWhereAndOrderBy(params, queryParamsToSQLCols)
+	if len(errs) > 0 {
+		return nil, errs, tc.DataConflictError
+	}
 
-	query += ParametersGroupBy()
+	query := selectParametersQuery() + where + ParametersGroupBy() + orderBy
 	log.Debugln("Query is ", query)
+
 	rows, err = db.NamedQuery(query, queryValues)
 	if err != nil {
-		return nil, fmt.Errorf("querying: %v", err)
+		return nil, []error{fmt.Errorf("querying: %v", err)}, tc.SystemError
 	}
 	defer rows.Close()
 
@@ -104,7 +113,7 @@ func getParameters(v url.Values, db *sqlx.DB, privLevel int) ([]tc.Parameter, er
 	for rows.Next() {
 		var s tc.Parameter
 		if err = rows.StructScan(&s); err != nil {
-			return nil, fmt.Errorf("getting parameters: %v", err)
+			return nil, []error{fmt.Errorf("getting parameters: %v", err)}, tc.SystemError
 		}
 		if s.Secure && privLevel < auth.PrivLevelAdmin {
 			// Secure params only visible to admin
@@ -112,7 +121,7 @@ func getParameters(v url.Values, db *sqlx.DB, privLevel int) ([]tc.Parameter, er
 		}
 		parameters = append(parameters, s)
 	}
-	return parameters, nil
+	return parameters, nil, tc.NoError
 }
 
 func selectParametersQuery() string {
diff --git a/traffic_ops/traffic_ops_golang/parameters_test.go b/traffic_ops/traffic_ops_golang/parameters_test.go
index 3a0616e..8a26b6b 100644
--- a/traffic_ops/traffic_ops_golang/parameters_test.go
+++ b/traffic_ops/traffic_ops_golang/parameters_test.go
@@ -20,7 +20,6 @@ package main
  */
 
 import (
-	"net/url"
 	"testing"
 	"time"
 
@@ -85,12 +84,11 @@ func TestGetParameters(t *testing.T) {
 		)
 	}
 	mock.ExpectQuery("SELECT").WillReturnRows(rows)
-	v := url.Values{}
-	v.Set("dsId", "1")
+	v := map[string]string{"dsId": "1"}
 
-	parameters, err := getParameters(v, db, auth.PrivLevelAdmin)
-	if err != nil {
-		t.Errorf("getParameters expected: nil error, actual: %v", err)
+	parameters, errs, errType := getParameters(v, db, auth.PrivLevelAdmin)
+	if len(errs) > 0 {
+		t.Errorf("getParameters expected: no errors, actual: %v with error type: %s", errs, errType.String())
 	}
 
 	if len(parameters) != 2 {
diff --git a/traffic_ops/traffic_ops_golang/phys_locations.go b/traffic_ops/traffic_ops_golang/phys_locations.go
index 538970d..b76cafb 100644
--- a/traffic_ops/traffic_ops_golang/phys_locations.go
+++ b/traffic_ops/traffic_ops_golang/phys_locations.go
@@ -23,8 +23,8 @@ import (
 	"encoding/json"
 	"fmt"
 	"net/http"
-	"net/url"
 
+	"github.com/apache/incubator-trafficcontrol/lib/go-log"
 	"github.com/apache/incubator-trafficcontrol/lib/go-tc"
 	"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/api"
 	"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/dbhelpers"
@@ -35,21 +35,15 @@ func physLocationsHandler(db *sqlx.DB) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		handleErrs := tc.GetHandleErrorsFunc(w, r)
 
-		ctx := r.Context()
-		pathParams, err := api.GetPathParams(ctx)
+		params, err := api.GetCombinedParams(r)
 		if err != nil {
+			log.Errorf("unable to get parameters from request: %s", err)
 			handleErrs(http.StatusInternalServerError, err)
-			return
 		}
 
-		// Load the PathParams into the query parameters for pass through
-		q := r.URL.Query()
-		for k, v := range pathParams {
-			q.Set(k, v)
-		}
-		resp, err := getPhysLocationsResponse(q, db)
-		if err != nil {
-			handleErrs(http.StatusInternalServerError, err)
+		resp, errs, errType := getPhysLocationsResponse(params, db)
+		if len(errs) > 0 {
+			tc.HandleErrorsWithType(errs, errType, handleErrs)
 			return
 		}
 
@@ -64,34 +58,39 @@ func physLocationsHandler(db *sqlx.DB) http.HandlerFunc {
 	}
 }
 
-func getPhysLocationsResponse(q url.Values, db *sqlx.DB) (*tc.PhysLocationsResponse, error) {
-	physLocations, err := getPhysLocations(q, db)
-	if err != nil {
-		return nil, fmt.Errorf("getting physLocations response: %v", err)
+func getPhysLocationsResponse(params map[string]string, db *sqlx.DB) (*tc.PhysLocationsResponse, []error, tc.ApiErrorType) {
+	physLocations, errs, errType := getPhysLocations(params, db)
+	if len(errs) > 0 {
+		return nil, errs, errType
 	}
-
 	resp := tc.PhysLocationsResponse{
 		Response: physLocations,
 	}
-	return &resp, nil
+	return &resp, nil, tc.NoError
 }
 
-func getPhysLocations(v url.Values, db *sqlx.DB) ([]tc.PhysLocation, error) {
+func getPhysLocations(params map[string]string, db *sqlx.DB) ([]tc.PhysLocation, []error, tc.ApiErrorType) {
 	var rows *sqlx.Rows
 	var err error
 
 	// Query Parameters to Database Query column mappings
 	// see the fields mapped in the SQL query
-	queryParamsToQueryCols := map[string]string{
-		"id":     "pl.id",
-		"region": "pl.region",
+	queryParamsToQueryCols := map[string]dbhelpers.WhereColumnInfo{
+		"id":     dbhelpers.WhereColumnInfo{"pl.id", api.IsInt},
+		"region": dbhelpers.WhereColumnInfo{"pl.region", api.IsInt},
+	}
+
+	where, orderBy, queryValues, errs := dbhelpers.BuildWhereAndOrderBy(params, queryParamsToQueryCols)
+	if len(errs) > 0 {
+		return nil, errs, tc.DataConflictError
 	}
 
-	query, queryValues := dbhelpers.BuildQuery(v, selectPhysLocationsQuery(), queryParamsToQueryCols)
+	query := selectPhysLocationsQuery() + where + orderBy
+	log.Debugln("Query is ", query)
 
 	rows, err = db.NamedQuery(query, queryValues)
 	if err != nil {
-		return nil, err
+		return nil, []error{err}, tc.SystemError
 	}
 	defer rows.Close()
 
@@ -99,11 +98,11 @@ func getPhysLocations(v url.Values, db *sqlx.DB) ([]tc.PhysLocation, error) {
 	for rows.Next() {
 		var s tc.PhysLocation
 		if err = rows.StructScan(&s); err != nil {
-			return nil, fmt.Errorf("getting physLocations: %v", err)
+			return nil, []error{fmt.Errorf("getting physLocations: %v", err)}, tc.SystemError
 		}
 		physLocations = append(physLocations, s)
 	}
-	return physLocations, nil
+	return physLocations, nil, tc.NoError
 }
 
 func selectPhysLocationsQuery() string {
diff --git a/traffic_ops/traffic_ops_golang/phys_locations_test.go b/traffic_ops/traffic_ops_golang/phys_locations_test.go
index 65e02f1..b47c69c 100644
--- a/traffic_ops/traffic_ops_golang/phys_locations_test.go
+++ b/traffic_ops/traffic_ops_golang/phys_locations_test.go
@@ -20,7 +20,6 @@ package main
  */
 
 import (
-	"net/url"
 	"testing"
 	"time"
 
@@ -90,12 +89,11 @@ func TestGetPhysLocations(t *testing.T) {
 		)
 	}
 	mock.ExpectQuery("SELECT").WillReturnRows(rows)
-	v := url.Values{}
-	v.Set("dsId", "1")
+	v := map[string]string{"dsId": "1"}
 
-	servers, err := getPhysLocations(v, db)
-	if err != nil {
-		t.Errorf("getPhysLocations expected: nil error, actual: %v", err)
+	servers, errs, errType := getPhysLocations(v, db)
+	if len(errs) > 0 {
+		t.Errorf("getPhysLocations expected: no errors, actual: %v with error type: %s", err, errType.String())
 	}
 
 	if len(servers) != 2 {
diff --git a/traffic_ops/traffic_ops_golang/regions.go b/traffic_ops/traffic_ops_golang/regions.go
index 7f8f85d..66e06ef 100644
--- a/traffic_ops/traffic_ops_golang/regions.go
+++ b/traffic_ops/traffic_ops_golang/regions.go
@@ -23,8 +23,8 @@ import (
 	"encoding/json"
 	"fmt"
 	"net/http"
-	"net/url"
 
+	"github.com/apache/incubator-trafficcontrol/lib/go-log"
 	"github.com/apache/incubator-trafficcontrol/lib/go-tc"
 	"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/api"
 	"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/dbhelpers"
@@ -35,21 +35,15 @@ func regionsHandler(db *sqlx.DB) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		handleErrs := tc.GetHandleErrorsFunc(w, r)
 
-		ctx := r.Context()
-		pathParams, err := api.GetPathParams(ctx)
+		params, err := api.GetCombinedParams(r)
 		if err != nil {
+			log.Errorf("unable to get parameters from request: %s", err)
 			handleErrs(http.StatusInternalServerError, err)
-			return
 		}
 
-		// Load the PathParams into the query parameters for pass through
-		q := r.URL.Query()
-		for k, v := range pathParams {
-			q.Set(k, v)
-		}
-		resp, err := getRegionsResponse(q, db)
-		if err != nil {
-			handleErrs(http.StatusInternalServerError, err)
+		resp, errs, errType := getRegionsResponse(params, db)
+		if len(errs) > 0 {
+			tc.HandleErrorsWithType(errs, errType, handleErrs)
 			return
 		}
 
@@ -64,35 +58,41 @@ func regionsHandler(db *sqlx.DB) http.HandlerFunc {
 	}
 }
 
-func getRegionsResponse(q url.Values, db *sqlx.DB) (*tc.RegionsResponse, error) {
-	regions, err := getRegions(q, db)
-	if err != nil {
-		return nil, fmt.Errorf("getting regions response: %v", err)
+func getRegionsResponse(params map[string]string, db *sqlx.DB) (*tc.RegionsResponse, []error, tc.ApiErrorType) {
+	regions, errs, errType := getRegions(params, db)
+	if len(errs) > 0 {
+		return nil, errs, errType
 	}
 
 	resp := tc.RegionsResponse{
 		Response: regions,
 	}
-	return &resp, nil
+	return &resp, nil, tc.NoError
 }
 
-func getRegions(v url.Values, db *sqlx.DB) ([]tc.Region, error) {
+func getRegions(params map[string]string, db *sqlx.DB) ([]tc.Region, []error, tc.ApiErrorType) {
 	var rows *sqlx.Rows
 	var err error
 
 	// Query Parameters to Database Query column mappings
 	// see the fields mapped in the SQL query
-	queryParamsToQueryCols := map[string]string{
-		"division": "d.id",
-		"id":       "r.id",
-		"name":     "r.name",
+	queryParamsToQueryCols := map[string]dbhelpers.WhereColumnInfo{
+		"division": dbhelpers.WhereColumnInfo{"d.id", api.IsInt},
+		"id":       dbhelpers.WhereColumnInfo{"r.id", api.IsInt},
+		"name":     dbhelpers.WhereColumnInfo{"r.name", nil},
+	}
+
+	where, orderBy, queryValues, errs := dbhelpers.BuildWhereAndOrderBy(params, queryParamsToQueryCols)
+	if len(errs) > 0 {
+		return nil, errs, tc.DataConflictError
 	}
 
-	query, queryValues := dbhelpers.BuildQuery(v, selectRegionsQuery(), queryParamsToQueryCols)
+	query := selectRegionsQuery() + where + orderBy
+	log.Debugln("Query is ", query)
 
 	rows, err = db.NamedQuery(query, queryValues)
 	if err != nil {
-		return nil, err
+		return nil, []error{err}, tc.SystemError
 	}
 	defer rows.Close()
 
@@ -100,11 +100,11 @@ func getRegions(v url.Values, db *sqlx.DB) ([]tc.Region, error) {
 	for rows.Next() {
 		var s tc.Region
 		if err = rows.StructScan(&s); err != nil {
-			return nil, fmt.Errorf("getting regions: %v", err)
+			return nil, []error{fmt.Errorf("getting regions: %v", err)}, tc.SystemError
 		}
 		regions = append(regions, s)
 	}
-	return regions, nil
+	return regions, nil, tc.NoError
 }
 
 func selectRegionsQuery() string {
diff --git a/traffic_ops/traffic_ops_golang/regions_test.go b/traffic_ops/traffic_ops_golang/regions_test.go
index 010ba19..1b18d75 100644
--- a/traffic_ops/traffic_ops_golang/regions_test.go
+++ b/traffic_ops/traffic_ops_golang/regions_test.go
@@ -20,7 +20,6 @@ package main
  */
 
 import (
-	"net/url"
 	"testing"
 	"time"
 
@@ -72,12 +71,11 @@ func TestGetRegions(t *testing.T) {
 		)
 	}
 	mock.ExpectQuery("SELECT").WillReturnRows(rows)
-	v := url.Values{}
-	v.Set("dsId", "1")
+	v := map[string]string{"dsId": "1"}
 
-	servers, err := getRegions(v, db)
-	if err != nil {
-		t.Errorf("getRegions expected: nil error, actual: %v", err)
+	servers, errs, errType := getRegions(v, db)
+	if len(errs) > 0 {
+		t.Errorf("getRegions expected: no errors, actual: %v with error type: %s", errs, errType.String())
 	}
 
 	if len(servers) != 2 {
diff --git a/traffic_ops/traffic_ops_golang/routing.go b/traffic_ops/traffic_ops_golang/routing.go
index af6f25d..070ac75 100644
--- a/traffic_ops/traffic_ops_golang/routing.go
+++ b/traffic_ops/traffic_ops_golang/routing.go
@@ -165,7 +165,7 @@ func Handler(routes map[string][]CompiledRoute, catchall http.Handler, w http.Re
 
 		ctx := r.Context()
 
-		params := api.PathParams{}
+		params := map[string]string{}
 		for i, v := range compiledRoute.Params {
 			params[v] = match[i+1]
 		}
diff --git a/traffic_ops/traffic_ops_golang/servers.go b/traffic_ops/traffic_ops_golang/servers.go
index 1d2f34e..9f8bc4f 100644
--- a/traffic_ops/traffic_ops_golang/servers.go
+++ b/traffic_ops/traffic_ops_golang/servers.go
@@ -21,10 +21,8 @@ package main
 
 import (
 	"encoding/json"
-	"errors"
 	"fmt"
 	"net/http"
-	"net/url"
 	"strconv"
 
 	"github.com/apache/incubator-trafficcontrol/lib/go-log"
@@ -49,28 +47,21 @@ func serversHandler(db *sqlx.DB) http.HandlerFunc {
 		}
 		privLevel := user.PrivLevel
 
-		pathParams, err := api.GetPathParams(ctx)
+		params, err := api.GetCombinedParams(r)
 		if err != nil {
+			log.Errorf("unable to get parameters from request: %s", err)
 			handleErrs(http.StatusInternalServerError, err)
-			return
 		}
 
-		q := r.URL.Query()
-		// TODO: move this checking to a common area so all endpoints can use it
-		for k, v := range pathParams {
-			if k == `id` {
-				if _, err := strconv.Atoi(v); err != nil {
-					log.Errorf("Expected {id} to be an integer: %s", v)
-					handleErrs(http.StatusNotFound, errors.New("Resource not found")) //matches perl response
+		resp, errs, errType := getServersResponse(params, db, privLevel)
+		if len(errs) > 0 {
+			for _, err := range errs {
+				if err.Error() == `id cannot parse to integer` {
+					handleErrs(http.StatusNotFound, errors.New("Resource not found.")) //matches perl response
 					return
 				}
 			}
-			q.Set(k, v)
-		}
-		resp, err := getServersResponse(q, db, privLevel)
-		if err != nil {
-			log.Errorln(err)
-			handleErrs(http.StatusInternalServerError, err)
+			tc.HandleErrorsWithType(errs, errType, handleErrs)
 			return
 		}
 
@@ -86,41 +77,47 @@ func serversHandler(db *sqlx.DB) http.HandlerFunc {
 	}
 }
 
-func getServersResponse(v url.Values, db *sqlx.DB, privLevel int) (*tc.ServersResponse, error) {
-	servers, err := getServers(v, db, privLevel)
-	if err != nil {
-		return nil, fmt.Errorf("getting servers response: %v", err)
+func getServersResponse(params map[string]string, db *sqlx.DB, privLevel int) (*tc.ServersResponse, []error, tc.ApiErrorType) {
+	servers, errs, errType := getServers(params, db, privLevel)
+	if len(errs) > 0 {
+		return nil, errs, errType
 	}
 
 	resp := tc.ServersResponse{
 		Response: servers,
 	}
-	return &resp, nil
+	return &resp, nil, tc.NoError
 }
 
-func getServers(v url.Values, db *sqlx.DB, privLevel int) ([]tc.Server, error) {
+func getServers(params map[string]string, db *sqlx.DB, privLevel int) ([]tc.Server, []error, tc.ApiErrorType) {
 
 	var rows *sqlx.Rows
 	var err error
 
 	// Query Parameters to Database Query column mappings
 	// see the fields mapped in the SQL query
-	queryParamsToSQLCols := map[string]string{
-		"cachegroup":   "s.cachegroup",
-		"cdn":          "s.cdn_id",
-		"id":           "s.id",
-		"hostName":     "s.host_name",
-		"physLocation": "s.phys_location",
-		"profileId":    "s.profile",
-		"status":       "st.name",
-		"type":         "t.name",
+	queryParamsToSQLCols := map[string]dbhelpers.WhereColumnInfo{
+		"cachegroup":   dbhelpers.WhereColumnInfo{"s.cachegroup", api.IsInt},
+		"cdn":          dbhelpers.WhereColumnInfo{"s.cdn_id", api.IsInt},
+		"id":           dbhelpers.WhereColumnInfo{"s.id", api.IsInt},
+		"hostName":     dbhelpers.WhereColumnInfo{"s.host_name", nil},
+		"physLocation": dbhelpers.WhereColumnInfo{"s.phys_location", api.IsInt},
+		"profileId":    dbhelpers.WhereColumnInfo{"s.profile", api.IsInt},
+		"status":       dbhelpers.WhereColumnInfo{"st.name", nil},
+		"type":         dbhelpers.WhereColumnInfo{"t.name", nil},
+	}
+
+	where, orderBy, queryValues, errs := dbhelpers.BuildWhereAndOrderBy(params, queryParamsToSQLCols)
+	if len(errs) > 0 {
+		return nil, errs, tc.DataConflictError
 	}
 
-	query, queryValues := dbhelpers.BuildQuery(v, selectServersQuery(), queryParamsToSQLCols)
+	query := selectServersQuery() + where + orderBy
+	log.Debugln("Query is ", query)
 
 	rows, err = db.NamedQuery(query, queryValues)
 	if err != nil {
-		return nil, fmt.Errorf("querying: %v", err)
+		return nil, []error{fmt.Errorf("querying: %v", err)}, tc.SystemError
 	}
 	defer rows.Close()
 
@@ -131,7 +128,7 @@ func getServers(v url.Values, db *sqlx.DB, privLevel int) ([]tc.Server, error) {
 	for rows.Next() {
 		var s tc.Server
 		if err = rows.StructScan(&s); err != nil {
-			return nil, fmt.Errorf("getting servers: %v", err)
+			return nil, []error{fmt.Errorf("getting servers: %v", err)}, tc.SystemError
 		}
 		if privLevel < auth.PrivLevelAdmin {
 			s.ILOPassword = HiddenField
@@ -139,7 +136,7 @@ func getServers(v url.Values, db *sqlx.DB, privLevel int) ([]tc.Server, error) {
 		}
 		servers = append(servers, s)
 	}
-	return servers, nil
+	return servers, nil, tc.NoError
 }
 
 func selectServersQuery() string {
diff --git a/traffic_ops/traffic_ops_golang/servers_assignment.go b/traffic_ops/traffic_ops_golang/servers_assignment.go
index 872e8be..b04883c 100644
--- a/traffic_ops/traffic_ops_golang/servers_assignment.go
+++ b/traffic_ops/traffic_ops_golang/servers_assignment.go
@@ -40,12 +40,10 @@ func assignDeliveryServicesToServerHandler(db *sqlx.DB) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		handleErrs := tc.GetHandleErrorsFunc(w, r)
 
-		// p PathParams, username string, privLevel int
-		ctx := r.Context()
-		pathParams, err := api.GetPathParams(ctx)
+		params, err := api.GetCombinedParams(r)
 		if err != nil {
+			log.Errorf("unable to get parameters from request: %s", err)
 			handleErrs(http.StatusInternalServerError, err)
-			return
 		}
 
 		var dsList []int
@@ -56,16 +54,14 @@ func assignDeliveryServicesToServerHandler(db *sqlx.DB) http.HandlerFunc {
 			return
 		}
 
-		q := r.URL.Query()
-
-		replaceQueryParameter := q["replace"][0]
+		replaceQueryParameter := params["replace"]
 		replace, err := strconv.ParseBool(replaceQueryParameter) //accepts 1, t, T, TRUE, true, True, 0, f, F, FALSE, false, False. for replace url parameter documentation
 		if err != nil {
 			handleErrs(http.StatusBadRequest, err)
 			return
 		}
 
-		serverPathParameter := pathParams["id"]
+		serverPathParameter := params["id"]
 		server, err := strconv.Atoi(serverPathParameter)
 		if err != nil {
 			handleErrs(http.StatusBadRequest, err)
diff --git a/traffic_ops/traffic_ops_golang/servers_test.go b/traffic_ops/traffic_ops_golang/servers_test.go
index 0dc1228..4447801 100644
--- a/traffic_ops/traffic_ops_golang/servers_test.go
+++ b/traffic_ops/traffic_ops_golang/servers_test.go
@@ -20,7 +20,6 @@ package main
  */
 
 import (
-	"net/url"
 	"testing"
 	"time"
 
@@ -159,13 +158,12 @@ func TestGetServersByCachegroup(t *testing.T) {
 		)
 	}
 	mock.ExpectQuery("SELECT").WillReturnRows(rows)
-	v := url.Values{}
-	v.Set("cachegroup", "cachegroup2")
+	v := map[string]string{"cachegroup": "cachegroup2"}
 
-	servers, err := getServers(v, db, auth.PrivLevelAdmin)
+	servers, errs, errType := getServers(v, db, auth.PrivLevelAdmin)
 	log.Debugln("%v-->", servers)
-	if err != nil {
-		t.Errorf("getServers expected: nil error, actual: %v", err)
+	if len(errs) > 0 {
+		t.Errorf("getServers expected: no errors, actual: %v with error type: %s", errs, errType.String())
 	}
 
 	if len(servers) != 3 {
diff --git a/traffic_ops/traffic_ops_golang/servers_update_status.go b/traffic_ops/traffic_ops_golang/servers_update_status.go
index 5aa1e72..b0282bd 100644
--- a/traffic_ops/traffic_ops_golang/servers_update_status.go
+++ b/traffic_ops/traffic_ops_golang/servers_update_status.go
@@ -35,14 +35,12 @@ func getServerUpdateStatusHandler(db *sqlx.DB) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		handleErrs := tc.GetHandleErrorsFunc(w, r)
 
-		// p PathParams, username string, privLevel int
-		ctx := r.Context()
-		pathParams, err := api.GetPathParams(ctx)
+		params, err := api.GetCombinedParams(r)
 		if err != nil {
+			log.Errorf("unable to get parameters from request: %s", err)
 			handleErrs(http.StatusInternalServerError, err)
-			return
 		}
-		hostName := pathParams["host_name"]
+		hostName := params["host_name"]
 
 		serverUpdateStatus, err := getServerUpdateStatus(hostName, db)
 		if err != nil {
diff --git a/traffic_ops/traffic_ops_golang/statuses.go b/traffic_ops/traffic_ops_golang/statuses.go
index f9b5954..03d38ff 100644
--- a/traffic_ops/traffic_ops_golang/statuses.go
+++ b/traffic_ops/traffic_ops_golang/statuses.go
@@ -23,14 +23,11 @@ import (
 	"encoding/json"
 	"fmt"
 	"net/http"
-	"net/url"
-	"strconv"
 
 	"github.com/apache/incubator-trafficcontrol/lib/go-log"
 	"github.com/apache/incubator-trafficcontrol/lib/go-tc"
-	"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/dbhelpers"
-
 	"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/api"
+	"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/dbhelpers"
 	"github.com/jmoiron/sqlx"
 )
 
@@ -38,29 +35,15 @@ func statusesHandler(db *sqlx.DB) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		handleErrs := tc.GetHandleErrorsFunc(w, r)
 
-		pathParams, err := api.GetPathParams(r.Context())
+		params, err := api.GetCombinedParams(r)
 		if err != nil {
+			log.Errorf("unable to get parameters from request: %s", err)
 			handleErrs(http.StatusInternalServerError, err)
-			return
-		}
-
-		q := r.URL.Query()
-
-		for k, v := range pathParams {
-			if k == `id` {
-				if _, err := strconv.Atoi(v); err != nil {
-					log.Errorf("Expected {id} to be an integer: %s", v)
-					handleErrs(http.StatusBadRequest, err)
-					return
-				}
-			}
-			q.Set(k, v)
 		}
 
-		resp, err := getStatusesResponse(q, db)
-
-		if err != nil {
-			handleErrs(http.StatusInternalServerError, err)
+		resp, errs, errType := getStatusesResponse(params, db)
+		if len(errs) > 0 {
+			tc.HandleErrorsWithType(errs, errType, handleErrs)
 			return
 		}
 
@@ -75,35 +58,41 @@ func statusesHandler(db *sqlx.DB) http.HandlerFunc {
 	}
 }
 
-func getStatusesResponse(q url.Values, db *sqlx.DB) (*tc.StatusesResponse, error) {
-	cdns, err := getStatuses(q, db)
-	if err != nil {
-		return nil, fmt.Errorf("getting cdns response: %v", err)
+func getStatusesResponse(params map[string]string, db *sqlx.DB) (*tc.StatusesResponse, []error, tc.ApiErrorType) {
+	cdns, errs, errType := getStatuses(params, db)
+	if len(errs) > 0 {
+		return nil, errs, errType
 	}
 
 	resp := tc.StatusesResponse{
 		Response: cdns,
 	}
-	return &resp, nil
+	return &resp, nil, tc.NoError
 }
 
-func getStatuses(v url.Values, db *sqlx.DB) ([]tc.Status, error) {
+func getStatuses(params map[string]string, db *sqlx.DB) ([]tc.Status, []error, tc.ApiErrorType) {
 	var rows *sqlx.Rows
 	var err error
 
 	// Query Parameters to Database Query column mappings
 	// see the fields mapped in the SQL query
-	queryParamsToSQLCols := map[string]string{
-		"id":          "id",
-		"name":        "name",
-		"description": "description",
+	queryParamsToSQLCols := map[string]dbhelpers.WhereColumnInfo{
+		"id":          dbhelpers.WhereColumnInfo{"id", api.IsInt},
+		"name":        dbhelpers.WhereColumnInfo{"name", nil},
+		"description": dbhelpers.WhereColumnInfo{"description", nil},
+	}
+
+	where, orderBy, queryValues, errs := dbhelpers.BuildWhereAndOrderBy(params, queryParamsToSQLCols)
+	if len(errs) > 0 {
+		return nil, errs, tc.DataConflictError
 	}
 
-	query, queryValues := dbhelpers.BuildQuery(v, selectStatusesQuery(), queryParamsToSQLCols)
+	query := selectStatusesQuery() + where + orderBy
+	log.Debugln("Query is ", query)
 
 	rows, err = db.NamedQuery(query, queryValues)
 	if err != nil {
-		return nil, err
+		return nil, []error{err}, tc.SystemError
 	}
 	defer rows.Close()
 
@@ -111,11 +100,11 @@ func getStatuses(v url.Values, db *sqlx.DB) ([]tc.Status, error) {
 	for rows.Next() {
 		var s tc.Status
 		if err = rows.StructScan(&s); err != nil {
-			return nil, fmt.Errorf("getting statuses: %v", err)
+			return nil, []error{fmt.Errorf("getting statuses: %v", err)}, tc.SystemError
 		}
 		statuses = append(statuses, s)
 	}
-	return statuses, nil
+	return statuses, nil, tc.NoError
 }
 
 func selectStatusesQuery() string {
diff --git a/traffic_ops/traffic_ops_golang/statuses_test.go b/traffic_ops/traffic_ops_golang/statuses_test.go
index ed92c5b..6be62e6 100644
--- a/traffic_ops/traffic_ops_golang/statuses_test.go
+++ b/traffic_ops/traffic_ops_golang/statuses_test.go
@@ -20,7 +20,6 @@ package main
  */
 
 import (
-	"net/url"
 	"testing"
 	"time"
 
@@ -74,12 +73,11 @@ func TestGetStatus(t *testing.T) {
 		)
 	}
 	mock.ExpectQuery("SELECT").WillReturnRows(rows)
-	v := url.Values{}
-	v.Set("dsId", "1")
+	v := map[string]string{"dsId": "1"}
 
-	servers, err := getStatuses(v, db)
-	if err != nil {
-		t.Errorf("getStatus expected: nil error, actual: %v", err)
+	servers, errs, errType := getStatuses(v, db)
+	if len(errs) > 0 {
+		t.Errorf("getStatus expected: no errors, actual: %v with error type: %s", errs, errType.String())
 	}
 
 	if len(servers) != 2 {
diff --git a/traffic_ops/traffic_ops_golang/tenant/tenancy.go b/traffic_ops/traffic_ops_golang/tenant/tenancy.go
index 13a8899..aea8539 100644
--- a/traffic_ops/traffic_ops_golang/tenant/tenancy.go
+++ b/traffic_ops/traffic_ops_golang/tenant/tenancy.go
@@ -22,6 +22,7 @@ package tenant
 import (
 	"database/sql"
 	"fmt"
+
 	"github.com/apache/incubator-trafficcontrol/lib/go-log"
 	"github.com/apache/incubator-trafficcontrol/lib/go-tc"
 	"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/auth"
@@ -47,7 +48,7 @@ func GetDeliveryServiceTenantInfo(xmlId string, db *sqlx.DB) (*DeliveryServiceTe
 	ds := DeliveryServiceTenantInfo{}
 	query := "SELECT xml_id,tenant_id FROM deliveryservice where xml_id = $1"
 
-	err := db.Get(&ds,query,xmlId)
+	err := db.Get(&ds, query, xmlId)
 	switch {
 	case err == sql.ErrNoRows:
 		ds = DeliveryServiceTenantInfo{}

-- 
To stop receiving notification emails like this one, please contact
dangogh@apache.org.