How to query Salesforce APIs in Go
Interacting with the Salesforce APIs can be tricky if your favorite language doesn’t have modules or packages available to handle the complexity. Of course, you can build one from scratch. However, chances you’ll hit a couple of roadblocks along the way.
A couple of weeks ago, I started working on a package to interact with the Salesforce APIs in Go, currently available on Github. My main motivations were to use it for my personal projects, to leverage existing packages such as golang.org/x/oauth2 (since all the other packages seem to rebuild this part of the logic) and to improve my understanding of both the Salesforce APIs and Go.
Here’s a quick example on how to execute an SOQL query using the package.
First of, you will have to create an http client implementing the OAuth2 specification. To achieve this, github.com/jpmonette/force is leveraging the oauth2 package built by Google.
conf := &oauth2.Config{
ClientID: "CLIENT-ID",
ClientSecret: "CLIENT-SECRET",
Endpoint: oauth2.Endpoint{
TokenURL: "TOKEN-URL",
},
}
token, \_ := conf.PasswordCredentialsToken(oauth2.NoContext, "USERNAME", "PASSWORD")
instanceUrl, \_ := token.Extra("instance_url").(string)
client := conf.Client(oauth2.NoContext, token)Here are the steps to obtain a functional http client:
- Instantiating an
oauth2.Configrequired to query anaccess_tokenfrom Salesforce - details are provided when configuring a Connected App; - Requesting an
access_tokenusing the Username-Password OAuth Flow; - Storing the
instance_urlfrom the reponse, required by thegithub.com/jpmonette/forcepackage to query the correct instance; - Generating a http client implementing the OAuth2 specification.
Now that we have a functional http client, here’s how to use it with the force package:
c, \_ := force.NewClient(client, instanceUrl)
var data QueryReponse
c.Query("SELECT Id, Name FROM Account LIMIT 10", &data)
fmt.Println("Total size: "+data.TotalSize)
fmt.Println("First ID: "+data.Records[0].Id)In the previous snippet, we are:
- Generating a
forceclient; - Creating a
datavariable using the typeQueryReponse(defined later) - Executing an SOQL query using the
func (c *Client) Query(query string, v interface{}) (err error)function; - Printing the amount of records returned;
- Printing the Id of the first record found.
At last, you have to define the QueryReponse struct:
type QueryReponse struct {
TotalSize int `json:"totalSize"`
Records []struct {
ID string `json:"Id"`
Name string `json:"Name"`
Attributes struct {
Type string `json:"type"`
URL string `json:"url"`
} `json:"attributes"`
} `json:"records"`
}Now, here’s the whole example:
package main
import (
"os"
"fmt"
"github.com/jpmonette/force"
"golang.org/x/oauth2"
)
func main() {
conf := &oauth2.Config{
ClientID: os.Getenv("SFCLIENTID"),
ClientSecret: os.Getenv("SFCLIENTSECRET"),
Endpoint: oauth2.Endpoint{
TokenURL: os.Getenv("SFTOKENURL"),
},
}
token, _ := conf.PasswordCredentialsToken(oauth2.NoContext, os.Getenv("SFUSERNAME"), os.Getenv("SFPASSWORD"))
instanceUrl, _ := token.Extra("instance_url").(string)
client := conf.Client(oauth2.NoContext, token)
c, _ := force.NewClient(client, instanceUrl)
var data QueryReponse
c.Query("SELECT Id, Name FROM Account LIMIT 10", &data)
fmt.Println("Total size: " + data.TotalSize)
fmt.Println("First ID: " + data.Records[0].Id)
}
// QueryReponse is used to Unmarshal the SOQL query response
type QueryReponse struct {
TotalSize int `json:"totalSize"`
Records []struct {
ID string `json:"Id"`
Name string `json:"Name"`
Attributes struct {
Type string `json:"type"`
URL string `json:"url"`
} `json:"attributes"`
} `json:"records"`
}Now - if you go get github.com/jpmonette/force and go run main.go, the console should output something similar to:
~ » go run main.go
Total size: 10
First ID: 001b000002T9ak4Notes: For simplicity, error checking has been omitted in the example.
Please note that this package is inspired by the go-github package. Since it is a work in progress, you are more than welcomed to send pull requests to support additional features.