sfdc

package module
v0.2.6 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 15, 2025 License: Apache-2.0 Imports: 12 Imported by: 0

README

sfdc Build and Test

A go client library for the Salesforce REST API.

Usage

Get the Package
go get -u github.com/joefitzgerald/sfdc

Note: this package requires go 1.18 or later.

Connect to the Salesforce API

⚠️ You should make sure you have completed the steps outlined in the Getting Started with the Salesforce API section, below.

package main

import (
	"context"
	"fmt"
	"log"
	"net/http"
	"time"

	"github.com/joefitzgerald/sfdc"
	"github.com/joefitzgerald/sfdc/auth/devicecode"
)

func main() {
	// First: Fetch a Token
	// Note: if you request the `refresh_token` scope, this token includes a 
	// refresh token, which can be used to fetch new tokens in the future without
	// re-authenticating the user.
	// https://help.salesforce.com/s/articleView?id=sf.remoteaccess_oauth_refresh_token_flow.htm
	clientID := "your-client-id"
	clientSecret := "your-client-secret"
	domain := "your-domain"
	scopes := []string{"api", "openid", "id", "profile", "email", "refresh_token"}
	config := devicecode.NewWithDomain(domain, clientID, clientSecret, scopes)
	ctx, cancel := context.WithTimeout(context.Background(), time.Duration(5)*time.Minute)
	defer cancel()
	token, err := config.Token(ctx, http.DefaultClient)
	if err != nil {
		log.Fatal(err)
	}

	// Next: Use the token to construct a sfdc.Instance and then an sfdc.Entity
	// for each SObject you wish to query or interact with.
	instance, err := sfdc.New(sfdc.WithToken(context.Background(), config.Config, token))
	type Opportunity struct {
		ID          string `json:"Id,omitempty"`
		Name        string `json:"Name,omitempty"`
		Description string `json:"Description,omitempty"`
	}
	opportunityEntity := sfdc.NewEntity[Opportunity](instance)

	// Finally: Make requests to the Salesforce API
	opportunities, err := opportunityEntity.Query(context.Background(), "SELECT Id, Name, Description FROM Opportunity where CloseDate = 2019-01-01")
	if err != nil {
		log.Fatal(err)
	}
	for i := range opportunities {
		fmt.Printf("%s: %s\n", opportunities[i].ID, opportunities[i].Name)
	}
}

Getting Started with the Salesforce API

Accessing the Salesforce REST API is straightforward, but requires some one-time preparation:

  1. Sign up for Salesforce Developer Edition
  2. Create a Connected App
  3. Access the Salesforce REST API
Step 1: Sign up for Salesforce Developer Edition

You will need a developer edition organization so that you can register a connected app. If your company already has organization(s) that they use for development, just validate the API Enabled permission, below.

  1. Go to https://developer.salesforce.com/signup
  2. Follow the instructions to create an organization
  3. Verify that your user profile has the API Enabled permission set (this is enabled by default, but an administrator can modify it)
Step 2: Create a Connected App

You need a Connected App so that you can get an OAuth 2.0 Client ID and Client Secret, and configure the scopes that your API client will be able to request and make use of.

  1. In your Developer Edition organization, select “Setup”, and then go to Platform Tools > Apps > Apps Manager.
  2. Select New Connected App.
  3. Fill in the required fields, and then check the Enable OAuth Settings option. In the resulting section:
    • Check the Enable for Device Flow option
    • Add the following scopes:
      • Access the identity URL service (id, profile, email, address, phone): optional, if you want to be able to identify the user by name
      • Access unique user identifiers (openid): required for an OpenID connect payload in your token
      • Manage user data via APIs (api): required for all API access
      • Perform requests at any time (refresh_token, offline_access): required for you to receive a refresh token
    • Check the Configure ID Token option:
      • Set the Token Valid for option to the desired number of minutes
      • Set the Include Standard Claims option
  4. Select Save and then Continue
  5. Note the Client ID and Client Secret that you will make use of with this API client:
    • Client ID: Copy the Consumer Key field and use it as your ClientID
    • Client Secret: Copy the Consumer Secret field and make use of it as your ClientSecret

Documentation

Index

Constants

View Source
const (
	// DateTimeLayout is used to convert SFDC DateTime strings correctly
	DateTimeLayout = "2006-01-02T15:04:05.000Z"
)

Variables

This section is empty.

Functions

This section is empty.

Types

type AuthOption added in v0.2.0

type AuthOption interface {
	// contains filtered or unexported methods
}

func WithNoAuthentication added in v0.2.0

func WithNoAuthentication() AuthOption

WithNoAuthentication specifies that you are handling authentication yourself. You should consider using WithHTTPClient to provide your authenticated HTTPClient.

func WithToken added in v0.2.0

func WithToken(ctx context.Context, config *oauth2.Config, token *oauth2.Token) AuthOption

WithToken is an AuthOption that sets the token to use for authentication

type Entity added in v0.2.0

type Entity[T any] struct {
	// contains filtered or unexported fields
}

func NewEntity added in v0.2.0

func NewEntity[T any](instance *Instance) *Entity[T]

func (*Entity[T]) BuildQuery added in v0.2.0

func (e *Entity[T]) BuildQuery(fields string, constraints string) string

func (*Entity[T]) List added in v0.2.0

func (e *Entity[T]) List(ctx context.Context) (<-chan []T, <-chan error)

