Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions providers/hubspot/connector.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,14 +70,12 @@ func constructor(base *components.Connector) (*Connector, error) {
},
)

connector.customAdapter = custom.NewAdapter(connector.JSONHTTPClient(), connector.ModuleInfo())
associationsStrategy := associations.NewStrategy(
connector.JSONHTTPClient(), connector.ModuleInfo(), connector.ProviderInfo(),
)
connector.customAdapter = custom.NewAdapter(connector.JSONHTTPClient(), connector.ProviderInfo())
associationsStrategy := associations.NewStrategy(connector.JSONHTTPClient(), connector.ProviderInfo())
connector.associationsFiller = associationsStrategy
connector.batchAdapter = batch.NewAdapter(connector.HTTPClient(), connector.ModuleInfo(), associationsStrategy)
connector.batchAdapter = batch.NewAdapter(connector.HTTPClient(), connector.ProviderInfo(), associationsStrategy)
connector.searchStrategy = search.NewStrategy(
connector.JSONHTTPClient(), connector.ModuleInfo(), connector.associationsFiller,
connector.JSONHTTPClient(), connector.ProviderInfo(), connector.associationsFiller,
)

return connector, nil
Expand Down
2 changes: 1 addition & 1 deletion providers/hubspot/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
)

func (c *Connector) buildDeleteRequest(ctx context.Context, params common.DeleteParams) (*http.Request, error) {
url, err := c.getDeleteURL(params.ObjectName, params.RecordId)
url, err := c.getCRMObjectsDeleteURL(params.ObjectName, params.RecordId)
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion providers/hubspot/internal/associations/create_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ func constructTestStrategy(serverURL string) (*Strategy, error) {

transport.SetUnitTestMockServerBaseURL(serverURL)

return NewStrategy(transport.JSONHTTPClient(), transport.ModuleInfo(), transport.ProviderInfo()), nil
return NewStrategy(transport.JSONHTTPClient(), transport.ProviderInfo()), nil
}

type (
Expand Down
10 changes: 3 additions & 7 deletions providers/hubspot/internal/associations/strategy.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,12 @@ import (

type Strategy struct {
clientCRM *common.JSONHTTPClient
moduleInfo *providers.ModuleInfo
providerInfo *providers.ProviderInfo
}

func NewStrategy(
hubspotCRMClient *common.JSONHTTPClient, moduleInfo *providers.ModuleInfo, providerInfo *providers.ProviderInfo,
) *Strategy {
func NewStrategy(hubspotCRMClient *common.JSONHTTPClient, providerInfo *providers.ProviderInfo) *Strategy {
return &Strategy{
clientCRM: hubspotCRMClient,
moduleInfo: moduleInfo,
providerInfo: providerInfo,
}
}
Expand All @@ -28,7 +24,7 @@ func NewStrategy(
// nolint:lll
// https://developers.hubspot.com/docs/api-reference/latest/crm/associations/associate-records/batch/get-associations
func (s Strategy) getReadAssociationsURL(fromObject, toObject string) (*urlbuilder.URL, error) {
return urlbuilder.New(s.moduleInfo.BaseURL,
return urlbuilder.New(s.providerInfo.BaseURL, "crm",
"associations", core.APIVersion2026March, fromObject, toObject, "batch/read")
}

Expand All @@ -37,7 +33,7 @@ func (s Strategy) getReadAssociationsURL(fromObject, toObject string) (*urlbuild
// nolint:lll
// https://developers.hubspot.com/docs/api-reference/latest/crm/associations/associate-records/batch/create-associations-labeled
func (s Strategy) getCreateAssociationsURL(fromObject, toObject string) (*urlbuilder.URL, error) {
return urlbuilder.New(s.moduleInfo.BaseURL,
return urlbuilder.New(s.providerInfo.BaseURL, "crm",
"associations", core.APIVersion2026March, fromObject, toObject, "batch/create")
}

Expand Down
16 changes: 6 additions & 10 deletions providers/hubspot/internal/batch/adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ import (
// It abstracts API endpoint construction, versioning, and JSON response processing
// specific to the HubSpot Batch feature.
type Adapter struct {
Client *common.JSONHTTPClient
moduleInfo *providers.ModuleInfo
Client *common.JSONHTTPClient
providerInfo *providers.ProviderInfo

// Batch updating objects does not support manipulating associations.
// associationsStrategy is used to create associations as a follow up.
Expand All @@ -26,7 +26,7 @@ type Adapter struct {

// NewAdapter creates a new batch Adapter configured to work with Hubspot's APIs.
func NewAdapter(
hubspotCRMClient *common.HTTPClient, moduleInfo *providers.ModuleInfo,
hubspotCRMClient *common.HTTPClient, providerInfo *providers.ProviderInfo,
associationsStrategy *associations.Strategy,
) *Adapter {
shouldHandleError := func(response *http.Response) bool {
Expand All @@ -50,27 +50,23 @@ func NewAdapter(

return &Adapter{
Client: jsonHTTPClient,
moduleInfo: moduleInfo,
providerInfo: providerInfo,
associationsStrategy: associationsStrategy,
}
}

func (a *Adapter) getModuleURL() string {
return a.moduleInfo.BaseURL
}

// getCreateURL builds the HubSpot batch create endpoint for the given object type.
//
// nolint:lll
// Contacts example: https://developers.hubspot.com/docs/api-reference/latest/crm/objects/contacts/batch/create-contacts
func (a *Adapter) getCreateURL(objectName common.ObjectName) (*urlbuilder.URL, error) {
return urlbuilder.New(a.getModuleURL(), "objects", core.APIVersion2026March, objectName.String(), "batch/create")
return urlbuilder.New(a.providerInfo.BaseURL, "crm", "objects", core.APIVersion2026March, objectName.String(), "batch/create")
}

// getUpdateURL builds the HubSpot batch update endpoint for the given object type.
//
// nolint:lll
// Contacts example: https://developers.hubspot.com/docs/api-reference/latest/crm/objects/contacts/batch/update-contacts
func (a *Adapter) getUpdateURL(objectName common.ObjectName) (*urlbuilder.URL, error) {
return urlbuilder.New(a.getModuleURL(), "objects", core.APIVersion2026March, objectName.String(), "batch/update")
return urlbuilder.New(a.providerInfo.BaseURL, "crm", "objects", core.APIVersion2026March, objectName.String(), "batch/update")
}
18 changes: 9 additions & 9 deletions providers/hubspot/internal/custom/adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,37 +8,37 @@ import (
)

type Adapter struct {
Client *common.JSONHTTPClient
moduleInfo *providers.ModuleInfo
Client *common.JSONHTTPClient
providerInfo *providers.ProviderInfo
}

func NewAdapter(client *common.JSONHTTPClient, moduleInfo *providers.ModuleInfo) *Adapter {
func NewAdapter(client *common.JSONHTTPClient, providerInfo *providers.ProviderInfo) *Adapter {
return &Adapter{
Client: client,
moduleInfo: moduleInfo,
Client: client,
providerInfo: providerInfo,
}
}

// https://developers.hubspot.com/docs/api-reference/latest/crm/properties/batch/create-properties
// Note: Version APIVersion2026March is NOT FOUND at the moment for this endpoint. Using older V3.
func (a *Adapter) getPropertyBatchCreateURL(objectName string) (*urlbuilder.URL, error) {
return urlbuilder.New(a.moduleInfo.BaseURL, core.APIVersion3, "properties", objectName, "/batch/create")
return urlbuilder.New(a.providerInfo.BaseURL, "crm", core.APIVersion3, "properties", objectName, "/batch/create")
}

// https://developers.hubspot.com/docs/api-reference/latest/crm/properties/update-property
// Note: Version APIVersion2026March is NOT FOUND at the moment for this endpoint. Using older V3.
func (a *Adapter) getPropertyUpdateURL(objectName, propertyName string) (*urlbuilder.URL, error) {
return urlbuilder.New(a.moduleInfo.BaseURL, core.APIVersion3, "properties", objectName, propertyName)
return urlbuilder.New(a.providerInfo.BaseURL, "crm", core.APIVersion3, "properties", objectName, propertyName)
}

// https://developers.hubspot.com/docs/api-reference/latest/crm/properties/property-groups/get-property
// Note: Version APIVersion2026March is NOT FOUND at the moment for this endpoint. Using older V3.
func (a *Adapter) getPropertyGroupNameURL(objectName, groupName string) (*urlbuilder.URL, error) {
return urlbuilder.New(a.moduleInfo.BaseURL, core.APIVersion3, "properties", objectName, "groups", groupName)
return urlbuilder.New(a.providerInfo.BaseURL, "crm", core.APIVersion3, "properties", objectName, "groups", groupName)
}

// https://developers.hubspot.com/docs/api-reference/latest/crm/properties/property-groups/create-property
// Note: Version APIVersion2026March is NOT FOUND at the moment for this endpoint. Using older V3.
func (a *Adapter) getPropertyGroupNameCreationURL(objectName string) (*urlbuilder.URL, error) {
return urlbuilder.New(a.moduleInfo.BaseURL, core.APIVersion3, "properties", objectName, "groups")
return urlbuilder.New(a.providerInfo.BaseURL, "crm", core.APIVersion3, "properties", objectName, "groups")
}
14 changes: 5 additions & 9 deletions providers/hubspot/internal/search/strategy.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,36 +12,32 @@ import (

type Strategy struct {
clientCRM *common.JSONHTTPClient
moduleInfo *providers.ModuleInfo
providerInfo *providers.ProviderInfo
associationsFiller associations.Filler
}

func NewStrategy(
hubspotCRMClient *common.JSONHTTPClient,
moduleInfo *providers.ModuleInfo,
providerInfo *providers.ProviderInfo,
associationsStrategy associations.Filler,
) *Strategy {
return &Strategy{
clientCRM: hubspotCRMClient, // reuses error handling from Hubspot CRM connector.
moduleInfo: moduleInfo,
providerInfo: providerInfo,
associationsFiller: associationsStrategy,
}
}

func (s Strategy) getModuleURL(paths ...string) (*urlbuilder.URL, error) {
return urlbuilder.New(s.moduleInfo.BaseURL, paths...)
}

// https://developers.hubspot.com/docs/api-reference/latest/crm/search-the-crm#make-a-search-request
func (s Strategy) getObjectsAPISearchURL(objectName string) (*urlbuilder.URL, error) {
return s.getModuleURL("objects", core.APIVersion2026March, objectName, "search")
return urlbuilder.New(s.providerInfo.BaseURL, "crm", "objects", core.APIVersion2026March, objectName, "search")
}

func (s Strategy) getSearchURL(objectName string) (*urlbuilder.URL, error) {
switch objectName {
case "lists":
// https://developers.hubspot.com/docs/api-reference/latest/crm/lists/guide#retrieve-by-searching-list-details
return s.getModuleURL("lists", core.APIVersion2026March, "search")
return urlbuilder.New(s.providerInfo.BaseURL, "crm", "lists", core.APIVersion2026March, "search")
default:
return nil, fmt.Errorf("%w: search not supported for %v", common.ErrObjectNotSupported, objectName)
}
Expand Down
4 changes: 2 additions & 2 deletions providers/hubspot/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ func (c *Connector) getObjectMetadata(ctx context.Context, objectName string) (*
func (c *Connector) getObjectMetadataFromPropertyAPI(
ctx context.Context, objectName string,
) (*common.ObjectMetadata, error) {
url, err := c.getPropertiesURL(objectName)
url, err := c.getCRMPropertiesURL(objectName)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -519,7 +519,7 @@ type stage struct {
func (c *Connector) fetchRequiredFieldsBestEffort(
ctx context.Context, objectName string, fields map[string]common.FieldMetadata,
) (map[string]common.FieldMetadata, error) {
url, err := c.getObjectSchemaURL(objectName)
url, err := c.getCRMSchemaURL(objectName)
if err != nil {
return nil, err
}
Expand Down
30 changes: 13 additions & 17 deletions providers/hubspot/read.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,34 +88,30 @@ func (c *Connector) Read(ctx context.Context, config common.ReadParams) (*common
)
}

func (c *Connector) buildReadURL(config common.ReadParams) (string, error) {
if len(config.NextPage) != 0 {
func (c *Connector) buildReadURL(params common.ReadParams) (string, error) {
if len(params.NextPage) != 0 {
// If NextPage is set, then we're reading the next page of results.
// All that matters is the NextPage URL, the fields are ignored.
return config.NextPage.String(), nil
return params.NextPage.String(), nil
}

// If NextPage is not set, then we're reading the first page of results.
// We need to construct the query and then make the request.
// NB: The final slash is just to emulate prior behavior in earlier versions
// of this code. If it turns out to be unnecessary, remove it.
return c.getCRMObjectsReadURL(config)
}

// makeCRMObjectsQueryValues returns the query for the desired read operation.
func makeCRMObjectsQueryValues(config common.ReadParams) []string {
var out []string
url, err := c.getCRMObjectsURL(params.ObjectName)
if err != nil {
return "", err
}

fields := config.Fields.List()
fields := params.Fields.List()
if len(fields) != 0 {
out = append(out, "properties", strings.Join(fields, ","))
url.WithQueryParam("properties", strings.Join(fields, ","))
}

if config.Deleted {
out = append(out, "archived", "true")
if params.Deleted {
url.WithQueryParam("archived", "true")
}

out = append(out, "limit", core.DefaultPageSize)
url.WithQueryParam("limit", core.DefaultPageSize)

return out
return url.String(), nil
}
6 changes: 2 additions & 4 deletions providers/hubspot/record-count.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,7 @@ func (c *Connector) GetRecordCount(
params *common.RecordCountParams,
) (*common.RecordCountResult, error) {
// Build search URL
url, err := c.getCRMObjectsSearchURL(SearchParams{
ObjectName: params.ObjectName,
})
url, err := c.getCRMObjectsSearchURL(params.ObjectName)
if err != nil {
return nil, fmt.Errorf("failed to build search URL: %w", err)
}
Expand Down Expand Up @@ -61,7 +59,7 @@ func (c *Connector) GetRecordCount(
}

// Execute the search request
response, err := c.JSONHTTPClient().Post(ctx, url, filterBody)
response, err := c.JSONHTTPClient().Post(ctx, url.String(), filterBody)
if err != nil {
return nil, fmt.Errorf("failed to execute search request: %w", err)
}
Expand Down
15 changes: 9 additions & 6 deletions providers/hubspot/record.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func (c *Connector) GetRecordsByIds(

pluralObjectName := naming.NewPluralString(objectName).String()

u, err := c.getBatchRecordsURL(pluralObjectName, associationsList)
u, err := c.buildBatchRecordsURL(pluralObjectName, associationsList)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -88,12 +88,15 @@ func (c *Connector) GetRecordsByIds(
return marshaller(records, fields)
}

func (c *Connector) getBatchRecordsURL(objectName string, associations []string) (string, error) {
relativePath := strings.Join([]string{"/objects", objectName, "batch", "read"}, "/")
func (c *Connector) buildBatchRecordsURL(objectName string, associations []string) (string, error) {
url, err := c.getCRMObjectsBatchReadURL(objectName)
if err != nil {
return "", err
}

if len(associations) > 0 {
return c.getURL(relativePath, "associations", strings.Join(associations, ","))
} else {
return c.getURL(relativePath)
url.WithQueryParam("associations", strings.Join(associations, ","))
}

return url.String(), nil
}
8 changes: 4 additions & 4 deletions providers/hubspot/search.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,12 @@ func (c *Connector) ReadUsingSearchAPI(ctx context.Context, config SearchParams)
})
}

url, err := c.getCRMObjectsSearchURL(config)
url, err := c.getCRMObjectsSearchURL(config.ObjectName)
if err != nil {
return nil, err
}

rsp, err := c.JSONHTTPClient().Post(ctx, url, makeFilterBody(config))
rsp, err := c.JSONHTTPClient().Post(ctx, url.String(), makeFilterBody(config))
if err != nil {
return nil, err
}
Expand All @@ -91,7 +91,7 @@ func (c *Connector) searchCRM(
return nil, err
}

url, err := c.getCRMSearchURL(config)
url, err := c.getCRMSearchURL(config.ObjectName)
if err != nil {
return nil, err
}
Expand All @@ -101,7 +101,7 @@ func (c *Connector) searchCRM(
return nil, err
}

rsp, err := c.JSONHTTPClient().Post(ctx, url, payload)
rsp, err := c.JSONHTTPClient().Post(ctx, url.String(), payload)
if err != nil {
return nil, err
}
Expand Down
Loading
Loading