github.com/akamai/AkamaiOPEN-edgegrid-golang/v2@v2.17.0/pkg/datastream/stream.go (about)

     1  package datastream
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"net/http"
     8  	"net/url"
     9  	"strconv"
    10  
    11  	validation "github.com/go-ozzo/ozzo-validation/v4"
    12  )
    13  
    14  type (
    15  	// Stream is a ds stream operations API interface
    16  	Stream interface {
    17  		// CreateStream creates a stream
    18  		//
    19  		// See: https://techdocs.akamai.com/datastream2/reference/post-stream
    20  		CreateStream(context.Context, CreateStreamRequest) (*StreamUpdate, error)
    21  
    22  		// GetStream gets stream details
    23  		//
    24  		// See: https://techdocs.akamai.com/datastream2/reference/get-stream
    25  		GetStream(context.Context, GetStreamRequest) (*DetailedStreamVersion, error)
    26  
    27  		// UpdateStream updates a stream
    28  		//
    29  		// See: https://techdocs.akamai.com/datastream2/reference/put-stream
    30  		UpdateStream(context.Context, UpdateStreamRequest) (*StreamUpdate, error)
    31  
    32  		// DeleteStream deletes a stream
    33  		//
    34  		// See: https://techdocs.akamai.com/datastream2/reference/delete-stream
    35  		DeleteStream(context.Context, DeleteStreamRequest) (*DeleteStreamResponse, error)
    36  
    37  		// ListStreams retrieves list of streams
    38  		//
    39  		// See: https://techdocs.akamai.com/datastream2/reference/get-streams
    40  		ListStreams(context.Context, ListStreamsRequest) ([]StreamDetails, error)
    41  	}
    42  
    43  	// DetailedStreamVersion is returned from GetStream
    44  	DetailedStreamVersion struct {
    45  		ActivationStatus ActivationStatus   `json:"activationStatus"`
    46  		Config           Config             `json:"config"`
    47  		Connectors       []ConnectorDetails `json:"connectors"`
    48  		ContractID       string             `json:"contractId"`
    49  		CreatedBy        string             `json:"createdBy"`
    50  		CreatedDate      string             `json:"createdDate"`
    51  		Datasets         []DataSets         `json:"datasets"`
    52  		EmailIDs         string             `json:"emailIds"`
    53  		Errors           []Errors           `json:"errors"`
    54  		GroupID          int                `json:"groupId"`
    55  		GroupName        string             `json:"groupName"`
    56  		ModifiedBy       string             `json:"modifiedBy"`
    57  		ModifiedDate     string             `json:"modifiedDate"`
    58  		ProductID        string             `json:"productId"`
    59  		ProductName      string             `json:"productName"`
    60  		Properties       []Property         `json:"properties"`
    61  		StreamID         int64              `json:"streamId"`
    62  		StreamName       string             `json:"streamName"`
    63  		StreamType       StreamType         `json:"streamType"`
    64  		StreamVersionID  int64              `json:"streamVersionId"`
    65  		TemplateName     TemplateName       `json:"templateName"`
    66  	}
    67  
    68  	// ConnectorDetails provides detailed information about the connector’s configuration in the stream
    69  	ConnectorDetails struct {
    70  		AuthenticationType AuthenticationType `json:"authenticationType"`
    71  		ConnectorID        int                `json:"connectorId"`
    72  		CompressLogs       bool               `json:"compressLogs"`
    73  		ConnectorName      string             `json:"connectorName"`
    74  		ConnectorType      ConnectorType      `json:"connectorType"`
    75  		Path               string             `json:"path"`
    76  		URL                string             `json:"url"`
    77  		Endpoint           string             `json:"endpoint"`
    78  		IndexName          string             `json:"indexName"`
    79  		ServiceAccountName string             `json:"serviceAccountName"`
    80  		ProjectID          string             `json:"projectId"`
    81  		Service            string             `json:"service"`
    82  		Bucket             string             `json:"bucket"`
    83  		Tags               string             `json:"tags"`
    84  		Region             string             `json:"region"`
    85  		AccountName        string             `json:"accountName"`
    86  		Namespace          string             `json:"namespace"`
    87  		ContainerName      string             `json:"containerName"`
    88  		Source             string             `json:"source"`
    89  		ContentType        string             `json:"contentType"`
    90  		CustomHeaderName   string             `json:"customHeaderName"`
    91  		CustomHeaderValue  string             `json:"customHeaderValue"`
    92  		TLSHostname        string             `json:"tlsHostname"`
    93  		MTLS               string             `json:"mTLS"`
    94  	}
    95  
    96  	// StreamConfiguration is used in CreateStream as a request body
    97  	StreamConfiguration struct {
    98  		ActivateNow     bool                `json:"activateNow"`
    99  		Config          Config              `json:"config"`
   100  		Connectors      []AbstractConnector `json:"connectors,omitempty"`
   101  		ContractID      string              `json:"contractId"`
   102  		DatasetFieldIDs []int               `json:"datasetFieldIds"`
   103  		EmailIDs        string              `json:"emailIds,omitempty"`
   104  		GroupID         *int                `json:"groupId"`
   105  		PropertyIDs     []int               `json:"propertyIds"`
   106  		StreamName      string              `json:"streamName"`
   107  		StreamType      StreamType          `json:"streamType"`
   108  		TemplateName    TemplateName        `json:"templateName"`
   109  	}
   110  
   111  	// Config of the configuration of log lines, names of the files sent to a destination, and delivery frequency for these files
   112  	Config struct {
   113  		Delimiter        *DelimiterType `json:"delimiter,omitempty"`
   114  		Format           FormatType     `json:"format,omitempty"`
   115  		Frequency        Frequency      `json:"frequency"`
   116  		UploadFilePrefix string         `json:"uploadFilePrefix,omitempty"`
   117  		UploadFileSuffix string         `json:"uploadFileSuffix,omitempty"`
   118  	}
   119  
   120  	// The Frequency of collecting logs from each uploader and sending these logs to a destination.
   121  	Frequency struct {
   122  		TimeInSec TimeInSec `json:"timeInSec"`
   123  	}
   124  
   125  	// DataSets is a list of fields selected from the associated template that the stream monitors in logs
   126  	DataSets struct {
   127  		DatasetFields           []DatasetFields `json:"datasetFields"`
   128  		DatasetGroupDescription string          `json:"datasetGroupDescription"`
   129  		DatasetGroupName        string          `json:"datasetGroupName"`
   130  	}
   131  
   132  	// DatasetFields is list of data set fields selected from the associated template that the stream monitors in logs
   133  	DatasetFields struct {
   134  		DatasetFieldID          int    `json:"datasetFieldId"`
   135  		DatasetFieldDescription string `json:"datasetFieldDescription"`
   136  		DatasetFieldJsonKey     string `json:"datasetFieldJsonKey"`
   137  		DatasetFieldName        string `json:"datasetFieldName"`
   138  		Order                   int    `json:"order"`
   139  	}
   140  
   141  	// Errors associated to the stream
   142  	Errors struct {
   143  		Detail string `json:"detail"`
   144  		Title  string `json:"title"`
   145  		Type   string `json:"type"`
   146  	}
   147  
   148  	// Property identifies the properties monitored in the stream.
   149  	Property struct {
   150  		Hostnames    []string `json:"hostnames"`
   151  		ProductID    string   `json:"productId"`
   152  		ProductName  string   `json:"productName"`
   153  		PropertyID   int      `json:"propertyId"`
   154  		PropertyName string   `json:"propertyName"`
   155  	}
   156  
   157  	// ActivationStatus is used to create an enum of possible ActivationStatus values
   158  	ActivationStatus string
   159  
   160  	// AbstractConnector is an interface for all Connector types
   161  	AbstractConnector interface {
   162  		SetConnectorType()
   163  		Validate() error
   164  	}
   165  
   166  	// DelimiterType enum
   167  	DelimiterType string
   168  
   169  	// FormatType enum
   170  	FormatType string
   171  
   172  	// TemplateName enum
   173  	TemplateName string
   174  
   175  	// StreamType enum
   176  	StreamType string
   177  
   178  	// TimeInSec enum
   179  	TimeInSec int
   180  
   181  	// CreateStreamRequest is passed to CreateStream
   182  	CreateStreamRequest struct {
   183  		StreamConfiguration StreamConfiguration
   184  	}
   185  
   186  	// GetStreamRequest is passed to GetStream
   187  	GetStreamRequest struct {
   188  		StreamID int64
   189  		Version  *int64
   190  	}
   191  
   192  	// UpdateStreamRequest is passed to UpdateStream
   193  	UpdateStreamRequest struct {
   194  		StreamID            int64
   195  		StreamConfiguration StreamConfiguration
   196  	}
   197  
   198  	// StreamUpdate contains information about stream ID and version
   199  	StreamUpdate struct {
   200  		StreamVersionKey StreamVersionKey `json:"streamVersionKey"`
   201  	}
   202  
   203  	// StreamVersionKey contains information about stream ID and version
   204  	StreamVersionKey struct {
   205  		StreamID        int64 `json:"streamId"`
   206  		StreamVersionID int64 `json:"streamVersionId"`
   207  	}
   208  
   209  	// DeleteStreamRequest is passed to DeleteStream
   210  	DeleteStreamRequest struct {
   211  		StreamID int64
   212  	}
   213  
   214  	// DeleteStreamResponse is returned from DeleteStream
   215  	DeleteStreamResponse struct {
   216  		Message string `json:"message"`
   217  	}
   218  
   219  	// ListStreamsRequest is passed to ListStreams
   220  	ListStreamsRequest struct {
   221  		GroupID *int
   222  	}
   223  
   224  	// StreamDetails contains information about stream
   225  	StreamDetails struct {
   226  		ActivationStatus ActivationStatus `json:"activationStatus"`
   227  		Archived         bool             `json:"archived"`
   228  		Connectors       string           `json:"connectors"`
   229  		ContractID       string           `json:"contractId"`
   230  		CreatedBy        string           `json:"createdBy"`
   231  		CreatedDate      string           `json:"createdDate"`
   232  		CurrentVersionID int64            `json:"currentVersionId"`
   233  		Errors           []Errors         `json:"errors"`
   234  		GroupID          int              `json:"groupId"`
   235  		GroupName        string           `json:"groupName"`
   236  		Properties       []Property       `json:"properties"`
   237  		StreamID         int64            `json:"streamId"`
   238  		StreamName       string           `json:"streamName"`
   239  		StreamTypeName   string           `json:"streamTypeName"`
   240  		StreamVersionID  int64            `json:"streamVersionId"`
   241  	}
   242  )
   243  
   244  const (
   245  	// ActivationStatusActivated const
   246  	ActivationStatusActivated ActivationStatus = "ACTIVATED"
   247  	// ActivationStatusDeactivated const
   248  	ActivationStatusDeactivated ActivationStatus = "DEACTIVATED"
   249  	// ActivationStatusActivating const
   250  	ActivationStatusActivating ActivationStatus = "ACTIVATING"
   251  	// ActivationStatusDeactivating const state
   252  	ActivationStatusDeactivating ActivationStatus = "DEACTIVATING"
   253  	// ActivationStatusInactive const
   254  	ActivationStatusInactive ActivationStatus = "INACTIVE"
   255  
   256  	// StreamTypeRawLogs const
   257  	StreamTypeRawLogs StreamType = "RAW_LOGS"
   258  
   259  	// TemplateNameEdgeLogs const
   260  	TemplateNameEdgeLogs TemplateName = "EDGE_LOGS"
   261  
   262  	// DelimiterTypeSpace const
   263  	DelimiterTypeSpace DelimiterType = "SPACE"
   264  
   265  	// FormatTypeStructured const
   266  	FormatTypeStructured FormatType = "STRUCTURED"
   267  	// FormatTypeJson const
   268  	FormatTypeJson FormatType = "JSON"
   269  
   270  	// TimeInSec30 const
   271  	TimeInSec30 TimeInSec = 30
   272  	// TimeInSec60 const
   273  	TimeInSec60 TimeInSec = 60
   274  )
   275  
   276  // Validate validates CreateStreamRequest
   277  func (r CreateStreamRequest) Validate() error {
   278  	return validation.Errors{
   279  		"StreamConfiguration.Config":                     validation.Validate(r.StreamConfiguration.Config, validation.Required),
   280  		"StreamConfiguration.Config.Delimiter":           validation.Validate(r.StreamConfiguration.Config.Delimiter, validation.When(r.StreamConfiguration.Config.Format == FormatTypeStructured, validation.Required, validation.In(DelimiterTypeSpace)), validation.When(r.StreamConfiguration.Config.Format == FormatTypeJson, validation.Nil)),
   281  		"StreamConfiguration.Config.Format":              validation.Validate(r.StreamConfiguration.Config.Format, validation.Required, validation.In(FormatTypeStructured, FormatTypeJson), validation.When(r.StreamConfiguration.Config.Delimiter != nil, validation.Required, validation.In(FormatTypeStructured))),
   282  		"StreamConfiguration.Config.Frequency":           validation.Validate(r.StreamConfiguration.Config.Frequency, validation.Required),
   283  		"StreamConfiguration.Config.Frequency.TimeInSec": validation.Validate(r.StreamConfiguration.Config.Frequency.TimeInSec, validation.Required, validation.In(TimeInSec30, TimeInSec60)),
   284  		"StreamConfiguration.Connectors":                 validation.Validate(r.StreamConfiguration.Connectors, validation.Required, validation.Length(1, 1)),
   285  		"StreamConfiguration.ContractId":                 validation.Validate(r.StreamConfiguration.ContractID, validation.Required),
   286  		"StreamConfiguration.DatasetFields":              validation.Validate(r.StreamConfiguration.DatasetFieldIDs, validation.Required),
   287  		"StreamConfiguration.GroupID":                    validation.Validate(r.StreamConfiguration.GroupID, validation.Required),
   288  		"StreamConfiguration.PropertyIDs":                validation.Validate(r.StreamConfiguration.PropertyIDs, validation.Required),
   289  		"StreamConfiguration.StreamName":                 validation.Validate(r.StreamConfiguration.StreamName, validation.Required),
   290  		"StreamConfiguration.StreamType":                 validation.Validate(r.StreamConfiguration.StreamType, validation.Required, validation.In(StreamTypeRawLogs)),
   291  		"StreamConfiguration.TemplateName":               validation.Validate(r.StreamConfiguration.TemplateName, validation.Required, validation.In(TemplateNameEdgeLogs)),
   292  	}.Filter()
   293  }
   294  
   295  // Validate validates GetStreamRequest
   296  func (r GetStreamRequest) Validate() error {
   297  	return validation.Errors{
   298  		"streamId": validation.Validate(r.StreamID, validation.Required),
   299  	}.Filter()
   300  }
   301  
   302  // Validate validates UpdateStreamRequest
   303  func (r UpdateStreamRequest) Validate() error {
   304  	return validation.Errors{
   305  		"StreamConfiguration.Config":                     validation.Validate(r.StreamConfiguration.Config, validation.Required),
   306  		"StreamConfiguration.Config.Delimiter":           validation.Validate(r.StreamConfiguration.Config.Delimiter, validation.When(r.StreamConfiguration.Config.Format == FormatTypeStructured, validation.Required, validation.In(DelimiterTypeSpace)), validation.When(r.StreamConfiguration.Config.Format == FormatTypeJson, validation.Nil)),
   307  		"StreamConfiguration.Config.Format":              validation.Validate(r.StreamConfiguration.Config.Format, validation.In(FormatTypeStructured, FormatTypeJson)),
   308  		"StreamConfiguration.Config.Frequency":           validation.Validate(r.StreamConfiguration.Config.Frequency, validation.Required),
   309  		"StreamConfiguration.Config.Frequency.TimeInSec": validation.Validate(r.StreamConfiguration.Config.Frequency.TimeInSec, validation.Required, validation.In(TimeInSec30, TimeInSec60)),
   310  		"StreamConfiguration.Connectors":                 validation.Validate(r.StreamConfiguration.Connectors, validation.When(r.StreamConfiguration.Connectors != nil, validation.Length(1, 1))),
   311  		"StreamConfiguration.ContractId":                 validation.Validate(r.StreamConfiguration.ContractID, validation.Required),
   312  		"StreamConfiguration.DatasetFields":              validation.Validate(r.StreamConfiguration.DatasetFieldIDs, validation.Required),
   313  		"StreamConfiguration.GroupID":                    validation.Validate(r.StreamConfiguration.GroupID, validation.Nil),
   314  		"StreamConfiguration.PropertyIDs":                validation.Validate(r.StreamConfiguration.PropertyIDs, validation.Required),
   315  		"StreamConfiguration.StreamName":                 validation.Validate(r.StreamConfiguration.StreamName, validation.Required),
   316  		"StreamConfiguration.StreamType":                 validation.Validate(r.StreamConfiguration.StreamType, validation.Required, validation.In(StreamTypeRawLogs)),
   317  		"StreamConfiguration.TemplateName":               validation.Validate(r.StreamConfiguration.TemplateName, validation.Required, validation.In(TemplateNameEdgeLogs)),
   318  	}.Filter()
   319  }
   320  
   321  // Validate validates DeleteStreamRequest
   322  func (r DeleteStreamRequest) Validate() error {
   323  	return validation.Errors{
   324  		"streamId": validation.Validate(r.StreamID, validation.Required),
   325  	}.Filter()
   326  }
   327  
   328  var (
   329  	// ErrCreateStream represents error when creating stream fails
   330  	ErrCreateStream = errors.New("creating stream")
   331  	// ErrGetStream represents error when fetching stream fails
   332  	ErrGetStream = errors.New("fetching stream information")
   333  	// ErrUpdateStream represents error when updating stream fails
   334  	ErrUpdateStream = errors.New("updating stream")
   335  	// ErrDeleteStream represents error when deleting stream fails
   336  	ErrDeleteStream = errors.New("deleting stream")
   337  	// ErrListStreams represents error when listing streams fails
   338  	ErrListStreams = errors.New("listing streams")
   339  )
   340  
   341  func (d *ds) CreateStream(ctx context.Context, params CreateStreamRequest) (*StreamUpdate, error) {
   342  	logger := d.Log(ctx)
   343  	logger.Debug("CreateStream")
   344  
   345  	setConnectorTypes(&params.StreamConfiguration)
   346  	if err := params.Validate(); err != nil {
   347  		return nil, fmt.Errorf("%s: %w: %s", ErrCreateStream, ErrStructValidation, err)
   348  	}
   349  
   350  	uri := "/datastream-config-api/v1/log/streams"
   351  
   352  	req, err := http.NewRequestWithContext(ctx, http.MethodPost, uri, nil)
   353  	if err != nil {
   354  		return nil, fmt.Errorf("%w: failed to create request: %s", ErrCreateStream, err)
   355  	}
   356  
   357  	var rval StreamUpdate
   358  	resp, err := d.Exec(req, &rval, params.StreamConfiguration)
   359  	if err != nil {
   360  		return nil, fmt.Errorf("%w: request failed: %s", ErrCreateStream, err)
   361  	}
   362  
   363  	if resp.StatusCode != http.StatusAccepted {
   364  		return nil, fmt.Errorf("%s: %w", ErrCreateStream, d.Error(resp))
   365  	}
   366  
   367  	return &rval, nil
   368  }
   369  
   370  func (d *ds) GetStream(ctx context.Context, params GetStreamRequest) (*DetailedStreamVersion, error) {
   371  	logger := d.Log(ctx)
   372  	logger.Debug("GetStream")
   373  
   374  	if err := params.Validate(); err != nil {
   375  		return nil, fmt.Errorf("%s: %w: %s", ErrGetStream, ErrStructValidation, err)
   376  	}
   377  
   378  	uri, err := url.Parse(fmt.Sprintf(
   379  		"/datastream-config-api/v1/log/streams/%d",
   380  		params.StreamID))
   381  	if err != nil {
   382  		return nil, fmt.Errorf("%w: failed to parse url: %s", ErrGetStream, err)
   383  	}
   384  
   385  	if params.Version != nil {
   386  		query := uri.Query()
   387  		query.Add("version", strconv.FormatInt(*params.Version, 10))
   388  		uri.RawQuery = query.Encode()
   389  	}
   390  
   391  	req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri.String(), nil)
   392  	if err != nil {
   393  		return nil, fmt.Errorf("%w: failed to create request: %s", ErrGetStream, err)
   394  	}
   395  
   396  	var rval DetailedStreamVersion
   397  	resp, err := d.Exec(req, &rval)
   398  	if err != nil {
   399  		return nil, fmt.Errorf("%w: request failed: %s", ErrGetStream, err)
   400  	}
   401  
   402  	if resp.StatusCode != http.StatusOK {
   403  		return nil, fmt.Errorf("%s: %w", ErrGetStream, d.Error(resp))
   404  	}
   405  
   406  	return &rval, nil
   407  }
   408  
   409  func (d *ds) UpdateStream(ctx context.Context, params UpdateStreamRequest) (*StreamUpdate, error) {
   410  	logger := d.Log(ctx)
   411  	logger.Debug("UpdateStream")
   412  
   413  	setConnectorTypes(&params.StreamConfiguration)
   414  	if err := params.Validate(); err != nil {
   415  		return nil, fmt.Errorf("%s: %w: %s", ErrUpdateStream, ErrStructValidation, err)
   416  	}
   417  
   418  	uri, err := url.Parse(fmt.Sprintf(
   419  		"/datastream-config-api/v1/log/streams/%d",
   420  		params.StreamID),
   421  	)
   422  	if err != nil {
   423  		return nil, fmt.Errorf("%w: failed to parse url: %s", ErrUpdateStream, err)
   424  	}
   425  
   426  	req, err := http.NewRequestWithContext(ctx, http.MethodPut, uri.String(), nil)
   427  	if err != nil {
   428  		return nil, fmt.Errorf("%w: failed to create request: %s", ErrUpdateStream, err)
   429  	}
   430  
   431  	var rval StreamUpdate
   432  	resp, err := d.Exec(req, &rval, params.StreamConfiguration)
   433  	if err != nil {
   434  		return nil, fmt.Errorf("%w: request failed: %s", ErrUpdateStream, err)
   435  	}
   436  
   437  	if resp.StatusCode != http.StatusAccepted {
   438  		return nil, fmt.Errorf("%s: %w", ErrUpdateStream, d.Error(resp))
   439  	}
   440  
   441  	return &rval, nil
   442  }
   443  
   444  func (d *ds) DeleteStream(ctx context.Context, params DeleteStreamRequest) (*DeleteStreamResponse, error) {
   445  	logger := d.Log(ctx)
   446  	logger.Debug("DeleteStream")
   447  
   448  	if err := params.Validate(); err != nil {
   449  		return nil, fmt.Errorf("%s: %w: %s", ErrDeleteStream, ErrStructValidation, err)
   450  	}
   451  
   452  	uri, err := url.Parse(fmt.Sprintf(
   453  		"/datastream-config-api/v1/log/streams/%d",
   454  		params.StreamID),
   455  	)
   456  	if err != nil {
   457  		return nil, fmt.Errorf("%w: failed to parse url: %s", ErrDeleteStream, err)
   458  	}
   459  
   460  	req, err := http.NewRequestWithContext(ctx, http.MethodDelete, uri.String(), nil)
   461  	if err != nil {
   462  		return nil, fmt.Errorf("%w: failed to create request: %s", ErrDeleteStream, err)
   463  	}
   464  
   465  	var rval DeleteStreamResponse
   466  	resp, err := d.Exec(req, &rval)
   467  	if err != nil {
   468  		return nil, fmt.Errorf("%w: request failed: %s", ErrDeleteStream, err)
   469  	}
   470  
   471  	if resp.StatusCode != http.StatusOK {
   472  		return nil, fmt.Errorf("%s: %w", ErrDeleteStream, d.Error(resp))
   473  	}
   474  
   475  	return &rval, nil
   476  }
   477  
   478  func (d *ds) ListStreams(ctx context.Context, params ListStreamsRequest) ([]StreamDetails, error) {
   479  	logger := d.Log(ctx)
   480  	logger.Debug("ListStreams")
   481  
   482  	uri, err := url.Parse("/datastream-config-api/v1/log/streams")
   483  	if err != nil {
   484  		return nil, fmt.Errorf("%w: failed to parse url: %s", ErrListStreams, err)
   485  	}
   486  
   487  	q := uri.Query()
   488  	if params.GroupID != nil {
   489  		q.Add("groupId", fmt.Sprintf("%d", *params.GroupID))
   490  	}
   491  
   492  	uri.RawQuery = q.Encode()
   493  	req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri.String(), nil)
   494  	if err != nil {
   495  		return nil, fmt.Errorf("%w: failed to create request: %s", ErrListStreams, err)
   496  	}
   497  
   498  	var result []StreamDetails
   499  	resp, err := d.Exec(req, &result)
   500  	if err != nil {
   501  		return nil, fmt.Errorf("%w: request failed: %s", ErrListStreams, err)
   502  	}
   503  
   504  	if resp.StatusCode != http.StatusOK {
   505  		return nil, fmt.Errorf("%s: %w", ErrListStreams, d.Error(resp))
   506  	}
   507  
   508  	return result, nil
   509  }
   510  
   511  func setConnectorTypes(configuration *StreamConfiguration) {
   512  	for _, connector := range configuration.Connectors {
   513  		connector.SetConnectorType()
   514  	}
   515  }