List finds all T objects.

func (*Entity[T]) ListModifiedSince added in v0.2.0

func (e *Entity[T]) ListModifiedSince(ctx context.Context, since time.Time) (<-chan []T, <-chan error)

ListModifiedSince finds all T objects modified since some point in time.

func (*Entity[T]) Query added in v0.2.0

func (e *Entity[T]) Query(ctx context.Context, query string) ([]T, error)

func (*Entity[T]) QueryAsync added in v0.2.0

func (e *Entity[T]) QueryAsync(ctx context.Context, query string) (<-chan []T, <-chan error)

QueryAsync returns a channel that T are written to. The channel is closed when all records have been written. Errors are written to the returned error channel. The query aborts when an error is encountered.

func (*Entity[T]) SetName added in v0.2.0

func (e *Entity[T]) SetName(name string)

func (*Entity[T]) TaggedFields added in v0.2.0

func (e *Entity[T]) TaggedFields() string

type Instance added in v0.2.0

type Instance struct {
	// contains filtered or unexported fields
}

func New

func New(auth AuthOption, options ...InstanceOption) (*Instance, error)

func (*Instance) InstanceURL added in v0.2.0

func (i *Instance) InstanceURL() string

func (*Instance) QueryAllURL added in v0.2.0

func (i *Instance) QueryAllURL() (*url.URL, error)

func (*Instance) QueryURL added in v0.2.0

func (i *Instance) QueryURL() url.URL

type InstanceOption added in v0.2.0

type InstanceOption interface {
	// contains filtered or unexported methods
}

func WithAPIVersion added in v0.2.0

func WithAPIVersion(version string) InstanceOption

func WithHTTPClient added in v0.2.0

func WithHTTPClient(client *http.Client) InstanceOption

func WithURL added in v0.2.0

func WithURL(url string) InstanceOption

type Profile added in v0.2.1

type Profile struct {
	ID             string `json:"id,omitempty"`
	AssertedUser   bool   `json:"asserted_user,omitempty"`
	UserID         string `json:"user_id,omitempty"`
	OrganizationID string `json:"organization_id,omitempty"`
	Username       string `json:"username,omitempty"`
	Nickname       string `json:"nick_name,omitempty"`
	DisplayName    string `json:"display_name,omitempty"`
	Email          string `json:"email,omitempty"`
	EmailVerified  bool   `json:"email_verified,omitempty"`
	FirstName      string `json:"first_name,omitempty"`
	LastName       string `json:"last_name,omitempty"`
	Timezone       string `json:"timezone,omitempty"`
	Photos         struct {
		Picture   string `json:"picture,omitempty"`
		Thumbnail string `json:"thumbnail,omitempty"`
	} `json:"photos,omitempty"`
	AddrStreet           string      `json:"addr_street,omitempty"`
	AddrCity             string      `json:"addr_city,omitempty"`
	AddrState            string      `json:"addr_state,omitempty"`
	AddrCountry          string      `json:"addr_country,omitempty"`
	AddrZip              interface{} `json:"addr_zip,omitempty"`
	MobilePhone          interface{} `json:"mobile_phone,omitempty"`
	MobilePhoneVerified  bool        `json:"mobile_phone_verified,omitempty"`
	IsLightningLoginUser bool        `json:"is_lightning_login_user,omitempty"`
	Status               struct {
		CreatedDate string `json:"created_date,omitempty"`
		Body        string `json:"body,omitempty"`
	} `json:"status,omitempty"`
	URLs struct {
		Enterprise   string `json:"enterprise,omitempty"`
		Metadata     string `json:"metadata,omitempty"`
		Partner      string `json:"partner,omitempty"`
		Rest         string `json:"rest,omitempty"`
		Sobjects     string `json:"sobjects,omitempty"`
		Search       string `json:"search,omitempty"`
		Query        string `json:"query,omitempty"`
		Recent       string `json:"recent,omitempty"`
		ToolingSoap  string `json:"tooling_soap,omitempty"`
		ToolingRest  string `json:"tooling_rest,omitempty"`
		Profile      string `json:"profile,omitempty"`
		Feeds        string `json:"feeds,omitempty"`
		Groups       string `json:"groups,omitempty"`
		Users        string `json:"users,omitempty"`
		FeedItems    string `json:"feed_items,omitempty"`
		FeedElements string `json:"feed_elements,omitempty"`
		CustomDomain string `json:"custom_domain,omitempty"`
	} `json:"urls,omitempty"`
	Active           bool      `json:"active,omitempty"`
	UserType         string    `json:"user_type,omitempty"`
	Language         string    `json:"language,omitempty"`
	Locale           string    `json:"locale,omitempty"`
	UtcOffset        int       `json:"utcOffset,omitempty"`
	LastModifiedDate time.Time `json:"last_modified_date,omitempty"`
}

func GetProfile added in v0.2.1

func GetProfile(ctx context.Context, c *oauth2.Config, t *oauth2.Token) (*Profile, error)

type QueryResponse added in v0.2.0

type QueryResponse[T any] struct {
	Done           bool   `json:"done" sfdc:"-"`
	NextRecordsURL string `json:"nextRecordsUrl" sfdc:"-"`
	Records        []T    `json:"records" sfdc:"-"`
	TotalSize      int    `json:"totalSize" sfdc:"-"`
}

Directories

Path Synopsis
auth

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL