Repository: amp-labs/connectors
Pull request #1013 (2024-09-02 16:43:13)

fix: Require param validation Read/Write/Delete
# Background
Started adding ObjectName is required for Read operation. This is quickly going out of control. 

# Solution
I decided that ReadParams and others will natievly support validation. Which ever connector first recieves this must call it.
This makes all those comments saying `// required` or `// optional` enforced. This not only makes common package the owner of those errors but it decided where they are instantiated instead of every connector "figuring this out".

# Changes
First commit (disregard, its overriden by other 2).
Functional changes are captured here (in second commit) https://github.com/amp-labs/connectors/pull/1013/commits/aeef526b38ec2373bb075695dfae1957947112ea
The last commit touches all Read/Write/Delete methods and calls `ValidateParams`. This adds test changes.

NOTE: ListObjectMetadata is not addressed.

Cobalt0s: * **#1013** <a href="https://app.graphite.dev/github/pr/amp-labs/connectors/1013?utm_source=stack-comment-icon" target="_blank"><img src="https://static.graphite.dev/graphite-32x32-black.png" alt="Graphite" width="10px" height="10px"/></a> 👈
* `main`

This stack of pull requests is managed by Graphite. <a href="https://stacking.dev/?utm_source=stack-comment">Learn more about stacking.</a>
<h2></h2>

 Join @Cobalt0s and the rest of your teammates on <a href="https://graphite.dev?utm-source=stack-comment"><img src="https://static.graphite.dev/graphite-32x32-black.png" alt="Graphite" width="11px" height="11px"/> <b>Graphite</b></a>
  <!-- Current dependencies on/for this PR: -->

Patch:
diff --git a/common/types.go b/common/types.go
index 472ad0c7..d6b300ad 100644
--- a/common/types.go
+++ b/common/types.go
@@ -59,18 +59,6 @@ var (
 	// ErrNotImplemented is returned when a method is not implemented.
 	ErrNotImplemented = errors.New("not implemented")
 
-	// ErrMissingObjects is returned when no objects are provided in the request.
-	ErrMissingObjects = errors.New("no objects provided")
-
-	// ErrMissingRecordID is returned when resource id is missing in the request.
-	ErrMissingRecordID = errors.New("no object ID provided")
-
-	// ErrMissingFields is returned when no fields are provided for reading.
-	ErrMissingFields = errors.New("no fields provided in ReadParams")
-
-	// ErrInvalidPathJoin is returned when the path join is invalid.
-	ErrInvalidPathJoin = errors.New("invalid path join")
-
 	// ErrRequestFailed is returned when the request failed.
 	ErrRequestFailed = errors.New("request failed")
 
@@ -86,6 +74,9 @@ var (
 	// ErrEmptyJSONHTTPResponse is returned when the JSONHTTPResponse is nil.
 	ErrEmptyJSONHTTPResponse = errors.New("empty json http response")
 
+	// ErrEmptyRecordIdResponse is returned when the response body doesn't have record id.
+	ErrEmptyRecordIdResponse = errors.New("empty record id in response body")
+
 	// ErrRecordDataNotJSON is returned when the record data in WriteParams is not JSON.
 	ErrRecordDataNotJSON = errors.New("record data is not JSON")
 
diff --git a/common/validation.go b/common/validation.go
new file mode 100644
index 00000000..a0c2964a
--- /dev/null
+++ b/common/validation.go
@@ -0,0 +1,53 @@
+package common
+
+import "errors"
+
+var (
+	// ErrMissingObjects is returned when no objects are provided in the request.
+	ErrMissingObjects = errors.New("no objects provided")
+
+	// ErrMissingRecordID is returned when resource id is missing in the request.
+	ErrMissingRecordID = errors.New("no object ID provided")
+
+	// ErrMissingRecordData is returned when write data is missing in the request.
+	ErrMissingRecordData = errors.New("no data provided")
+
+	// ErrMissingFields is returned when no fields are provided for reading.
+	ErrMissingFields = errors.New("no fields provided in ReadParams")
+)
+
+func (p ReadParams) ValidateParams(withRequiredFields bool) error {
+	if len(p.ObjectName) == 0 {
+		return ErrMissingObjects
+	}
+
+	if withRequiredFields && len(p.Fields) == 0 {
+		return ErrMissingFields
+	}
+
+	return nil
+}
+
+func (p WriteParams) ValidateParams() error {
+	if len(p.ObjectName) == 0 {
+		return ErrMissingObjects
+	}
+
+	if p.RecordData == nil {
+		return ErrMissingRecordData
+	}
+
+	return nil
+}
+
+func (p DeleteParams) ValidateParams() error {
+	if len(p.ObjectName) == 0 {
+		return ErrMissingObjects
+	}
+
+	if len(p.RecordId) == 0 {
+		return ErrMissingRecordID
+	}
+
+	return nil
+}
diff --git a/mock/connector.go b/mock/connector.go
index eee0f8e4..5b3c116d 100644
--- a/mock/connector.go
+++ b/mock/connector.go
@@ -71,10 +71,18 @@ func (c *Connector) Provider() providers.Provider {
 }
 
 func (c *Connector) Read(ctx context.Context, params common.ReadParams) (*common.ReadResult, error) {
+	if err := params.ValidateParams(true); err != nil {
+		return nil, err
+	}
+
 	return c.read(ctx, params)
 }
 
 func (c *Connector) Write(ctx context.Context, params common.WriteParams) (*common.WriteResult, error) {
+	if err := params.ValidateParams(); err != nil {
+		return nil, err
+	}
+
 	return c.write(ctx, params)
 }
 
@@ -82,5 +90,9 @@ func (c *Connector) ListObjectMetadata(
 	ctx context.Context,
 	objectNames []string,
 ) (*common.ListObjectMetadataResult, error) {
+	if len(objectNames) == 0 {
+		return nil, common.ErrMissingObjects
+	}
+
 	return c.listObjectMetadata(ctx, objectNames)
 }
diff --git a/providers/apollo/read.go b/providers/apollo/read.go
index a63e441c..849771bd 100644
--- a/providers/apollo/read.go
+++ b/providers/apollo/read.go
@@ -10,6 +10,10 @@ import (
 //
 // This function executes a read operation using the given context and provided read parameters.
 func (c *Connector) Read(ctx context.Context, config common.ReadParams) (*common.ReadResult, error) {
+	if err := config.ValidateParams(true); err != nil {
+		return nil, err
+	}
+
 	url, err := c.getAPIURL(config.ObjectName, readOp)
 	if err != nil {
 		return nil, err
diff --git a/providers/apollo/write.go b/providers/apollo/write.go
index 944ddf9f..4071e6df 100644
--- a/providers/apollo/write.go
+++ b/providers/apollo/write.go
@@ -11,6 +11,10 @@ import (
 
 // Write creates/updates records in apolllo.
 func (c *Connector) Write(ctx context.Context, config common.WriteParams) (*common.WriteResult, error) {
+	if err := config.ValidateParams(); err != nil {
+		return nil, err
+	}
+
 	var write common.WriteMethod
 
 	url, err := c.getAPIURL(config.ObjectName, writeOp)
diff --git a/providers/atlassian/delete.go b/providers/atlassian/delete.go
index 7daf8bbf..7a322ed3 100644
--- a/providers/atlassian/delete.go
+++ b/providers/atlassian/delete.go
@@ -8,8 +8,8 @@ import (
 
 // Delete removes Jira issue.
 func (c *Connector) Delete(ctx context.Context, config common.DeleteParams) (*common.DeleteResult, error) {
-	if len(config.RecordId) == 0 {
-		return nil, common.ErrMissingRecordID
+	if err := config.ValidateParams(); err != nil {
+		return nil, err
 	}
 
 	url, err := c.getJiraRestApiURL("issue")
diff --git a/providers/atlassian/read.go b/providers/atlassian/read.go
index 89fa8330..491007a2 100644
--- a/providers/atlassian/read.go
+++ b/providers/atlassian/read.go
@@ -15,6 +15,10 @@ import (
 // * NextPage - to get next page which may have no elements left.
 // * Since - to scope the time frame, precision is in minutes.
 func (c *Connector) Read(ctx context.Context, config common.ReadParams) (*common.ReadResult, error) {
+	if err := config.ValidateParams(true); err != nil {
+		return nil, err
+	}
+
 	url, err := c.buildReadURL(config)
 	if err != nil {
 		return nil, err
diff --git a/providers/atlassian/write.go b/providers/atlassian/write.go
index 63de3d19..5250f872 100644
--- a/providers/atlassian/write.go
+++ b/providers/atlassian/write.go
@@ -14,6 +14,10 @@ import (
 // Update issue docs:
 // https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issues/#api-rest-api-3-issue-issueidorkey-put
 func (c *Connector) Write(ctx context.Context, config common.WriteParams) (*common.WriteResult, error) {
+	if err := config.ValidateParams(); err != nil {
+		return nil, err
+	}
+
 	url, err := c.getJiraRestApiURL("issue")
 	if err != nil {
 		return nil, err
diff --git a/providers/dynamicscrm/delete.go b/providers/dynamicscrm/delete.go
index 10ad938e..df60a224 100644
--- a/providers/dynamicscrm/delete.go
+++ b/providers/dynamicscrm/delete.go
@@ -8,12 +8,8 @@ import (
 )
 
 func (c *Connector) Delete(ctx context.Context, config common.DeleteParams) (*common.DeleteResult, error) {
-	if len(config.ObjectName) == 0 {
-		return nil, common.ErrMissingObjects
-	}
-
-	if len(config.RecordId) == 0 {
-		return nil, common.ErrMissingRecordID
+	if err := config.ValidateParams(); err != nil {
+		return nil, err
 	}
 
 	// resource id must be enclosed in brackets
diff --git a/providers/dynamicscrm/metadata.go b/providers/dynamicscrm/metadata.go
index 88456e45..d4ab1d99 100644
--- a/providers/dynamicscrm/metadata.go
+++ b/providers/dynamicscrm/metadata.go
@@ -14,6 +14,10 @@ import (
 func (c *Connector) ListObjectMetadata(
 	ctx context.Context, objectNames []string,
 ) (*common.ListObjectMetadataResult, error) {
+	if len(objectNames) == 0 {
+		return nil, common.ErrMissingObjects
+	}
+
 	// enforce string formating, then internal delegation
 	return c.listObjectMetadata(ctx, naming.NewSingularStrings(objectNames))
 }
@@ -22,7 +26,6 @@ func (c *Connector) ListObjectMetadata(
 func (c *Connector) listObjectMetadata(
 	ctx context.Context, objectNames naming.SingularStrings,
 ) (*common.ListObjectMetadataResult, error) {
-	// Ensure that objectNames is not empty
 	if len(objectNames) == 0 {
 		return nil, common.ErrMissingObjects
 	}
diff --git a/providers/dynamicscrm/read.go b/providers/dynamicscrm/read.go
index 81bd5eb9..16675163 100644
--- a/providers/dynamicscrm/read.go
+++ b/providers/dynamicscrm/read.go
@@ -15,8 +15,8 @@ import (
 // Microsoft API supports other capabilities like filtering, grouping, and sorting which we can potentially tap into later.
 // See https://learn.microsoft.com/en-us/power-apps/developer/data-platform/webapi/query-data-web-api#odata-query-options
 func (c *Connector) Read(ctx context.Context, config common.ReadParams) (*common.ReadResult, error) {
-	if len(config.ObjectName) == 0 {
-		return nil, common.ErrMissingObjects
+	if err := config.ValidateParams(true); err != nil {
+		return nil, err
 	}
 
 	url, err := c.buildReadURL(config)
diff --git a/providers/dynamicscrm/write.go b/providers/dynamicscrm/write.go
index 773326e1..79e8d650 100644
--- a/providers/dynamicscrm/write.go
+++ b/providers/dynamicscrm/write.go
@@ -10,8 +10,8 @@ import (
 // Write data will be used to Create or Update entity.
 // Return: common.WriteResult, where only the Success flag will be set.
 func (c *Connector) Write(ctx context.Context, config common.WriteParams) (*common.WriteResult, error) {
-	if len(config.ObjectName) == 0 {
-		return nil, common.ErrMissingObjects
+	if err := config.ValidateParams(); err != nil {
+		return nil, err
 	}
 
 	var resource string
diff --git a/providers/gong/metadata.go b/providers/gong/metadata.go
index da79cd2c..d70f7dae 100644
--- a/providers/gong/metadata.go
+++ b/providers/gong/metadata.go
@@ -10,7 +10,6 @@ import (
 func (c *Connector) ListObjectMetadata(
 	ctx context.Context, objectNames []string,
 ) (*common.ListObjectMetadataResult, error) {
-	// Ensure that objectNames is not empty
 	if len(objectNames) == 0 {
 		return nil, common.ErrMissingObjects
 	}
diff --git a/providers/gong/read.go b/providers/gong/read.go
index 86183040..0c1d777d 100644
--- a/providers/gong/read.go
+++ b/providers/gong/read.go
@@ -7,8 +7,8 @@ import (
 )
 
 func (c *Connector) Read(ctx context.Context, config common.ReadParams) (*common.ReadResult, error) {
-	if len(config.ObjectName) == 0 {
-		return nil, common.ErrMissingObjects
+	if err := config.ValidateParams(true); err != nil {
+		return nil, err
 	}
 
 	url, err := c.getURL(config.ObjectName)
diff --git a/providers/hubspot/metadata.go b/providers/hubspot/metadata.go
index e501ec52..75a3a00e 100644
--- a/providers/hubspot/metadata.go
+++ b/providers/hubspot/metadata.go
@@ -25,7 +25,6 @@ func (c *Connector) ListObjectMetadata( // nolint:cyclop,funlen
 	ctx context.Context,
 	objectNames []string,
 ) (*common.ListObjectMetadataResult, error) {
-	// Ensure that objectNames is not empty
 	if len(objectNames) == 0 {
 		return nil, common.ErrMissingObjects
 	}
diff --git a/providers/hubspot/read.go b/providers/hubspot/read.go
index e0d73369..36aa858f 100644
--- a/providers/hubspot/read.go
+++ b/providers/hubspot/read.go
@@ -15,6 +15,10 @@ import (
 // In case Deleted objects won’t appear in any search results.
 // Deleted objects can only be read by using this endpoint.
 func (c *Connector) Read(ctx context.Context, config common.ReadParams) (*common.ReadResult, error) {
+	if err := config.ValidateParams(true); err != nil {
+		return nil, err
+	}
+
 	var (
 		rsp *common.JSONHTTPResponse
 		err error
diff --git a/providers/hubspot/search.go b/providers/hubspot/search.go
index a7c65867..1b485095 100644
--- a/providers/hubspot/search.go
+++ b/providers/hubspot/search.go
@@ -15,6 +15,10 @@ import (
 // Archived results do not appear in search results.
 // Read more @ https://developers.hubspot.com/docs/api/crm/search
 func (c *Connector) Search(ctx context.Context, config SearchParams) (*common.ReadResult, error) {
+	if err := config.ValidateParams(); err != nil {
+		return nil, err
+	}
+
 	var (
 		rsp *common.JSONHTTPResponse
 		err error
diff --git a/providers/hubspot/types.go b/providers/hubspot/types.go
index a326a25a..45553ac9 100644
--- a/providers/hubspot/types.go
+++ b/providers/hubspot/types.go
@@ -15,6 +15,18 @@ type SearchParams struct {
 	Fields []string // optional
 }
 
+func (p SearchParams) ValidateParams() error {
+	if len(p.ObjectName) == 0 {
+		return common.ErrMissingObjects
+	}
+
+	if len(p.Fields) == 0 {
+		return common.ErrMissingFields
+	}
+
+	return nil
+}
+
 type SortBy struct {
 	// The name of the field to sort by.
 	PropertyName string `json:"propertyName,omitempty"`
diff --git a/providers/hubspot/write.go b/providers/hubspot/write.go
index 617f6041..7cdbc5d6 100644
--- a/providers/hubspot/write.go
+++ b/providers/hubspot/write.go
@@ -19,6 +19,10 @@ type writeResponse struct {
 }
 
 func (c *Connector) Write(ctx context.Context, config common.WriteParams) (*common.WriteResult, error) {
+	if err := config.ValidateParams(); err != nil {
+		return nil, err
+	}
+
 	var write common.WriteMethod
 
 	relativeURL := strings.Join([]string{"objects", config.ObjectName}, "/")
diff --git a/providers/instantly/delete.go b/providers/instantly/delete.go
index ffa78ea0..cfc47aa3 100644
--- a/providers/instantly/delete.go
+++ b/providers/instantly/delete.go
@@ -10,12 +10,8 @@ import (
 // deletion of other object types require a request payload to be added
 // c.Client.Delete does not yet support this.
 func (c *Connector) Delete(ctx context.Context, config common.DeleteParams) (*common.DeleteResult, error) {
-	if len(config.ObjectName) == 0 {
-		return nil, common.ErrMissingObjects
-	}
-
-	if len(config.RecordId) == 0 {
-		return nil, common.ErrMissingRecordID
+	if err := config.ValidateParams(); err != nil {
+		return nil, err
 	}
 
 	if !supportedObjectsByDelete.Has(config.ObjectName) {
diff --git a/providers/instantly/read.go b/providers/instantly/read.go
index 83bf9410..2d8cb23a 100644
--- a/providers/instantly/read.go
+++ b/providers/instantly/read.go
@@ -9,8 +9,8 @@ import (
 )
 
 func (c *Connector) Read(ctx context.Context, config common.ReadParams) (*common.ReadResult, error) {
-	if len(config.ObjectName) == 0 {
-		return nil, common.ErrMissingObjects
+	if err := config.ValidateParams(true); err != nil {
+		return nil, err
 	}
 
 	if !supportedObjectsByRead.Has(config.ObjectName) {
diff --git a/providers/instantly/write.go b/providers/instantly/write.go
index 3c7a5e08..84f6bd96 100644
--- a/providers/instantly/write.go
+++ b/providers/instantly/write.go
@@ -18,8 +18,8 @@ import (
 func (c *Connector) Write(
 	ctx context.Context, config common.WriteParams,
 ) (*common.WriteResult, error) {
-	if len(config.ObjectName) == 0 {
-		return nil, common.ErrMissingObjects
+	if err := config.ValidateParams(); err != nil {
+		return nil, err
 	}
 
 	if !supportedObjectsByWrite.Has(config.ObjectName) {
diff --git a/providers/intercom/delete.go b/providers/intercom/delete.go
index a916b522..d160e5d4 100644
--- a/providers/intercom/delete.go
+++ b/providers/intercom/delete.go
@@ -7,12 +7,8 @@ import (
 )
 
 func (c *Connector) Delete(ctx context.Context, config common.DeleteParams) (*common.DeleteResult, error) {
-	if len(config.ObjectName) == 0 {
-		return nil, common.ErrMissingObjects
-	}
-
-	if len(config.RecordId) == 0 {
-		return nil, common.ErrMissingRecordID
+	if err := config.ValidateParams(); err != nil {
+		return nil, err
 	}
 
 	url, err := c.getURL(config.ObjectName)
diff --git a/providers/intercom/metadata.go b/providers/intercom/metadata.go
index af594932..1f2c5458 100644
--- a/providers/intercom/metadata.go
+++ b/providers/intercom/metadata.go
@@ -10,7 +10,6 @@ import (
 func (c *Connector) ListObjectMetadata(
 	ctx context.Context, objectNames []string,
 ) (*common.ListObjectMetadataResult, error) {
-	// Ensure that objectNames is not empty
 	if len(objectNames) == 0 {
 		return nil, common.ErrMissingObjects
 	}
diff --git a/providers/intercom/read.go b/providers/intercom/read.go
index 80719b4b..60d25145 100644
--- a/providers/intercom/read.go
+++ b/providers/intercom/read.go
@@ -9,6 +9,10 @@ import (
 )
 
 func (c *Connector) Read(ctx context.Context, config common.ReadParams) (*common.ReadResult, error) {
+	if err := config.ValidateParams(true); err != nil {
+		return nil, err
+	}
+
 	url, err := c.buildReadURL(config)
 	if err != nil {
 		return nil, err
diff --git a/providers/intercom/write.go b/providers/intercom/write.go
index 4d8d3e36..3fb4a8f7 100644
--- a/providers/intercom/write.go
+++ b/providers/intercom/write.go
@@ -9,8 +9,8 @@ import (
 )
 
 func (c *Connector) Write(ctx context.Context, config common.WriteParams) (*common.WriteResult, error) {
-	if len(config.ObjectName) == 0 {
-		return nil, common.ErrMissingObjects
+	if err := config.ValidateParams(); err != nil {
+		return nil, err
 	}
 
 	url, err := c.getURL(config.ObjectName)
diff --git a/providers/marketo/metadata.go b/providers/marketo/metadata.go
index ecf54bf6..86d79d16 100644
--- a/providers/marketo/metadata.go
+++ b/providers/marketo/metadata.go
@@ -19,7 +19,6 @@ type responseObject struct {
 func (c *Connector) ListObjectMetadata(ctx context.Context,
 	objectNames []string,
 ) (*common.ListObjectMetadataResult, error) {
-	// Ensure that objectNames is not empty
 	if len(objectNames) == 0 {
 		return nil, common.ErrMissingObjects
 	}
diff --git a/providers/marketo/read.go b/providers/marketo/read.go
index c2f1bf4e..a01bf3a8 100644
--- a/providers/marketo/read.go
+++ b/providers/marketo/read.go
@@ -10,6 +10,10 @@ import (
 //
 // This function executes a read operation using the given context and.
 func (c *Connector) Read(ctx context.Context, config common.ReadParams) (*common.ReadResult, error) {
+	if err := config.ValidateParams(true); err != nil {
+		return nil, err
+	}
+
 	url, err := c.getURL(config)
 	if err != nil {
 		return nil, err
diff --git a/providers/marketo/write.go b/providers/marketo/write.go
index edd4d0ad..a134ac17 100644
--- a/providers/marketo/write.go
+++ b/providers/marketo/write.go
@@ -15,6 +15,10 @@ type writeResponse struct {
 
 // Write creates/updates records in marketo. Write currently supports operations to the leads API only.
 func (c *Connector) Write(ctx context.Context, config common.WriteParams) (*common.WriteResult, error) {
+	if err := config.ValidateParams(); err != nil {
+		return nil, err
+	}
+
 	url, err := c.getAPIURL(config.ObjectName)
 	if err != nil {
 		return nil, err
@@ -47,7 +51,7 @@ func (c *Connector) Write(ctx context.Context, config common.WriteParams) (*comm
 	// By default the id is returned as a float64
 	id, ok := id.(float64)
 	if !ok || id == 0 {
-		return nil, common.ErrMissingRecordID
+		return nil, common.ErrEmptyRecordIdResponse
 	}
 
 	return &common.WriteResult{
diff --git a/providers/outreach/metadata.go b/providers/outreach/metadata.go
index 0393e46e..08aa0276 100644
--- a/providers/outreach/metadata.go
+++ b/providers/outreach/metadata.go
@@ -20,7 +20,6 @@ type DataItem struct {
 func (c *Connector) ListObjectMetadata(ctx context.Context,
 	objectNames []string,
 ) (*common.ListObjectMetadataResult, error) {
-	// Ensure that objectNames is not empty
 	if len(objectNames) == 0 {
 		return nil, common.ErrMissingObjects
 	}
diff --git a/providers/outreach/read.go b/providers/outreach/read.go
index fbedae46..91c5941e 100644
--- a/providers/outreach/read.go
+++ b/providers/outreach/read.go
@@ -15,6 +15,10 @@ import (
 // configuration parameters. It returns the nested Attributes values read results or an error
 // if the operation fails.
 func (c *Connector) Read(ctx context.Context, config common.ReadParams) (*common.ReadResult, error) {
+	if err := config.ValidateParams(true); err != nil {
+		return nil, err
+	}
+
 	url, err := c.buildReadURL(config)
 	if err != nil {
 		return nil, err
diff --git a/providers/outreach/write.go b/providers/outreach/write.go
index 7d81f0db..4bec23f1 100644
--- a/providers/outreach/write.go
+++ b/providers/outreach/write.go
@@ -27,6 +27,10 @@ var JSONAPIContentTypeHeader = common.Header{ //nolint:gochecknoglobals
 }
 
 func (c *Connector) Write(ctx context.Context, config common.WriteParams) (*common.WriteResult, error) {
+	if err := config.ValidateParams(); err != nil {
+		return nil, err
+	}
+
 	var write common.WriteMethod
 
 	url, err := c.getApiURL(config.ObjectName)
diff --git a/providers/pipeliner/delete.go b/providers/pipeliner/delete.go
index 60bd52cd..c4d1c254 100644
--- a/providers/pipeliner/delete.go
+++ b/providers/pipeliner/delete.go
@@ -7,12 +7,8 @@ import (
 )
 
 func (c *Connector) Delete(ctx context.Context, config common.DeleteParams) (*common.DeleteResult, error) {
-	if len(config.ObjectName) == 0 {
-		return nil, common.ErrMissingObjects
-	}
-
-	if len(config.RecordId) == 0 {
-		return nil, common.ErrMissingRecordID
+	if err := config.ValidateParams(); err != nil {
+		return nil, err
 	}
 
 	url, err := c.getURL(config.ObjectName)
diff --git a/providers/pipeliner/metadata.go b/providers/pipeliner/metadata.go
index 15615424..af0ea35b 100644
--- a/providers/pipeliner/metadata.go
+++ b/providers/pipeliner/metadata.go
@@ -10,7 +10,6 @@ import (
 func (c *Connector) ListObjectMetadata(
 	ctx context.Context, objectNames []string,
 ) (*common.ListObjectMetadataResult, error) {
-	// Ensure that objectNames is not empty
 	if len(objectNames) == 0 {
 		return nil, common.ErrMissingObjects
 	}
diff --git a/providers/pipeliner/read.go b/providers/pipeliner/read.go
index 0d96f03e..95c8e93e 100644
--- a/providers/pipeliner/read.go
+++ b/providers/pipeliner/read.go
@@ -9,6 +9,10 @@ import (
 )
 
 func (c *Connector) Read(ctx context.Context, config common.ReadParams) (*common.ReadResult, error) {
+	if err := config.ValidateParams(true); err != nil {
+		return nil, err
+	}
+
 	url, err := c.buildReadURL(config)
 	if err != nil {
 		return nil, err
diff --git a/providers/pipeliner/write.go b/providers/pipeliner/write.go
index fada8acc..4c5126f9 100644
--- a/providers/pipeliner/write.go
+++ b/providers/pipeliner/write.go
@@ -9,8 +9,8 @@ import (
 )
 
 func (c *Connector) Write(ctx context.Context, config common.WriteParams) (*common.WriteResult, error) {
-	if len(config.ObjectName) == 0 {
-		return nil, common.ErrMissingObjects
+	if err := config.ValidateParams(); err != nil {
+		return nil, err
 	}
 
 	url, err := c.getURL(config.ObjectName)
diff --git a/providers/salesforce/metadata.go b/providers/salesforce/metadata.go
index 6f94c22d..9ffd23e9 100644
--- a/providers/salesforce/metadata.go
+++ b/providers/salesforce/metadata.go
@@ -14,7 +14,6 @@ func (c *Connector) ListObjectMetadata(
 	ctx context.Context,
 	objectNames []string,
 ) (*common.ListObjectMetadataResult, error) {
-	// Ensure that objectNames is not empty
 	if len(objectNames) == 0 {
 		return nil, common.ErrMissingObjects
 	}
diff --git a/providers/salesforce/read.go b/providers/salesforce/read.go
index b442ee05..5b04db17 100644
--- a/providers/salesforce/read.go
+++ b/providers/salesforce/read.go
@@ -10,9 +10,8 @@ import (
 // Read reads data from Salesforce. By default, it will read all rows (backfill). However, if Since is set,
 // it will read only rows that have been updated since the specified time.
 func (c *Connector) Read(ctx context.Context, config common.ReadParams) (*common.ReadResult, error) {
-	// Make sure we have at least one field
-	if len(config.Fields) == 0 {
-		return nil, common.ErrMissingFields
+	if err := config.ValidateParams(true); err != nil {
+		return nil, err
 	}
 
 	url, err := c.buildReadURL(config)
diff --git a/providers/salesforce/write.go b/providers/salesforce/write.go
index c8c0ebaa..891b9d88 100644
--- a/providers/salesforce/write.go
+++ b/providers/salesforce/write.go
@@ -10,8 +10,8 @@ import (
 
 // Write will write data to Salesforce.
 func (c *Connector) Write(ctx context.Context, config common.WriteParams) (*common.WriteResult, error) {
-	if len(config.ObjectName) == 0 {
-		return nil, common.ErrMissingObjects
+	if err := config.ValidateParams(); err != nil {
+		return nil, err
 	}
 
 	url, err := c.getRestApiURL("sobjects", config.ObjectName)
diff --git a/providers/salesloft/delete.go b/providers/salesloft/delete.go
index ac8c33fe..4b8500ac 100644
--- a/providers/salesloft/delete.go
+++ b/providers/salesloft/delete.go
@@ -7,12 +7,8 @@ import (
 )
 
 func (c *Connector) Delete(ctx context.Context, config common.DeleteParams) (*common.DeleteResult, error) {
-	if len(config.ObjectName) == 0 {
-		return nil, common.ErrMissingObjects
-	}
-
-	if len(config.RecordId) == 0 {
-		return nil, common.ErrMissingRecordID
+	if err := config.ValidateParams(); err != nil {
+		return nil, err
 	}
 
 	url, err := c.getURL(config.ObjectName)
diff --git a/providers/salesloft/metadata.go b/providers/salesloft/metadata.go
index 72bf2955..9bfe19c0 100644
--- a/providers/salesloft/metadata.go
+++ b/providers/salesloft/metadata.go
@@ -10,7 +10,6 @@ import (
 func (c *Connector) ListObjectMetadata(
 	ctx context.Context, objectNames []string,
 ) (*common.ListObjectMetadataResult, error) {
-	// Ensure that objectNames is not empty
 	if len(objectNames) == 0 {
 		return nil, common.ErrMissingObjects
 	}
diff --git a/providers/salesloft/read.go b/providers/salesloft/read.go
index 7bdff466..baf1f478 100644
--- a/providers/salesloft/read.go
+++ b/providers/salesloft/read.go
@@ -10,6 +10,10 @@ import (
 )
 
 func (c *Connector) Read(ctx context.Context, config common.ReadParams) (*common.ReadResult, error) {
+	if err := config.ValidateParams(true); err != nil {
+		return nil, err
+	}
+
 	url, err := c.buildReadURL(config)
 	if err != nil {
 		return nil, err
diff --git a/providers/salesloft/write.go b/providers/salesloft/write.go
index 157ed090..e4e3fd97 100644
--- a/providers/salesloft/write.go
+++ b/providers/salesloft/write.go
@@ -10,8 +10,8 @@ import (
 )
 
 func (c *Connector) Write(ctx context.Context, config common.WriteParams) (*common.WriteResult, error) {
-	if len(config.ObjectName) == 0 {
-		return nil, common.ErrMissingObjects
+	if err := config.ValidateParams(); err != nil {
+		return nil, err
 	}
 
 	url, err := c.getURL(config.ObjectName)
diff --git a/providers/smartlead/delete.go b/providers/smartlead/delete.go
index 2d2fe031..6eb61d39 100644
--- a/providers/smartlead/delete.go
+++ b/providers/smartlead/delete.go
@@ -8,12 +8,8 @@ import (
 
 // Delete removes object. As of now only removal of Campaigns is allowed.
 func (c *Connector) Delete(ctx context.Context, config common.DeleteParams) (*common.DeleteResult, error) {
-	if len(config.ObjectName) == 0 {
-		return nil, common.ErrMissingObjects
-	}
-
-	if len(config.RecordId) == 0 {
-		return nil, common.ErrMissingRecordID
+	if err := config.ValidateParams(); err != nil {
+		return nil, err
 	}
 
 	if !supportedObjectsByDelete.Has(config.ObjectName) {
diff --git a/providers/smartlead/metadata.go b/providers/smartlead/metadata.go
index 8b9ed055..41a27d91 100644
--- a/providers/smartlead/metadata.go
+++ b/providers/smartlead/metadata.go
@@ -10,7 +10,6 @@ import (
 func (c *Connector) ListObjectMetadata(
 	ctx context.Context, objectNames []string,
 ) (*common.ListObjectMetadataResult, error) {
-	// Ensure that objectNames is not empty
 	if len(objectNames) == 0 {
 		return nil, common.ErrMissingObjects
 	}
diff --git a/providers/smartlead/read.go b/providers/smartlead/read.go
index 680c6287..a5f083a0 100644
--- a/providers/smartlead/read.go
+++ b/providers/smartlead/read.go
@@ -7,8 +7,8 @@ import (
 )
 
 func (c *Connector) Read(ctx context.Context, config common.ReadParams) (*common.ReadResult, error) {
-	if len(config.ObjectName) == 0 {
-		return nil, common.ErrMissingObjects
+	if err := config.ValidateParams(true); err != nil {
+		return nil, err
 	}
 
 	url, err := c.getURL(config.ObjectName)
diff --git a/providers/smartlead/write.go b/providers/smartlead/write.go
index 3ee5e160..affa2983 100644
--- a/providers/smartlead/write.go
+++ b/providers/smartlead/write.go
@@ -18,8 +18,8 @@ import (
 func (c *Connector) Write(
 	ctx context.Context, config common.WriteParams,
 ) (*common.WriteResult, error) {
-	if len(config.ObjectName) == 0 {
-		return nil, common.ErrMissingObjects
+	if err := config.ValidateParams(); err != nil {
+		return nil, err
 	}
 
 	if !supportedObjectsByWrite.Has(config.ObjectName) {
diff --git a/providers/zendesksupport/delete.go b/providers/zendesksupport/delete.go
index 52606f76..9a5ba26c 100644
--- a/providers/zendesksupport/delete.go
+++ b/providers/zendesksupport/delete.go
@@ -7,12 +7,8 @@ import (
 )
 
 func (c *Connector) Delete(ctx context.Context, config common.DeleteParams) (*common.DeleteResult, error) {
-	if len(config.ObjectName) == 0 {
-		return nil, common.ErrMissingObjects
-	}
-
-	if len(config.RecordId) == 0 {
-		return nil, common.ErrMissingRecordID
+	if err := config.ValidateParams(); err != nil {
+		return nil, err
 	}
 
 	url, err := c.getURL(config.ObjectName)
diff --git a/providers/zendesksupport/metadata.go b/providers/zendesksupport/metadata.go
index 8832260f..a54a158a 100644
--- a/providers/zendesksupport/metadata.go
+++ b/providers/zendesksupport/metadata.go
@@ -10,7 +10,6 @@ import (
 func (c *Connector) ListObjectMetadata(
 	ctx context.Context, objectNames []string,
 ) (*common.ListObjectMetadataResult, error) {
-	// Ensure that objectNames is not empty
 	if len(objectNames) == 0 {
 		return nil, common.ErrMissingObjects
 	}
diff --git a/providers/zendesksupport/read.go b/providers/zendesksupport/read.go
index 26860380..bf89de76 100644
--- a/providers/zendesksupport/read.go
+++ b/providers/zendesksupport/read.go
@@ -8,8 +8,8 @@ import (
 )
 
 func (c *Connector) Read(ctx context.Context, config common.ReadParams) (*common.ReadResult, error) {
-	if len(config.ObjectName) == 0 {
-		return nil, common.ErrMissingObjects
+	if err := config.ValidateParams(true); err != nil {
+		return nil, err
 	}
 
 	url, err := c.buildReadURL(config)
diff --git a/providers/zendesksupport/write.go b/providers/zendesksupport/write.go
index 0a655200..0aceec78 100644
--- a/providers/zendesksupport/write.go
+++ b/providers/zendesksupport/write.go
@@ -11,8 +11,8 @@ import (
 )
 
 func (c *Connector) Write(ctx context.Context, config common.WriteParams) (*common.WriteResult, error) {
-	if len(config.ObjectName) == 0 {
-		return nil, common.ErrMissingObjects
+	if err := config.ValidateParams(); err != nil {
+		return nil, err
 	}
 
 	url, err := c.getURL(config.ObjectName)


Test patch:
diff --git a/providers/atlassian/delete_test.go b/providers/atlassian/delete_test.go
index 1ebd09f9..a93fcb3d 100644
--- a/providers/atlassian/delete_test.go
+++ b/providers/atlassian/delete_test.go
@@ -11,6 +11,7 @@ import (
 	"github.com/amp-labs/connectors/common"
 	"github.com/amp-labs/connectors/common/interpreter"
 	"github.com/amp-labs/connectors/test/utils/mockutils"
+	"github.com/amp-labs/connectors/test/utils/mockutils/mockserver"
 	"github.com/amp-labs/connectors/test/utils/testroutines"
 	"github.com/amp-labs/connectors/test/utils/testutils"
 )
@@ -21,9 +22,14 @@ func TestDelete(t *testing.T) { // nolint:funlen,cyclop
 	responseErrorFormat := testutils.DataFromFile(t, "delete-issue-not-found.json")
 
 	tests := []testroutines.Delete{
+		{
+			Name:         "Delete object must be included",
+			Server:       mockserver.Dummy(),
+			ExpectedErrs: []error{common.ErrMissingObjects},
+		},
 		{
 			Name:  "Write issue must include ID",
-			Input: common.DeleteParams{},
+			Input: common.DeleteParams{ObjectName: "issues"},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.WriteHeader(http.StatusTeapot)
 			})),
@@ -31,7 +37,7 @@ func TestDelete(t *testing.T) { // nolint:funlen,cyclop
 		},
 		{
 			Name:  "Mime response header expected",
-			Input: common.DeleteParams{RecordId: "10010"},
+			Input: common.DeleteParams{ObjectName: "issues", RecordId: "10010"},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.WriteHeader(http.StatusTeapot)
 			})),
@@ -39,7 +45,7 @@ func TestDelete(t *testing.T) { // nolint:funlen,cyclop
 		},
 		{
 			Name:  "Not found returned on removing missing entry",
-			Input: common.DeleteParams{RecordId: "10010"},
+			Input: common.DeleteParams{ObjectName: "issues", RecordId: "10010"},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusNotFound)
@@ -52,7 +58,7 @@ func TestDelete(t *testing.T) { // nolint:funlen,cyclop
 		},
 		{
 			Name:  "Successful delete",
-			Input: common.DeleteParams{RecordId: "10010"},
+			Input: common.DeleteParams{ObjectName: "issues", RecordId: "10010"},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				mockutils.RespondNoContentForMethod(w, r, "DELETE")
@@ -87,7 +93,7 @@ func TestDeleteWithoutMetadata(t *testing.T) {
 		t.Fatal("failed to create connector")
 	}
 
-	_, err = connector.Delete(context.Background(), common.DeleteParams{RecordId: "123"})
+	_, err = connector.Delete(context.Background(), common.DeleteParams{ObjectName: "issues", RecordId: "123"})
 	if !errors.Is(err, ErrMissingCloudId) {
 		t.Fatalf("expected Delete method to complain about missing cloud id")
 	}
diff --git a/providers/atlassian/read_test.go b/providers/atlassian/read_test.go
index 216fff0a..63bcc824 100644
--- a/providers/atlassian/read_test.go
+++ b/providers/atlassian/read_test.go
@@ -27,13 +27,26 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 	responsePathNotFoundError := testutils.DataFromFile(t, "path-not-found.json")
 
 	tests := []testroutines.Read{
+		{
+			Name:         "Read object must be included",
+			Server:       mockserver.Dummy(),
+			ExpectedErrs: []error{common.ErrMissingObjects},
+		},
+		{
+			Name:         "At least one field is requested",
+			Input:        common.ReadParams{ObjectName: "issues"},
+			Server:       mockserver.Dummy(),
+			ExpectedErrs: []error{common.ErrMissingFields},
+		},
 		{
 			Name:         "Mime response header expected",
+			Input:        common.ReadParams{ObjectName: "issues", Fields: []string{"id"}},
 			Server:       mockserver.Dummy(),
 			ExpectedErrs: []error{interpreter.ErrMissingContentType},
 		},
 		{
-			Name: "Correct error message is understood from JSON response",
+			Name:  "Correct error message is understood from JSON response",
+			Input: common.ReadParams{ObjectName: "issues", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusBadRequest)
@@ -45,7 +58,8 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 			},
 		},
 		{
-			Name: "Invalid path understood as not found error",
+			Name:  "Invalid path understood as not found error",
+			Input: common.ReadParams{ObjectName: "issues", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusNotFound)
@@ -57,7 +71,8 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 			},
 		},
 		{
-			Name: "Incorrect key in payload",
+			Name:  "Incorrect key in payload",
+			Input: common.ReadParams{ObjectName: "issues", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusOK)
@@ -68,7 +83,8 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 			ExpectedErrs: []error{jsonquery.ErrKeyNotFound},
 		},
 		{
-			Name: "Incorrect data type in payload",
+			Name:  "Incorrect data type in payload",
+			Input: common.ReadParams{ObjectName: "issues", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusOK)
@@ -79,7 +95,8 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 			ExpectedErrs: []error{jsonquery.ErrNotArray},
 		},
 		{
-			Name: "Empty array produces no next page",
+			Name:  "Empty array produces no next page",
+			Input: common.ReadParams{ObjectName: "issues", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusOK)
@@ -100,7 +117,8 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 			ExpectedErrs: nil,
 		},
 		{
-			Name: "Issue must have fields property",
+			Name:  "Issue must have fields property",
+			Input: common.ReadParams{ObjectName: "issues", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusOK)
@@ -112,7 +130,8 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 			ExpectedErrs: []error{jsonquery.ErrKeyNotFound},
 		},
 		{
-			Name: "Issue must have id property",
+			Name:  "Issue must have id property",
+			Input: common.ReadParams{ObjectName: "issues", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusOK)
@@ -124,7 +143,8 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 			ExpectedErrs: []error{jsonquery.ErrKeyNotFound},
 		},
 		{
-			Name: "Missing starting index produces no next page",
+			Name:  "Missing starting index produces no next page",
+			Input: common.ReadParams{ObjectName: "issues", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusOK)
@@ -146,7 +166,8 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 			ExpectedErrs: nil,
 		},
 		{
-			Name: "Next page is implied from start index and issues size",
+			Name:  "Next page is implied from start index and issues size",
+			Input: common.ReadParams{ObjectName: "issues", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusOK)
@@ -171,7 +192,9 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 		{
 			Name: "Since rounds to minute time frame",
 			Input: common.ReadParams{
-				Since: time.Now().Add(-5 * time.Minute),
+				ObjectName: "issues",
+				Fields:     []string{"id"},
+				Since:      time.Now().Add(-5 * time.Minute),
 			},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
@@ -198,7 +221,9 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 		{
 			Name: "Next page is propagated in query params",
 			Input: common.ReadParams{
-				NextPage: "17",
+				ObjectName: "issues",
+				Fields:     []string{"id"},
+				NextPage:   "17",
 			},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
@@ -227,7 +252,8 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 		{
 			Name: "Successful list of rows",
 			Input: common.ReadParams{
-				Fields: []string{"id", "summary"},
+				ObjectName: "issues",
+				Fields:     []string{"id", "summary"},
 			},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
@@ -298,7 +324,7 @@ func TestReadWithoutMetadata(t *testing.T) {
 		t.Fatal("failed to create connector")
 	}
 
-	_, err = connector.Read(context.Background(), common.ReadParams{})
+	_, err = connector.Read(context.Background(), common.ReadParams{ObjectName: "issues", Fields: []string{"id"}})
 	if !errors.Is(err, ErrMissingCloudId) {
 		t.Fatalf("expected Read method to complain about missing cloud id")
 	}
diff --git a/providers/atlassian/write_test.go b/providers/atlassian/write_test.go
index e80accd0..2e276f7e 100644
--- a/providers/atlassian/write_test.go
+++ b/providers/atlassian/write_test.go
@@ -24,15 +24,26 @@ func TestWrite(t *testing.T) { // nolint:funlen,cyclop
 	createIssueResponse := testutils.DataFromFile(t, "create-issue.json")
 
 	tests := []testroutines.Write{
+		{
+			Name:         "Write object must be included",
+			Server:       mockserver.Dummy(),
+			ExpectedErrs: []error{common.ErrMissingObjects},
+		},
+		{
+			Name:         "Write needs data payload",
+			Input:        common.WriteParams{ObjectName: "issues"},
+			Server:       mockserver.Dummy(),
+			ExpectedErrs: []error{common.ErrMissingRecordData},
+		},
 		{
 			Name:         "Mime response header expected",
-			Input:        common.WriteParams{},
+			Input:        common.WriteParams{ObjectName: "issues", RecordData: "dummy"},
 			Server:       mockserver.Dummy(),
 			ExpectedErrs: []error{interpreter.ErrMissingContentType},
 		},
 		{
 			Name:  "Error missing project during write",
-			Input: common.WriteParams{RecordId: "10003"},
+			Input: common.WriteParams{ObjectName: "issues", RecordId: "10003", RecordData: "dummy"},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusBadRequest)
@@ -45,7 +56,7 @@ func TestWrite(t *testing.T) { // nolint:funlen,cyclop
 		},
 		{
 			Name:  "Error missing issue type during write",
-			Input: common.WriteParams{RecordId: "10003"},
+			Input: common.WriteParams{ObjectName: "issues", RecordId: "10003", RecordData: "dummy"},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusBadRequest)
@@ -58,7 +69,7 @@ func TestWrite(t *testing.T) { // nolint:funlen,cyclop
 		},
 		{
 			Name:  "Write must act as a Create",
-			Input: common.WriteParams{},
+			Input: common.WriteParams{ObjectName: "issues", RecordData: "dummy"},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				mockutils.RespondToMethod(w, r, "POST", func() {
@@ -70,7 +81,7 @@ func TestWrite(t *testing.T) { // nolint:funlen,cyclop
 		},
 		{
 			Name:  "Write must act as an Update",
-			Input: common.WriteParams{RecordId: "10003"},
+			Input: common.WriteParams{ObjectName: "issues", RecordId: "10003", RecordData: "dummy"},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				mockutils.RespondToMethod(w, r, "PUT", func() {
@@ -82,7 +93,7 @@ func TestWrite(t *testing.T) { // nolint:funlen,cyclop
 		},
 		{
 			Name:  "Valid creation of an Issue",
-			Input: common.WriteParams{ObjectName: "accounts"},
+			Input: common.WriteParams{ObjectName: "issues", RecordData: "dummy"},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				mockutils.RespondToMethod(w, r, "POST", func() {
@@ -128,7 +139,7 @@ func TestWriteWithoutMetadata(t *testing.T) {
 		t.Fatal("failed to create connector")
 	}
 
-	_, err = connector.Write(context.Background(), common.WriteParams{})
+	_, err = connector.Write(context.Background(), common.WriteParams{ObjectName: "issues", RecordData: "dummy"})
 	if !errors.Is(err, ErrMissingCloudId) {
 		t.Fatalf("expected Write method to complain about missing cloud id")
 	}
diff --git a/providers/dynamicscrm/delete_test.go b/providers/dynamicscrm/delete_test.go
index 4c659268..5fdfe325 100644
--- a/providers/dynamicscrm/delete_test.go
+++ b/providers/dynamicscrm/delete_test.go
@@ -19,7 +19,7 @@ func TestDelete(t *testing.T) { // nolint:funlen,cyclop
 
 	tests := []testroutines.Delete{
 		{
-			Name:         "Write object must be included",
+			Name:         "Delete object must be included",
 			Server:       mockserver.Dummy(),
 			ExpectedErrs: []error{common.ErrMissingObjects},
 		},
diff --git a/providers/dynamicscrm/read_test.go b/providers/dynamicscrm/read_test.go
index ca845db2..cf8c5125 100644
--- a/providers/dynamicscrm/read_test.go
+++ b/providers/dynamicscrm/read_test.go
@@ -24,19 +24,24 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop
 	tests := []testroutines.Read{
 		{
 			Name:         "Read object must be included",
-			Input:        common.ReadParams{},
 			Server:       mockserver.Dummy(),
 			ExpectedErrs: []error{common.ErrMissingObjects},
 		},
 		{
-			Name:         "Mime response header expected",
+			Name:         "At least one field is requested",
 			Input:        common.ReadParams{ObjectName: "contact"},
 			Server:       mockserver.Dummy(),
+			ExpectedErrs: []error{common.ErrMissingFields},
+		},
+		{
+			Name:         "Mime response header expected",
+			Input:        common.ReadParams{ObjectName: "contact", Fields: []string{"id"}},
+			Server:       mockserver.Dummy(),
 			ExpectedErrs: []error{interpreter.ErrMissingContentType},
 		},
 		{
 			Name:  "Correct error message is understood from JSON response",
-			Input: common.ReadParams{ObjectName: "contact"},
+			Input: common.ReadParams{ObjectName: "contact", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusBadRequest)
@@ -53,7 +58,7 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop
 		},
 		{
 			Name:  "Incorrect key in payload",
-			Input: common.ReadParams{ObjectName: "contact"},
+			Input: common.ReadParams{ObjectName: "contact", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusOK)
@@ -65,7 +70,7 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop
 		},
 		{
 			Name:  "Incorrect data type in payload",
-			Input: common.ReadParams{ObjectName: "contact"},
+			Input: common.ReadParams{ObjectName: "contact", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusOK)
@@ -77,7 +82,7 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop
 		},
 		{
 			Name:  "Next page cursor may be missing in payload",
-			Input: common.ReadParams{ObjectName: "contact"},
+			Input: common.ReadParams{ObjectName: "contact", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusOK)
@@ -91,44 +96,6 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop
 			},
 			ExpectedErrs: nil,
 		},
-		{
-			Name:  "Successful read with 2 entries",
-			Input: common.ReadParams{ObjectName: "contact"},
-			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
-				w.Header().Set("Content-Type", "application/json")
-				w.WriteHeader(http.StatusOK)
-				_, _ = w.Write(responseContactsGet)
-			})),
-			Expected: &common.ReadResult{
-				Rows: 2,
-				Data: []common.ReadResultRow{{
-					Fields: map[string]any{},
-					Raw: map[string]any{
-						"@odata.etag":   "W/\"4372108\"",
-						"fullname":      "Heriberto Nathan",
-						"emailaddress1": "heriberto@northwindtraders.com",
-						"fax":           "614-555-0122",
-						"familystatuscode@OData.Community.Display.V1.FormattedValue": "Single",
-						"familystatuscode": float64(1),
-						"contactid":        "cdcfa450-cb0c-ea11-a813-000d3a1b1223",
-					},
-				}, {
-					Fields: map[string]any{},
-					Raw: map[string]any{
-						"@odata.etag":   "W/\"4372115\"",
-						"fullname":      "Dwayne Elijah",
-						"emailaddress1": "dwayne@alpineskihouse.com",
-						"fax":           "281-555-0158",
-						"familystatuscode@OData.Community.Display.V1.FormattedValue": "Single",
-						"familystatuscode": float64(1),
-						"contactid":        "9fd4a450-cb0c-ea11-a813-000d3a1b1223",
-					},
-				}},
-				NextPage: "https://org5bd08fdd.api.crm.dynamics.com/api/data/v9.2/contacts?$select=fullname,emailaddress1,fax,familystatuscode&$skiptoken=%3Ccookie%20pagenumber=%222%22%20pagingcookie=%22%253ccookie%2520page%253d%25221%2522%253e%253ccontactid%2520last%253d%2522%257b9FD4A450-CB0C-EA11-A813-000D3A1B1223%257d%2522%2520first%253d%2522%257bCDCFA450-CB0C-EA11-A813-000D3A1B1223%257d%2522%2520%252f%253e%253c%252fcookie%253e%22%20istracking=%22False%22%20/%3E", // nolint:lll
-				Done:     false,
-			},
-			ExpectedErrs: nil,
-		},
 		{
 			Name:  "Successful read with chosen fields",
 			Input: common.ReadParams{ObjectName: "contact", Fields: []string{"fullname", "fax"}},
diff --git a/providers/dynamicscrm/write_test.go b/providers/dynamicscrm/write_test.go
index e6ea4556..47edabc5 100644
--- a/providers/dynamicscrm/write_test.go
+++ b/providers/dynamicscrm/write_test.go
@@ -20,19 +20,24 @@ func TestWrite(t *testing.T) { // nolint:funlen,cyclop
 	tests := []testroutines.Write{
 		{
 			Name:         "Write object must be included",
-			Input:        common.WriteParams{},
 			Server:       mockserver.Dummy(),
 			ExpectedErrs: []error{common.ErrMissingObjects},
 		},
 		{
-			Name:         "Mime response header expected",
+			Name:         "Write needs data payload",
 			Input:        common.WriteParams{ObjectName: "fax"},
 			Server:       mockserver.Dummy(),
+			ExpectedErrs: []error{common.ErrMissingRecordData},
+		},
+		{
+			Name:         "Mime response header expected",
+			Input:        common.WriteParams{ObjectName: "fax", RecordData: "dummy"},
+			Server:       mockserver.Dummy(),
 			ExpectedErrs: []error{interpreter.ErrMissingContentType},
 		},
 		{
 			Name:  "Correct error message is understood from JSON response",
-			Input: common.WriteParams{ObjectName: "fax"},
+			Input: common.WriteParams{ObjectName: "fax", RecordData: "dummy"},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusBadRequest)
@@ -50,7 +55,7 @@ func TestWrite(t *testing.T) { // nolint:funlen,cyclop
 		},
 		{
 			Name:  "Write must act as a Create",
-			Input: common.WriteParams{ObjectName: "fax"},
+			Input: common.WriteParams{ObjectName: "fax", RecordData: "dummy"},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				mockutils.RespondNoContentForMethod(w, r, "POST")
@@ -59,8 +64,12 @@ func TestWrite(t *testing.T) { // nolint:funlen,cyclop
 			ExpectedErrs: nil,
 		},
 		{
-			Name:  "Write must act as an Update",
-			Input: common.WriteParams{ObjectName: "fax", RecordId: "dd2f7870-3fe8-ee11-a204-0022481f9e3c"},
+			Name: "Write must act as an Update",
+			Input: common.WriteParams{
+				ObjectName: "fax",
+				RecordId:   "dd2f7870-3fe8-ee11-a204-0022481f9e3c",
+				RecordData: "dummy",
+			},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				mockutils.RespondNoContentForMethod(w, r, "PATCH")
diff --git a/providers/gong/read_test.go b/providers/gong/read_test.go
index 174c4ce3..3c17865a 100644
--- a/providers/gong/read_test.go
+++ b/providers/gong/read_test.go
@@ -29,14 +29,20 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop
 			ExpectedErrs: []error{common.ErrMissingObjects},
 		},
 		{
-			Name:         "Mime response header expected",
+			Name:         "At least one field is requested",
 			Input:        common.ReadParams{ObjectName: "calls"},
 			Server:       mockserver.Dummy(),
+			ExpectedErrs: []error{common.ErrMissingFields},
+		},
+		{
+			Name:         "Mime response header expected",
+			Input:        common.ReadParams{ObjectName: "calls", Fields: []string{"id"}},
+			Server:       mockserver.Dummy(),
 			ExpectedErrs: []error{interpreter.ErrMissingContentType},
 		},
 		{
 			Name:  "Incorrect key in payload",
-			Input: common.ReadParams{ObjectName: "calls"},
+			Input: common.ReadParams{ObjectName: "calls", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusOK)
@@ -48,7 +54,7 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop
 		},
 		{
 			Name:  "Bad request handling test",
-			Input: common.ReadParams{ObjectName: "calls"},
+			Input: common.ReadParams{ObjectName: "calls", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusBadRequest)
@@ -65,7 +71,7 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop
 		},
 		{
 			Name:  "Records section is missing in the payload",
-			Input: common.ReadParams{ObjectName: "calls"},
+			Input: common.ReadParams{ObjectName: "calls", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusOK)
@@ -78,7 +84,7 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop
 
 		{
 			Name:  "currentPageSize may be missing in payload",
-			Input: common.ReadParams{ObjectName: "calls"},
+			Input: common.ReadParams{ObjectName: "calls", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusOK)
@@ -101,8 +107,8 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop
 		},
 
 		{
-			Name:  "Successful read with 2 entries wihtout cursor/next page",
-			Input: common.ReadParams{ObjectName: "calls"},
+			Name:  "Successful read with 2 entries without cursor/next page",
+			Input: common.ReadParams{ObjectName: "calls", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusOK)
@@ -111,7 +117,9 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop
 			Expected: &common.ReadResult{
 				Rows: 2,
 				Data: []common.ReadResultRow{{
-					Fields: map[string]any{},
+					Fields: map[string]any{
+						"id": "52947912500572621",
+					},
 					Raw: map[string]any{
 						"id":             "52947912500572621",
 						"clientUniqueId": "ce93bb26-de69-41e3-8a7f-43ea3714b9e8",
@@ -120,7 +128,9 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop
 						"workspaceId":    "1007648505208900737",
 					},
 				}, {
-					Fields: map[string]any{},
+					Fields: map[string]any{
+						"id": "137982752092261989",
+					},
 					Raw: map[string]any{
 						"id":             "137982752092261989",
 						"clientUniqueId": "f77501df-0c70-4c38-b565-a3a09fee14fb",
@@ -136,7 +146,7 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop
 
 		{
 			Name:  "Successful read with 2 entries and cursor for next page",
-			Input: common.ReadParams{ObjectName: "calls"},
+			Input: common.ReadParams{ObjectName: "calls", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusOK)
@@ -145,7 +155,9 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop
 			Expected: &common.ReadResult{
 				Rows: 2,
 				Data: []common.ReadResultRow{{
-					Fields: map[string]any{},
+					Fields: map[string]any{
+						"id": "52947912500572621",
+					},
 					Raw: map[string]any{
 						"id":             "52947912500572621",
 						"clientUniqueId": "ce93bb26-de69-41e3-8a7f-43ea3714b9e8",
@@ -154,7 +166,9 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop
 						"workspaceId":    "1007648505208900737",
 					},
 				}, {
-					Fields: map[string]any{},
+					Fields: map[string]any{
+						"id": "137982752092261989",
+					},
 					Raw: map[string]any{
 						"id":             "137982752092261989",
 						"clientUniqueId": "f77501df-0c70-4c38-b565-a3a09fee14fb",
@@ -170,7 +184,7 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop
 		},
 		{
 			Name:  "Incorrect data type in payload",
-			Input: common.ReadParams{ObjectName: "calls"},
+			Input: common.ReadParams{ObjectName: "calls", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusOK)
diff --git a/providers/instantly/read_test.go b/providers/instantly/read_test.go
index 2850f3ac..eb2fa1d0 100644
--- a/providers/instantly/read_test.go
+++ b/providers/instantly/read_test.go
@@ -33,14 +33,20 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 			ExpectedErrs: []error{common.ErrMissingObjects},
 		},
 		{
-			Name:         "Mime response header expected",
+			Name:         "At least one field is requested",
 			Input:        common.ReadParams{ObjectName: "campaigns"},
 			Server:       mockserver.Dummy(),
+			ExpectedErrs: []error{common.ErrMissingFields},
+		},
+		{
+			Name:         "Mime response header expected",
+			Input:        common.ReadParams{ObjectName: "campaigns", Fields: []string{"id"}},
+			Server:       mockserver.Dummy(),
 			ExpectedErrs: []error{interpreter.ErrMissingContentType},
 		},
 		{
 			Name:     "Unknown object name is not supported",
-			Input:    common.ReadParams{ObjectName: "orders"},
+			Input:    common.ReadParams{ObjectName: "orders", Fields: []string{"id"}},
 			Server:   mockserver.Dummy(),
 			Expected: nil,
 			ExpectedErrs: []error{
@@ -49,7 +55,7 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 		},
 		{
 			Name:  "Correct error message is understood from JSON response",
-			Input: common.ReadParams{ObjectName: "campaigns"},
+			Input: common.ReadParams{ObjectName: "campaigns", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusNotFound)
@@ -62,7 +68,7 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 		},
 		{
 			Name:  "Incorrect key in payload",
-			Input: common.ReadParams{ObjectName: "emails"},
+			Input: common.ReadParams{ObjectName: "emails", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusOK)
@@ -74,7 +80,7 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 		},
 		{
 			Name:  "Incorrect data type in payload",
-			Input: common.ReadParams{ObjectName: "emails"},
+			Input: common.ReadParams{ObjectName: "emails", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusOK)
@@ -89,6 +95,7 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 			Input: common.ReadParams{
 				ObjectName: "campaigns",
 				NextPage:   "test-placeholder?skip=700",
+				Fields:     []string{"id"},
 			},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
@@ -115,6 +122,7 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 			Name: "Current empty page signifies no next page",
 			Input: common.ReadParams{
 				ObjectName: "campaigns",
+				Fields:     []string{"id"},
 			},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
diff --git a/providers/instantly/write_test.go b/providers/instantly/write_test.go
index dbe4a27d..15150994 100644
--- a/providers/instantly/write_test.go
+++ b/providers/instantly/write_test.go
@@ -34,15 +34,21 @@ func TestWrite(t *testing.T) { // nolint:funlen,cyclop
 			Server:       mockserver.Dummy(),
 			ExpectedErrs: []error{common.ErrMissingObjects},
 		},
+		{
+			Name:         "Write needs data payload",
+			Input:        common.WriteParams{ObjectName: "notes"},
+			Server:       mockserver.Dummy(),
+			ExpectedErrs: []error{common.ErrMissingRecordData},
+		},
 		{
 			Name:         "Mime response header expected",
-			Input:        common.WriteParams{ObjectName: "unibox-replies"},
+			Input:        common.WriteParams{ObjectName: "unibox-replies", RecordData: "dummy"},
 			Server:       mockserver.Dummy(),
 			ExpectedErrs: []error{interpreter.ErrMissingContentType},
 		},
 		{
 			Name:     "Unknown object name is not supported",
-			Input:    common.WriteParams{ObjectName: "orders"},
+			Input:    common.WriteParams{ObjectName: "orders", RecordData: "dummy"},
 			Server:   mockserver.Dummy(),
 			Expected: nil,
 			ExpectedErrs: []error{
@@ -51,7 +57,7 @@ func TestWrite(t *testing.T) { // nolint:funlen,cyclop
 		},
 		{
 			Name:  "Create Blocklist Entry",
-			Input: common.WriteParams{ObjectName: "blocklist-entries"},
+			Input: common.WriteParams{ObjectName: "blocklist-entries", RecordData: "dummy"},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				mockutils.RespondToMethod(w, r, "POST", func() {
@@ -69,7 +75,7 @@ func TestWrite(t *testing.T) { // nolint:funlen,cyclop
 		},
 		{
 			Name:  "Create Unibox Reply",
-			Input: common.WriteParams{ObjectName: "unibox-replies"},
+			Input: common.WriteParams{ObjectName: "unibox-replies", RecordData: "dummy"},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				mockutils.RespondToMethod(w, r, "POST", func() {
@@ -88,7 +94,7 @@ func TestWrite(t *testing.T) { // nolint:funlen,cyclop
 
 		{
 			Name:  "Invalid Lead creation",
-			Input: common.WriteParams{ObjectName: "leads"},
+			Input: common.WriteParams{ObjectName: "leads", RecordData: "dummy"},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusNotFound)
@@ -101,7 +107,7 @@ func TestWrite(t *testing.T) { // nolint:funlen,cyclop
 		},
 		{
 			Name:  "Create Lead",
-			Input: common.WriteParams{ObjectName: "leads"},
+			Input: common.WriteParams{ObjectName: "leads", RecordData: "dummy"},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				mockutils.RespondToMethod(w, r, "POST", func() {
@@ -119,7 +125,7 @@ func TestWrite(t *testing.T) { // nolint:funlen,cyclop
 		},
 		{
 			Name:  "Invalid Tag creation",
-			Input: common.WriteParams{ObjectName: "tags"},
+			Input: common.WriteParams{ObjectName: "tags", RecordData: "dummy"},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusNotFound)
@@ -132,7 +138,7 @@ func TestWrite(t *testing.T) { // nolint:funlen,cyclop
 		},
 		{
 			Name:  "Create Tag acts as POST",
-			Input: common.WriteParams{ObjectName: "tags"},
+			Input: common.WriteParams{ObjectName: "tags", RecordData: "dummy"},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				mockutils.RespondToMethod(w, r, "POST", func() {
@@ -150,7 +156,7 @@ func TestWrite(t *testing.T) { // nolint:funlen,cyclop
 		},
 		{
 			Name:  "Update tag acts as PATCH",
-			Input: common.WriteParams{ObjectName: "tags", RecordId: "885633"},
+			Input: common.WriteParams{ObjectName: "tags", RecordId: "885633", RecordData: "dummy"},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				mockutils.RespondToMethod(w, r, "PATCH", func() {
diff --git a/providers/intercom/read_test.go b/providers/intercom/read_test.go
index 9a9d7eb6..e421ef06 100644
--- a/providers/intercom/read_test.go
+++ b/providers/intercom/read_test.go
@@ -35,13 +35,26 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 	responseNotesSecondPage := testutils.DataFromFile(t, "read-notes-2-last-page.json")
 
 	tests := []testroutines.Read{
+		{
+			Name:         "Read object must be included",
+			Server:       mockserver.Dummy(),
+			ExpectedErrs: []error{common.ErrMissingObjects},
+		},
+		{
+			Name:         "At least one field is requested",
+			Input:        common.ReadParams{ObjectName: "contacts"},
+			Server:       mockserver.Dummy(),
+			ExpectedErrs: []error{common.ErrMissingFields},
+		},
 		{
 			Name:         "Mime response header expected",
+			Input:        common.ReadParams{ObjectName: "contacts", Fields: []string{"id"}},
 			Server:       mockserver.Dummy(),
 			ExpectedErrs: []error{interpreter.ErrMissingContentType},
 		},
 		{
-			Name: "Correct error message is understood from JSON response",
+			Name:  "Correct error message is understood from JSON response",
+			Input: common.ReadParams{ObjectName: "contacts", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusNotFound)
@@ -52,7 +65,8 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 			},
 		},
 		{
-			Name: "Incorrect key in payload",
+			Name:  "Incorrect key in payload",
+			Input: common.ReadParams{ObjectName: "contacts", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusOK)
@@ -63,7 +77,8 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 			ExpectedErrs: []error{jsonquery.ErrKeyNotFound},
 		},
 		{
-			Name: "Incorrect data type in payload",
+			Name:  "Incorrect data type in payload",
+			Input: common.ReadParams{ObjectName: "contacts", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusOK)
@@ -74,7 +89,8 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 			ExpectedErrs: []error{jsonquery.ErrNotArray},
 		},
 		{
-			Name: "Next page cursor may be missing in payload",
+			Name:  "Next page cursor may be missing in payload",
+			Input: common.ReadParams{ObjectName: "contacts", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusOK)
@@ -91,7 +107,8 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 			ExpectedErrs: nil,
 		},
 		{
-			Name: "API version header is passed as server request",
+			Name:  "API version header is passed as server request",
+			Input: common.ReadParams{ObjectName: "notes", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				mockutils.RespondToHeader(w, r, testApiVersionHeader, func() {
@@ -107,7 +124,8 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 			ExpectedErrs: nil,
 		},
 		{
-			Name: "Next page URL is resolved, when provided with a string",
+			Name:  "Next page URL is resolved, when provided with a string",
+			Input: common.ReadParams{ObjectName: "notes", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusOK)
@@ -122,7 +140,8 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 			ExpectedErrs: nil,
 		},
 		{
-			Name: "Next page URL is inferred, when provided with an object",
+			Name:  "Next page URL is inferred, when provided with an object",
+			Input: common.ReadParams{ObjectName: "contacts", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusOK)
@@ -133,13 +152,14 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 				return actual.NextPage.String() == expectedNextPage // nolint:nlreturn
 			},
 			Expected: &common.ReadResult{
-				NextPage: "{{testServerURL}}?per_page=60&starting_after=" +
+				NextPage: "{{testServerURL}}/contacts?per_page=60&starting_after=" +
 					"WzE3MTU2OTU2NzkwMDAsIjY2NDM3MDNmZmFlNzgzNGQxNzkyZmQzMCIsMl0=",
 			},
 			ExpectedErrs: nil,
 		},
 		{
-			Name: "Next page URL is empty, when provided with null object",
+			Name:  "Next page URL is empty, when provided with null object",
+			Input: common.ReadParams{ObjectName: "notes", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusOK)
@@ -153,7 +173,8 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 			ExpectedErrs: nil,
 		},
 		{
-			Name: "Next page URL is empty, when provided with missing object",
+			Name:  "Next page URL is empty, when provided with missing object",
+			Input: common.ReadParams{ObjectName: "contacts", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusOK)
@@ -169,7 +190,8 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 		{
 			Name: "Successful read with chosen fields",
 			Input: common.ReadParams{
-				Fields: []string{"email", "name"},
+				ObjectName: "contacts",
+				Fields:     []string{"email", "name"},
 			},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
@@ -201,7 +223,7 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 						"updated_at": float64(1715706939),
 					},
 				}},
-				NextPage: "{{testServerURL}}?per_page=60&starting_after=" +
+				NextPage: "{{testServerURL}}/contacts?per_page=60&starting_after=" +
 					"Wy0xLCI2NjQzOWI5NDdiYjA5NWE2ODFmN2ZkOWUiLDNd",
 				Done: false,
 			},
@@ -210,7 +232,8 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 		{
 			Name: "Successful read of named list",
 			Input: common.ReadParams{
-				Fields: []string{"state"},
+				ObjectName: "conversations",
+				Fields:     []string{"state"},
 			},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
diff --git a/providers/intercom/write_test.go b/providers/intercom/write_test.go
index 6531a64b..05ec61f9 100644
--- a/providers/intercom/write_test.go
+++ b/providers/intercom/write_test.go
@@ -30,14 +30,20 @@ func TestWrite(t *testing.T) { // nolint:funlen,cyclop
 			ExpectedErrs: []error{common.ErrMissingObjects},
 		},
 		{
-			Name:         "Mime response header expected",
+			Name:         "Write needs data payload",
 			Input:        common.WriteParams{ObjectName: "signals"},
 			Server:       mockserver.Dummy(),
+			ExpectedErrs: []error{common.ErrMissingRecordData},
+		},
+		{
+			Name:         "Mime response header expected",
+			Input:        common.WriteParams{ObjectName: "signals", RecordData: "dummy"},
+			Server:       mockserver.Dummy(),
 			ExpectedErrs: []error{interpreter.ErrMissingContentType},
 		},
 		{
 			Name:  "Correct error message is understood from JSON response",
-			Input: common.WriteParams{ObjectName: "signals", RecordId: "22165"},
+			Input: common.WriteParams{ObjectName: "signals", RecordId: "22165", RecordData: "dummy"},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusUnprocessableEntity)
@@ -50,7 +56,7 @@ func TestWrite(t *testing.T) { // nolint:funlen,cyclop
 		},
 		{
 			Name:  "Write must act as a Create",
-			Input: common.WriteParams{ObjectName: "signals"},
+			Input: common.WriteParams{ObjectName: "signals", RecordData: "dummy"},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				mockutils.RespondToMethod(w, r, "POST", func() {
@@ -62,7 +68,7 @@ func TestWrite(t *testing.T) { // nolint:funlen,cyclop
 		},
 		{
 			Name:  "Write must act as an Update",
-			Input: common.WriteParams{ObjectName: "signals", RecordId: "22165"},
+			Input: common.WriteParams{ObjectName: "signals", RecordId: "22165", RecordData: "dummy"},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				mockutils.RespondToMethod(w, r, "PUT", func() {
@@ -74,7 +80,7 @@ func TestWrite(t *testing.T) { // nolint:funlen,cyclop
 		},
 		{
 			Name:  "API version header is passed as server request on POST",
-			Input: common.WriteParams{ObjectName: "articles"},
+			Input: common.WriteParams{ObjectName: "articles", RecordData: "dummy"},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				mockutils.RespondToHeader(w, r, testApiVersionHeader, func() {
@@ -90,7 +96,7 @@ func TestWrite(t *testing.T) { // nolint:funlen,cyclop
 		},
 		{
 			Name:  "Valid creation of an article",
-			Input: common.WriteParams{ObjectName: "articles"},
+			Input: common.WriteParams{ObjectName: "articles", RecordData: "dummy"},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				mockutils.RespondToMethod(w, r, "POST", func() {
diff --git a/providers/pipeliner/delete_test.go b/providers/pipeliner/delete_test.go
index b80ce5a1..249615f5 100644
--- a/providers/pipeliner/delete_test.go
+++ b/providers/pipeliner/delete_test.go
@@ -21,7 +21,7 @@ func TestDelete(t *testing.T) { // nolint:funlen,cyclop
 
 	tests := []testroutines.Delete{
 		{
-			Name:         "Write object must be included",
+			Name:         "Delete object must be included",
 			Server:       mockserver.Dummy(),
 			ExpectedErrs: []error{common.ErrMissingObjects},
 		},
diff --git a/providers/pipeliner/read_test.go b/providers/pipeliner/read_test.go
index 1ee20b29..f964f27f 100644
--- a/providers/pipeliner/read_test.go
+++ b/providers/pipeliner/read_test.go
@@ -25,14 +25,27 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 	responseProfilesLastPage := testutils.DataFromFile(t, "read-profiles-3-last-page.json")
 
 	tests := []testroutines.Read{
+		{
+			Name:         "Read object must be included",
+			Input:        common.ReadParams{},
+			Server:       mockserver.Dummy(),
+			ExpectedErrs: []error{common.ErrMissingObjects},
+		},
+		{
+			Name:         "At least one field is requested",
+			Input:        common.ReadParams{ObjectName: "Profiles"},
+			Server:       mockserver.Dummy(),
+			ExpectedErrs: []error{common.ErrMissingFields},
+		},
 		{
 			Name:         "Mime response header expected",
+			Input:        common.ReadParams{ObjectName: "Profiles", Fields: []string{"id"}},
 			Server:       mockserver.Dummy(),
 			ExpectedErrs: []error{interpreter.ErrMissingContentType},
 		},
 		{
 			Name:  "Correct error message is understood from JSON response",
-			Input: common.ReadParams{ObjectName: "articles"},
+			Input: common.ReadParams{ObjectName: "Profiles", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusNotFound)
@@ -44,7 +57,8 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 			},
 		},
 		{
-			Name: "Incorrect key in payload",
+			Name:  "Incorrect key in payload",
+			Input: common.ReadParams{ObjectName: "Profiles", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusOK)
@@ -55,7 +69,8 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 			ExpectedErrs: []error{jsonquery.ErrKeyNotFound},
 		},
 		{
-			Name: "Incorrect data type in payload",
+			Name:  "Incorrect data type in payload",
+			Input: common.ReadParams{ObjectName: "Profiles", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusOK)
@@ -66,7 +81,8 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 			ExpectedErrs: []error{jsonquery.ErrNotArray},
 		},
 		{
-			Name: "Next page cursor may be missing in payload",
+			Name:  "Next page cursor may be missing in payload",
+			Input: common.ReadParams{ObjectName: "Profiles", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusOK)
@@ -84,7 +100,8 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 			ExpectedErrs: nil,
 		},
 		{
-			Name: "Next page URL is inferred, when provided with an object",
+			Name:  "Next page URL is inferred, when provided with an object",
+			Input: common.ReadParams{ObjectName: "Profiles", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusOK)
@@ -99,7 +116,8 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 			ExpectedErrs: nil,
 		},
 		{
-			Name: "Next page URL is empty, when provided with null object",
+			Name:  "Next page URL is empty, when provided with null object",
+			Input: common.ReadParams{ObjectName: "Profiles", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusOK)
@@ -115,7 +133,8 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 		{
 			Name: "Successful read with chosen fields",
 			Input: common.ReadParams{
-				Fields: []string{"name", "owner_id"},
+				ObjectName: "Profiles",
+				Fields:     []string{"name", "owner_id"},
 			},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
diff --git a/providers/pipeliner/write_test.go b/providers/pipeliner/write_test.go
index 5efdb20f..f133d3a0 100644
--- a/providers/pipeliner/write_test.go
+++ b/providers/pipeliner/write_test.go
@@ -30,14 +30,24 @@ func TestWrite(t *testing.T) { // nolint:funlen,cyclop
 			ExpectedErrs: []error{common.ErrMissingObjects},
 		},
 		{
-			Name:         "Mime response header expected",
+			Name:         "Write needs data payload",
 			Input:        common.WriteParams{ObjectName: "notes"},
 			Server:       mockserver.Dummy(),
+			ExpectedErrs: []error{common.ErrMissingRecordData},
+		},
+		{
+			Name:         "Mime response header expected",
+			Input:        common.WriteParams{ObjectName: "notes", RecordData: "dummy"},
+			Server:       mockserver.Dummy(),
 			ExpectedErrs: []error{interpreter.ErrMissingContentType},
 		},
 		{
-			Name:  "Error on failed entity validation",
-			Input: common.WriteParams{ObjectName: "notes", RecordId: "019097b8-a5f4-ca93-62c5-5a25c58afa63"},
+			Name: "Error on failed entity validation",
+			Input: common.WriteParams{
+				ObjectName: "notes",
+				RecordId:   "019097b8-a5f4-ca93-62c5-5a25c58afa63",
+				RecordData: "dummy",
+			},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusUnprocessableEntity)
@@ -51,8 +61,12 @@ func TestWrite(t *testing.T) { // nolint:funlen,cyclop
 			},
 		},
 		{
-			Name:  "Error on invalid json body",
-			Input: common.WriteParams{ObjectName: "notes", RecordId: "019097b8-a5f4-ca93-62c5-5a25c58afa63"},
+			Name: "Error on invalid json body",
+			Input: common.WriteParams{
+				ObjectName: "notes",
+				RecordId:   "019097b8-a5f4-ca93-62c5-5a25c58afa63",
+				RecordData: "dummy",
+			},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusBadRequest)
@@ -65,7 +79,7 @@ func TestWrite(t *testing.T) { // nolint:funlen,cyclop
 		},
 		{
 			Name:  "Write must act as a Create",
-			Input: common.WriteParams{ObjectName: "notes"},
+			Input: common.WriteParams{ObjectName: "notes", RecordData: "dummy"},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				mockutils.RespondToMethod(w, r, "POST", func() {
@@ -76,8 +90,12 @@ func TestWrite(t *testing.T) { // nolint:funlen,cyclop
 			ExpectedErrs: nil,
 		},
 		{
-			Name:  "Write must act as an Update",
-			Input: common.WriteParams{ObjectName: "notes", RecordId: "019097b8-a5f4-ca93-62c5-5a25c58afa63"},
+			Name: "Write must act as an Update",
+			Input: common.WriteParams{
+				ObjectName: "notes",
+				RecordId:   "019097b8-a5f4-ca93-62c5-5a25c58afa63",
+				RecordData: "dummy",
+			},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				mockutils.RespondToMethod(w, r, "PATCH", func() {
@@ -89,7 +107,7 @@ func TestWrite(t *testing.T) { // nolint:funlen,cyclop
 		},
 		{
 			Name:  "Valid creation of a note",
-			Input: common.WriteParams{ObjectName: "notes"},
+			Input: common.WriteParams{ObjectName: "notes", RecordData: "dummy"},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				mockutils.RespondToMethod(w, r, "POST", func() {
@@ -113,8 +131,12 @@ func TestWrite(t *testing.T) { // nolint:funlen,cyclop
 			ExpectedErrs: nil,
 		},
 		{
-			Name:  "Valid update of a note",
-			Input: common.WriteParams{ObjectName: "notes", RecordId: "019097b8-a5f4-ca93-62c5-5a25c58afa63"},
+			Name: "Valid update of a note",
+			Input: common.WriteParams{
+				ObjectName: "notes",
+				RecordId:   "019097b8-a5f4-ca93-62c5-5a25c58afa63",
+				RecordData: "dummy",
+			},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				mockutils.RespondToMethod(w, r, "PATCH", func() {
diff --git a/providers/salesforce/read_test.go b/providers/salesforce/read_test.go
index 83787686..24f85d92 100644
--- a/providers/salesforce/read_test.go
+++ b/providers/salesforce/read_test.go
@@ -25,19 +25,25 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 
 	tests := []testroutines.Read{
 		{
-			Name:         "At least one field must be provided",
+			Name:         "Read object must be included",
+			Server:       mockserver.Dummy(),
+			ExpectedErrs: []error{common.ErrMissingObjects},
+		},
+		{
+			Name:         "At least one field is requested",
+			Input:        common.ReadParams{ObjectName: "leads"},
 			Server:       mockserver.Dummy(),
 			ExpectedErrs: []error{common.ErrMissingFields},
 		},
 		{
 			Name:         "Mime response header expected",
-			Input:        common.ReadParams{Fields: []string{"Name"}},
+			Input:        common.ReadParams{ObjectName: "leads", Fields: []string{"Name"}},
 			Server:       mockserver.Dummy(),
 			ExpectedErrs: []error{interpreter.ErrMissingContentType},
 		},
 		{
 			Name:  "Correct error message is understood from JSON response",
-			Input: common.ReadParams{Fields: []string{"Name"}},
+			Input: common.ReadParams{ObjectName: "leads", Fields: []string{"Name"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusBadRequest)
@@ -49,7 +55,7 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 		},
 		{
 			Name:  "Incorrect key in payload",
-			Input: common.ReadParams{Fields: []string{"Name"}},
+			Input: common.ReadParams{ObjectName: "leads", Fields: []string{"Name"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusOK)
@@ -61,7 +67,7 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 		},
 		{
 			Name:  "Incorrect data type in payload",
-			Input: common.ReadParams{Fields: []string{"Name"}},
+			Input: common.ReadParams{ObjectName: "leads", Fields: []string{"Name"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusOK)
@@ -73,7 +79,7 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 		},
 		{
 			Name:  "Next page cursor may be missing in payload",
-			Input: common.ReadParams{Fields: []string{"Name"}},
+			Input: common.ReadParams{ObjectName: "leads", Fields: []string{"Name"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusOK)
@@ -90,7 +96,7 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 		},
 		{
 			Name:  "Next page URL is resolved, when provided with a string",
-			Input: common.ReadParams{Fields: []string{"City"}},
+			Input: common.ReadParams{ObjectName: "leads", Fields: []string{"City"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusOK)
@@ -107,7 +113,8 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 		{
 			Name: "Successful read with chosen fields",
 			Input: common.ReadParams{
-				Fields: []string{"Department", "AssistantName"},
+				ObjectName: "contacts",
+				Fields:     []string{"Department", "AssistantName"},
 			},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
diff --git a/providers/salesforce/write_test.go b/providers/salesforce/write_test.go
index 7fc4cad4..46ed7b4e 100644
--- a/providers/salesforce/write_test.go
+++ b/providers/salesforce/write_test.go
@@ -31,14 +31,20 @@ func TestWrite(t *testing.T) { // nolint:funlen,cyclop
 			ExpectedErrs: []error{common.ErrMissingObjects},
 		},
 		{
-			Name:         "Mime response header expected",
+			Name:         "Write needs data payload",
 			Input:        common.WriteParams{ObjectName: "account"},
 			Server:       mockserver.Dummy(),
+			ExpectedErrs: []error{common.ErrMissingRecordData},
+		},
+		{
+			Name:         "Mime response header expected",
+			Input:        common.WriteParams{ObjectName: "account", RecordData: "dummy"},
+			Server:       mockserver.Dummy(),
 			ExpectedErrs: []error{interpreter.ErrMissingContentType},
 		},
 		{
 			Name:  "Error response understood for creating with unknown field",
-			Input: common.WriteParams{ObjectName: "account", RecordId: "003ak000004dQCUAA2"},
+			Input: common.WriteParams{ObjectName: "account", RecordId: "003ak000004dQCUAA2", RecordData: "dummy"},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusBadRequest)
@@ -51,7 +57,7 @@ func TestWrite(t *testing.T) { // nolint:funlen,cyclop
 		},
 		{
 			Name:  "Error response understood for updating reserved field",
-			Input: common.WriteParams{ObjectName: "account", RecordId: "003ak000004dQCUAA2"},
+			Input: common.WriteParams{ObjectName: "account", RecordId: "003ak000004dQCUAA2", RecordData: "dummy"},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusBadRequest)
@@ -64,7 +70,7 @@ func TestWrite(t *testing.T) { // nolint:funlen,cyclop
 		},
 		{
 			Name:  "Write must act as an Update",
-			Input: common.WriteParams{ObjectName: "account", RecordId: "003ak000004dQCUAA2"},
+			Input: common.WriteParams{ObjectName: "account", RecordId: "003ak000004dQCUAA2", RecordData: "dummy"},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				mockutils.RespondToMethod(w, r, "POST", func() {
@@ -86,7 +92,7 @@ func TestWrite(t *testing.T) { // nolint:funlen,cyclop
 		},
 		{
 			Name:  "Valid creation of account",
-			Input: common.WriteParams{ObjectName: "accounts"},
+			Input: common.WriteParams{ObjectName: "accounts", RecordData: "dummy"},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				mockutils.RespondToMethod(w, r, "POST", func() {
@@ -104,7 +110,7 @@ func TestWrite(t *testing.T) { // nolint:funlen,cyclop
 		},
 		{
 			Name:  "OK Response, but with errors field",
-			Input: common.WriteParams{ObjectName: "accounts"},
+			Input: common.WriteParams{ObjectName: "accounts", RecordData: "dummy"},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				mockutils.RespondToMethod(w, r, "POST", func() {
diff --git a/providers/salesloft/read_test.go b/providers/salesloft/read_test.go
index 223f56c7..00779a25 100644
--- a/providers/salesloft/read_test.go
+++ b/providers/salesloft/read_test.go
@@ -31,13 +31,26 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 	mockutils.NoErrors(t, err)
 
 	tests := []testroutines.Read{
+		{
+			Name:         "Read object must be included",
+			Server:       mockserver.Dummy(),
+			ExpectedErrs: []error{common.ErrMissingObjects},
+		},
+		{
+			Name:         "At least one field is requested",
+			Input:        common.ReadParams{ObjectName: "users"},
+			Server:       mockserver.Dummy(),
+			ExpectedErrs: []error{common.ErrMissingFields},
+		},
 		{
 			Name:         "Mime response header expected",
+			Input:        common.ReadParams{ObjectName: "users", Fields: []string{"id"}},
 			Server:       mockserver.Dummy(),
 			ExpectedErrs: []error{interpreter.ErrMissingContentType},
 		},
 		{
-			Name: "Correct error message is understood from JSON response",
+			Name:  "Correct error message is understood from JSON response",
+			Input: common.ReadParams{ObjectName: "users", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusNotFound)
@@ -50,7 +63,8 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 			},
 		},
 		{
-			Name: "Incorrect key in payload",
+			Name:  "Incorrect key in payload",
+			Input: common.ReadParams{ObjectName: "users", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusOK)
@@ -61,7 +75,8 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 			ExpectedErrs: []error{jsonquery.ErrKeyNotFound},
 		},
 		{
-			Name: "Incorrect data type in payload",
+			Name:  "Incorrect data type in payload",
+			Input: common.ReadParams{ObjectName: "users", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusOK)
@@ -72,7 +87,8 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 			ExpectedErrs: []error{jsonquery.ErrNotArray},
 		},
 		{
-			Name: "Next page cursor may be missing in payload",
+			Name:  "Next page cursor may be missing in payload",
+			Input: common.ReadParams{ObjectName: "users", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusOK)
@@ -85,7 +101,8 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 			ExpectedErrs: nil,
 		},
 		{
-			Name: "Next page URL is correctly inferred",
+			Name:  "Next page URL is correctly inferred",
+			Input: common.ReadParams{ObjectName: "people", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusOK)
@@ -96,12 +113,13 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 				return actual.NextPage.String() == expectedNextPage // nolint:nlreturn
 			},
 			Expected: &common.ReadResult{
-				NextPage: "{{testServerURL}}/v2?page=2&per_page=100",
+				NextPage: "{{testServerURL}}/v2/people?page=2&per_page=100",
 			},
 			ExpectedErrs: nil,
 		},
 		{
-			Name: "Successful read with 25 entries, checking one row",
+			Name:  "Successful read with 25 entries, checking one row",
+			Input: common.ReadParams{ObjectName: "people", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusOK)
@@ -131,7 +149,8 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 		{
 			Name: "Successful read with chosen fields",
 			Input: common.ReadParams{
-				Fields: []string{"email_address", "person_company_website"},
+				ObjectName: "people",
+				Fields:     []string{"email_address", "person_company_website"},
 			},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
@@ -161,7 +180,8 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 		{
 			Name: "Listing Users without pagination payload",
 			Input: common.ReadParams{
-				Fields: []string{"email", "guid"},
+				ObjectName: "users",
+				Fields:     []string{"email", "guid"},
 			},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
@@ -192,7 +212,7 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 		},
 		{
 			Name:  "Successful read accounts without since query",
-			Input: common.ReadParams{ObjectName: "accounts"},
+			Input: common.ReadParams{ObjectName: "accounts", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				mockutils.RespondToMissingQueryParameters(w, r, []string{"updated_at[gte]"}, func() {
@@ -213,6 +233,7 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 			Input: common.ReadParams{
 				ObjectName: "accounts",
 				Since:      accountsSince,
+				Fields:     []string{"id"},
 			},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
diff --git a/providers/salesloft/write_test.go b/providers/salesloft/write_test.go
index 4b6982a0..1d9bf9d7 100644
--- a/providers/salesloft/write_test.go
+++ b/providers/salesloft/write_test.go
@@ -29,14 +29,20 @@ func TestWrite(t *testing.T) { // nolint:funlen,cyclop
 			ExpectedErrs: []error{common.ErrMissingObjects},
 		},
 		{
-			Name:         "Mime response header expected",
+			Name:         "Write needs data payload",
 			Input:        common.WriteParams{ObjectName: "signals"},
 			Server:       mockserver.Dummy(),
+			ExpectedErrs: []error{common.ErrMissingRecordData},
+		},
+		{
+			Name:         "Mime response header expected",
+			Input:        common.WriteParams{ObjectName: "signals", RecordData: "dummy"},
+			Server:       mockserver.Dummy(),
 			ExpectedErrs: []error{interpreter.ErrMissingContentType},
 		},
 		{
 			Name:  "Correct error message is understood from JSON response",
-			Input: common.WriteParams{ObjectName: "signals", RecordId: "22165"},
+			Input: common.WriteParams{ObjectName: "signals", RecordId: "22165", RecordData: "dummy"},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusUnprocessableEntity)
@@ -49,7 +55,7 @@ func TestWrite(t *testing.T) { // nolint:funlen,cyclop
 		},
 		{
 			Name:  "Write must act as a Create",
-			Input: common.WriteParams{ObjectName: "signals"},
+			Input: common.WriteParams{ObjectName: "signals", RecordData: "dummy"},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				mockutils.RespondToMethod(w, r, "POST", func() {
@@ -61,7 +67,7 @@ func TestWrite(t *testing.T) { // nolint:funlen,cyclop
 		},
 		{
 			Name:  "Write must act as an Update",
-			Input: common.WriteParams{ObjectName: "signals", RecordId: "22165"},
+			Input: common.WriteParams{ObjectName: "signals", RecordId: "22165", RecordData: "dummy"},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				mockutils.RespondToMethod(w, r, "PUT", func() {
@@ -73,7 +79,7 @@ func TestWrite(t *testing.T) { // nolint:funlen,cyclop
 		},
 		{
 			Name:  "Valid creation of account",
-			Input: common.WriteParams{ObjectName: "accounts"},
+			Input: common.WriteParams{ObjectName: "accounts", RecordData: "dummy"},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				mockutils.RespondToMethod(w, r, "POST", func() {
@@ -100,7 +106,7 @@ func TestWrite(t *testing.T) { // nolint:funlen,cyclop
 		},
 		{
 			Name:  "Valid creation of a task",
-			Input: common.WriteParams{ObjectName: "tasks"},
+			Input: common.WriteParams{ObjectName: "tasks", RecordData: "dummy"},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				mockutils.RespondToMethod(w, r, "POST", func() {
@@ -125,7 +131,7 @@ func TestWrite(t *testing.T) { // nolint:funlen,cyclop
 		},
 		{
 			Name:  "Valid update of Saved List View",
-			Input: common.WriteParams{ObjectName: "saved_list_views", RecordId: "22463"},
+			Input: common.WriteParams{ObjectName: "saved_list_views", RecordId: "22463", RecordData: "dummy"},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				mockutils.RespondToMethod(w, r, "PUT", func() {
diff --git a/providers/smartlead/delete_test.go b/providers/smartlead/delete_test.go
index 7181f787..87b32c8c 100644
--- a/providers/smartlead/delete_test.go
+++ b/providers/smartlead/delete_test.go
@@ -23,7 +23,7 @@ func TestDelete(t *testing.T) { // nolint:funlen,cyclop
 
 	tests := []testroutines.Delete{
 		{
-			Name:         "Write object must be included",
+			Name:         "Delete object must be included",
 			Server:       mockserver.Dummy(),
 			ExpectedErrs: []error{common.ErrMissingObjects},
 		},
diff --git a/providers/smartlead/read_test.go b/providers/smartlead/read_test.go
index 41fe638b..4d2b4431 100644
--- a/providers/smartlead/read_test.go
+++ b/providers/smartlead/read_test.go
@@ -31,14 +31,20 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop
 			ExpectedErrs: []error{common.ErrMissingObjects},
 		},
 		{
-			Name:         "Mime response header expected",
+			Name:         "At least one field is requested",
 			Input:        common.ReadParams{ObjectName: "contact"},
 			Server:       mockserver.Dummy(),
+			ExpectedErrs: []error{common.ErrMissingFields},
+		},
+		{
+			Name:         "Mime response header expected",
+			Input:        common.ReadParams{ObjectName: "contact", Fields: []string{"id"}},
+			Server:       mockserver.Dummy(),
 			ExpectedErrs: []error{interpreter.ErrMissingContentType},
 		},
 		{
 			Name:  "Correct error message is understood from HTML response",
-			Input: common.ReadParams{ObjectName: "contact"},
+			Input: common.ReadParams{ObjectName: "contact", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "text/html")
 				w.WriteHeader(http.StatusBadRequest)
@@ -51,7 +57,7 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop
 		},
 		{
 			Name:  "Incorrect data type in payload",
-			Input: common.ReadParams{ObjectName: "contact"},
+			Input: common.ReadParams{ObjectName: "contact", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusOK)
@@ -61,7 +67,7 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop
 		},
 		{
 			Name:  "Empty read response",
-			Input: common.ReadParams{ObjectName: "campaigns"},
+			Input: common.ReadParams{ObjectName: "campaigns", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusOK)
diff --git a/providers/smartlead/write_test.go b/providers/smartlead/write_test.go
index 00df8f44..57efa428 100644
--- a/providers/smartlead/write_test.go
+++ b/providers/smartlead/write_test.go
@@ -31,14 +31,20 @@ func TestWrite(t *testing.T) { // nolint:funlen,cyclop
 			ExpectedErrs: []error{common.ErrMissingObjects},
 		},
 		{
-			Name:         "Mime response header expected",
+			Name:         "Write needs data payload",
 			Input:        common.WriteParams{ObjectName: "campaigns"},
 			Server:       mockserver.Dummy(),
+			ExpectedErrs: []error{common.ErrMissingRecordData},
+		},
+		{
+			Name:         "Mime response header expected",
+			Input:        common.WriteParams{ObjectName: "campaigns", RecordData: "dummy"},
+			Server:       mockserver.Dummy(),
 			ExpectedErrs: []error{interpreter.ErrMissingContentType},
 		},
 		{
 			Name:     "Unknown object name is not supported",
-			Input:    common.WriteParams{ObjectName: "orders"},
+			Input:    common.WriteParams{ObjectName: "orders", RecordData: "dummy"},
 			Server:   mockserver.Dummy(),
 			Expected: nil,
 			ExpectedErrs: []error{
@@ -47,7 +53,7 @@ func TestWrite(t *testing.T) { // nolint:funlen,cyclop
 		},
 		{
 			Name:  "Update non-existent Email Account",
-			Input: common.WriteParams{ObjectName: "email-accounts", RecordId: "08037"},
+			Input: common.WriteParams{ObjectName: "email-accounts", RecordId: "08037", RecordData: "dummy"},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusNotFound)
@@ -60,7 +66,7 @@ func TestWrite(t *testing.T) { // nolint:funlen,cyclop
 		},
 		{
 			Name:  "Invalid field when creating campaign",
-			Input: common.WriteParams{ObjectName: "campaigns"},
+			Input: common.WriteParams{ObjectName: "campaigns", RecordData: "dummy"},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusBadRequest)
@@ -73,7 +79,7 @@ func TestWrite(t *testing.T) { // nolint:funlen,cyclop
 		},
 		{
 			Name:  "Create new email campaign",
-			Input: common.WriteParams{ObjectName: "campaigns"},
+			Input: common.WriteParams{ObjectName: "campaigns", RecordData: "dummy"},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				mockutils.RespondToMethod(w, r, "POST", func() {
@@ -91,7 +97,7 @@ func TestWrite(t *testing.T) { // nolint:funlen,cyclop
 		},
 		{
 			Name:  "Create new client",
-			Input: common.WriteParams{ObjectName: "client"},
+			Input: common.WriteParams{ObjectName: "client", RecordData: "dummy"},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				mockutils.RespondToMethod(w, r, "POST", func() {
@@ -109,7 +115,7 @@ func TestWrite(t *testing.T) { // nolint:funlen,cyclop
 		},
 		{
 			Name:  "Create new email account",
-			Input: common.WriteParams{ObjectName: "email-accounts"},
+			Input: common.WriteParams{ObjectName: "email-accounts", RecordData: "dummy"},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				mockutils.RespondToMethod(w, r, "POST", func() {
diff --git a/providers/zendesksupport/delete_test.go b/providers/zendesksupport/delete_test.go
index 57552e3f..8a28c215 100644
--- a/providers/zendesksupport/delete_test.go
+++ b/providers/zendesksupport/delete_test.go
@@ -22,7 +22,7 @@ func TestDelete(t *testing.T) { // nolint:funlen,cyclop
 
 	tests := []testroutines.Delete{
 		{
-			Name:         "Write object must be included",
+			Name:         "Delete object must be included",
 			Server:       mockserver.Dummy(),
 			ExpectedErrs: []error{common.ErrMissingObjects},
 		},
diff --git a/providers/zendesksupport/read_test.go b/providers/zendesksupport/read_test.go
index d90f351e..7587e748 100644
--- a/providers/zendesksupport/read_test.go
+++ b/providers/zendesksupport/read_test.go
@@ -32,14 +32,20 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 			ExpectedErrs: []error{common.ErrMissingObjects},
 		},
 		{
-			Name:         "Mime response header expected",
+			Name:         "At least one field is requested",
 			Input:        common.ReadParams{ObjectName: "triggers"},
 			Server:       mockserver.Dummy(),
+			ExpectedErrs: []error{common.ErrMissingFields},
+		},
+		{
+			Name:         "Mime response header expected",
+			Input:        common.ReadParams{ObjectName: "triggers", Fields: []string{"id"}},
+			Server:       mockserver.Dummy(),
 			ExpectedErrs: []error{interpreter.ErrMissingContentType},
 		},
 		{
 			Name:  "Correct error message is understood from JSON response",
-			Input: common.ReadParams{ObjectName: "triggers"},
+			Input: common.ReadParams{ObjectName: "triggers", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusNotFound)
@@ -51,7 +57,7 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 		},
 		{
 			Name:  "Forbidden error code and response",
-			Input: common.ReadParams{ObjectName: "triggers"},
+			Input: common.ReadParams{ObjectName: "triggers", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusForbidden)
@@ -63,7 +69,7 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 		},
 		{
 			Name:  "Incorrect key in payload",
-			Input: common.ReadParams{ObjectName: "triggers"},
+			Input: common.ReadParams{ObjectName: "triggers", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusOK)
@@ -75,7 +81,7 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 		},
 		{
 			Name:  "Incorrect data type in payload",
-			Input: common.ReadParams{ObjectName: "triggers"},
+			Input: common.ReadParams{ObjectName: "triggers", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusOK)
@@ -87,7 +93,7 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 		},
 		{
 			Name:  "Next page cursor may be missing in payload",
-			Input: common.ReadParams{ObjectName: "users"},
+			Input: common.ReadParams{ObjectName: "users", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusOK)
@@ -101,7 +107,7 @@ func TestRead(t *testing.T) { //nolint:funlen,gocognit,cyclop,maintidx
 		},
 		{
 			Name:  "Next page URL is resolved, when provided with a string",
-			Input: common.ReadParams{ObjectName: "users"},
+			Input: common.ReadParams{ObjectName: "users", Fields: []string{"id"}},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusOK)
diff --git a/providers/zendesksupport/write_test.go b/providers/zendesksupport/write_test.go
index 8b66bbdf..eb0fa9a2 100644
--- a/providers/zendesksupport/write_test.go
+++ b/providers/zendesksupport/write_test.go
@@ -33,14 +33,20 @@ func TestWrite(t *testing.T) { // nolint:funlen,cyclop
 			ExpectedErrs: []error{common.ErrMissingObjects},
 		},
 		{
-			Name:         "Mime response header expected",
+			Name:         "Write needs data payload",
 			Input:        common.WriteParams{ObjectName: "signals"},
 			Server:       mockserver.Dummy(),
+			ExpectedErrs: []error{common.ErrMissingRecordData},
+		},
+		{
+			Name:         "Mime response header expected",
+			Input:        common.WriteParams{ObjectName: "signals", RecordData: "dummy"},
+			Server:       mockserver.Dummy(),
 			ExpectedErrs: []error{interpreter.ErrMissingContentType},
 		},
 		{
 			Name:  "Missing write parameter",
-			Input: common.WriteParams{ObjectName: "brands"},
+			Input: common.WriteParams{ObjectName: "brands", RecordData: "dummy"},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusBadRequest)
@@ -53,7 +59,7 @@ func TestWrite(t *testing.T) { // nolint:funlen,cyclop
 		},
 		{
 			Name:  "Record validation with single detail",
-			Input: common.WriteParams{ObjectName: "brands"},
+			Input: common.WriteParams{ObjectName: "brands", RecordData: "dummy"},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusBadRequest)
@@ -67,7 +73,7 @@ func TestWrite(t *testing.T) { // nolint:funlen,cyclop
 		},
 		{
 			Name:  "Record validation with multiple details is split into dedicated errors",
-			Input: common.WriteParams{ObjectName: "brands"},
+			Input: common.WriteParams{ObjectName: "brands", RecordData: "dummy"},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				w.WriteHeader(http.StatusBadRequest)
@@ -83,7 +89,7 @@ func TestWrite(t *testing.T) { // nolint:funlen,cyclop
 		},
 		{
 			Name:  "Write must act as a Create",
-			Input: common.WriteParams{ObjectName: "brands"},
+			Input: common.WriteParams{ObjectName: "brands", RecordData: "dummy"},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				mockutils.RespondToMethod(w, r, "POST", func() {
@@ -94,8 +100,12 @@ func TestWrite(t *testing.T) { // nolint:funlen,cyclop
 			ExpectedErrs: nil,
 		},
 		{
-			Name:  "Write must act as an Update",
-			Input: common.WriteParams{ObjectName: "brands", RecordId: "31207417638931"},
+			Name: "Write must act as an Update",
+			Input: common.WriteParams{
+				ObjectName: "brands",
+				RecordId:   "31207417638931",
+				RecordData: "dummy",
+			},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				mockutils.RespondToMethod(w, r, "PUT", func() {
@@ -107,7 +117,7 @@ func TestWrite(t *testing.T) { // nolint:funlen,cyclop
 		},
 		{
 			Name:  "Valid creation of a brand",
-			Input: common.WriteParams{ObjectName: "brands"},
+			Input: common.WriteParams{ObjectName: "brands", RecordData: "dummy"},
 			Server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/json")
 				mockutils.RespondToMethod(w, r, "POST", func() {
diff --git a/test/salesforce/bulk/utils.go b/test/salesforce/bulk/utils.go
index 3a31f1fb..d6a94366 100644
--- a/test/salesforce/bulk/utils.go
+++ b/test/salesforce/bulk/utils.go
@@ -52,7 +52,7 @@ func getInfoInLoop(
 	})
 }
 
-func GetRecordIDsForJob(ctx context.Context, conn *salesforce.Connector, jobId string)  ([]byte, error) {
+func GetRecordIDsForJob(ctx context.Context, conn *salesforce.Connector, jobId string) ([]byte, error) {
 	// Get the successful results to get the ids to use for the deletion
 	successRes, err := conn.GetSuccessfulJobResults(ctx, jobId)
 	if err != nil {
diff --git a/test/salesforce/bulk/write/check-result.go b/test/salesforce/bulk/write/check-result.go
index e768a9c6..0cb6e8db 100644
--- a/test/salesforce/bulk/write/check-result.go
+++ b/test/salesforce/bulk/write/check-result.go
@@ -4,10 +4,11 @@ import (
 	"context"
 	"encoding/json"
 	"fmt"
-	"github.com/amp-labs/connectors/providers/salesforce"
 	"log/slog"
 	"os"
 	"time"
+
+	"github.com/amp-labs/connectors/providers/salesforce"
 )
 
 func testGetJobResultsForFile(ctx context.Context, conn *salesforce.Connector, fileName string) (string, error) {
diff --git a/test/salesforce/bulk/write/csvgen/main.go b/test/salesforce/bulk/write/csvgen/main.go
index 61415cae..38444cba 100644
--- a/test/salesforce/bulk/write/csvgen/main.go
+++ b/test/salesforce/bulk/write/csvgen/main.go
@@ -2,6 +2,7 @@ package main
 
 import (
 	"fmt"
+
 	"github.com/amp-labs/connectors/test/utils/csvgen"
 	"github.com/amp-labs/connectors/tools/fileconv"
 	"github.com/brianvoe/gofakeit/v6"
@@ -12,6 +13,7 @@ func main() {
 
 	records := make([][]string, size)
 	records[0] = []string{"Name", "StageName", "external_id__c", "CloseDate"}
+
 	for i := 1; i < size; i++ {
 		records[i] = []string{
 			gofakeit.Name(),
diff --git a/test/salesforce/bulk/write/launch-job.go b/test/salesforce/bulk/write/launch-job.go
index 485e498b..09d1bc61 100644
--- a/test/salesforce/bulk/write/launch-job.go
+++ b/test/salesforce/bulk/write/launch-job.go
@@ -4,10 +4,11 @@ import (
 	"context"
 	"encoding/json"
 	"fmt"
-	"github.com/amp-labs/connectors/providers/salesforce"
-	testUtils "github.com/amp-labs/connectors/test/utils"
 	"os"
 	"time"
+
+	"github.com/amp-labs/connectors/providers/salesforce"
+	testUtils "github.com/amp-labs/connectors/test/utils"
 )
 
 func testBulkWriteOpportunity(ctx context.Context, conn *salesforce.Connector, filePath string) (string, error) {
diff --git a/test/utils/csvgen/writer.go b/test/utils/csvgen/writer.go
index 6159b2cd..b1603f17 100644
--- a/test/utils/csvgen/writer.go
+++ b/test/utils/csvgen/writer.go
@@ -13,6 +13,7 @@ func SaveCSV(filePath string, records [][]string) {
 	if err != nil {
 		utils.Fail("couldn't open file for writing", "error", err, "filePath", file)
 	}
+
 	defer func() {
 		if err := file.Close(); err != nil {
 			slog.Error("failed closing file", "error", err)
diff --git a/test/utils/testutils/parallel.go b/test/utils/testutils/parallel.go
index 428a1f01..1421b96b 100644
--- a/test/utils/testutils/parallel.go
+++ b/test/utils/testutils/parallel.go
@@ -2,8 +2,9 @@ package testutils
 
 import (
 	"context"
-	"github.com/amp-labs/connectors/tools/fileconv"
 	"sync"
+
+	"github.com/amp-labs/connectors/tools/fileconv"
 )
 
 const testLineBreak = "\n=============================================\n"
@@ -35,6 +36,7 @@ func (r ParallelRunners[C]) Run(ctx context.Context, conn C) []string {
 			if err != nil {
 				logText = err.Error()
 			}
+
 			logs[idx] = formatLog(test.TestTitle, logText)
 		}(test, i)
 	}