From 9ca5f5524b1cd30b78fa25e1cbe9633c963035bf Mon Sep 17 00:00:00 2001 From: "Kyle Capehart (Huntersville)" Date: Tue, 26 Mar 2024 16:00:08 -0400 Subject: [PATCH] unstructured query and sobject insert --- salesforce/auth.go | 59 ++++++++++++++++++++++++ salesforce/salesforce.go | 99 ++++++++++++++++++++++------------------ 2 files changed, 113 insertions(+), 45 deletions(-) create mode 100644 salesforce/auth.go diff --git a/salesforce/auth.go b/salesforce/auth.go new file mode 100644 index 0000000..e5d5dad --- /dev/null +++ b/salesforce/auth.go @@ -0,0 +1,59 @@ +package salesforce + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + "net/url" + "strings" +) + +type Auth struct { + AccessToken string `json:"access_token"` + InstanceUrl string `json:"instance_url"` + Id string `json:"id"` + IssuedAt string `json:"issued_at"` + Signature string `json:"signature"` +} + +func loginPassword(domain string, username string, password string, securityToken string, consumerKey string, consumerSecret string) *Auth { + payload := url.Values{ + "grant_type": {"password"}, + "client_id": {consumerKey}, + "client_secret": {consumerSecret}, + "username": {username}, + "password": {password + securityToken}, + } + endpoint := "/services/oauth2/token" + body := strings.NewReader(payload.Encode()) + resp, err := http.Post(domain+endpoint, "application/x-www-form-urlencoded", body) + if err != nil { + fmt.Println("Error logging in") + fmt.Println(err.Error()) + return nil + } + if resp.StatusCode != http.StatusOK { + fmt.Println("Error with " + resp.Request.Method + " " + endpoint) + fmt.Println(resp.Status) + return nil + } + + respBody, err := io.ReadAll(resp.Body) + if err != nil { + fmt.Println("Error reading response") + fmt.Println(err.Error()) + return nil + } + + auth := &Auth{} + jsonError := json.Unmarshal(respBody, &auth) + if jsonError != nil { + fmt.Println("Error decoding response") + fmt.Println(jsonError.Error()) + return nil + } + + defer resp.Body.Close() + return auth +} diff --git a/salesforce/salesforce.go b/salesforce/salesforce.go index d238817..a8f19c3 100644 --- a/salesforce/salesforce.go +++ b/salesforce/salesforce.go @@ -9,42 +9,54 @@ import ( "strings" ) -type Auth struct { - AccessToken string `json:"access_token"` - InstanceUrl string `json:"instance_url"` - Id string `json:"id"` - IssuedAt string `json:"issued_at"` - Signature string `json:"signature"` -} +const API_VERSION = "v60.0" -type SObject struct { - Id string +type Attributes struct { + Type string `json:"type"` + Url string `json:"url"` } type QueryResponse struct { - Done bool `json:"done"` - NextRecordsURL string `json:"nextRecordsUrl"` - SObjects []SObject `json:"records"` - TotalSize int `json:"totalSize"` + TotalSize int `json:"totalSize"` + Done bool `json:"done"` + Records []map[string]any `json:"records"` } type Salesforce struct { auth *Auth } +type SObject struct { + SObjectName string + Fields map[string]string +} + func Init(domain string, username string, password string, securityToken string, consumerKey string, consumerSecret string) *Salesforce { - payload := url.Values{ - "grant_type": {"password"}, - "client_id": {consumerKey}, - "client_secret": {consumerSecret}, - "username": {username}, - "password": {password + securityToken}, + auth := loginPassword(domain, username, password, securityToken, consumerKey, consumerSecret) + return &Salesforce{auth: auth} +} + +func (sf *Salesforce) QueryUnstructured(query string) *QueryResponse { + if sf.auth == nil { + fmt.Println("Not authenticated. Please use salesforce.Init().") + return nil } - endpoint := "/services/oauth2/token" - body := strings.NewReader(payload.Encode()) - resp, err := http.Post(domain+endpoint, "application/x-www-form-urlencoded", body) + query = url.QueryEscape(query) + endpoint := sf.auth.InstanceUrl + "/services/data/" + API_VERSION + "/query/?q=" + query + req, err := http.NewRequest("GET", endpoint, nil) if err != nil { - fmt.Println("Error logging in") + fmt.Println("Error creating request") + fmt.Println(err.Error()) + return nil + } + + req.Header.Set("User-Agent", "go-salesforce") + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Accept", "application/json") + req.Header.Set("Authorization", "Bearer "+sf.auth.AccessToken) + resp, err := http.DefaultClient.Do(req) + if err != nil { + fmt.Println("Error authenticating") fmt.Println(err.Error()) return nil } @@ -61,8 +73,8 @@ func Init(domain string, username string, password string, securityToken string, return nil } - sf := &Salesforce{} - jsonError := json.Unmarshal(respBody, &sf.auth) + queryResponse := &QueryResponse{} + jsonError := json.Unmarshal(respBody, &queryResponse) if jsonError != nil { fmt.Println("Error decoding response") fmt.Println(jsonError.Error()) @@ -70,21 +82,27 @@ func Init(domain string, username string, password string, securityToken string, } defer resp.Body.Close() - return sf + return queryResponse } -func (sf *Salesforce) Query(query string) []byte { +func (sf *Salesforce) Insert(sObject SObject) { if sf.auth == nil { fmt.Println("Not authenticated. Please use salesforce.Init().") - return nil + return } - query = url.QueryEscape(query) - endpoint := sf.auth.InstanceUrl + "/services/data/v60.0/query/?q=" + query - req, err := http.NewRequest("GET", endpoint, nil) + json, err := json.Marshal(sObject.Fields) + body := strings.NewReader(string(json)) + if err != nil { + fmt.Println("Error converting object to json") + fmt.Println(err.Error()) + return + } + endpoint := sf.auth.InstanceUrl + "/services/data/" + API_VERSION + "/sobjects/" + sObject.SObjectName + req, err := http.NewRequest("POST", endpoint, body) if err != nil { fmt.Println("Error creating request") fmt.Println(err.Error()) - return nil + return } req.Header.Set("User-Agent", "go-salesforce") @@ -93,22 +111,13 @@ func (sf *Salesforce) Query(query string) []byte { req.Header.Set("Authorization", "Bearer "+sf.auth.AccessToken) resp, err := http.DefaultClient.Do(req) if err != nil { - fmt.Println("Error logging in") + fmt.Println("Error with DML operation") fmt.Println(err.Error()) - return nil + return } - if resp.StatusCode != http.StatusOK { + if resp.StatusCode != http.StatusCreated { fmt.Println("Error with " + resp.Request.Method + " " + endpoint) fmt.Println(resp.Status) - return nil - } - - respBody, err := io.ReadAll(resp.Body) - if err != nil { - fmt.Println("Error reading response") - fmt.Println(err.Error()) - return nil + return } - defer resp.Body.Close() - return respBody }