Introduction
⚡️ SharePoint authentication, HTTP client & fluent API wrapper for Go (Golang)

Main features

  • Unattended authentication using different strategies.
  • Fluent API syntax for SharePoint object model.
  • Simplified API consumption (REST, CSOM, SOAP, etc.).
  • SharePoint-aware embedded features (retries, header presets, error handling).

Supported SharePoint versions

  • SharePoint Online (SPO).
  • On-Premises (2019/2016/2013).

Supported auth strategies

Installation

1
go get github.com/koltyakov/gosip
Copied!

Usage insights

Understand SharePoint environment type and authentication strategy

Let's assume it's SharePoint Online and Add-In Only permissions. Then strategy "github.com/koltyakov/gosip/auth/addin" sub package should be used.
1
package main
2
3
import (
4
"github.com/koltyakov/gosip"
5
"github.com/koltyakov/gosip/api"
6
strategy "github.com/koltyakov/gosip/auth/addin"
7
)
Copied!

Initiate authentication object

1
auth := &strategy.AuthCnfg{
2
SiteURL: os.Getenv("SPAUTH_SITEURL"),
3
ClientID: os.Getenv("SPAUTH_CLIENTID"),
4
ClientSecret: os.Getenv("SPAUTH_CLIENTSECRET"),
5
}
Copied!
AuthCnfg's from different strategies contains different options relevant for a specified auth type.
The authentication options can be provided explicitly or can be read from a configuration file (see more).
1
configPath := "./config/private.json"
2
auth := &strategy.AuthCnfg{}
3
4
err := auth.ReadConfig(configPath)
5
if err != nil {
6
fmt.Printf("Unable to get config: %v\n", err)
7
return
8
}
Copied!

Bind auth client with Fluent API

1
client := &gosip.SPClient{AuthCnfg: auth}
2
3
sp := api.NewSP(client)
4
5
res, err := sp.Web().Select("Title").Get()
6
if err != nil {
7
fmt.Println(err)
8
}
9
10
fmt.Printf("%s\n", res.Data().Title)
Copied!

Usage samples

Fluent API client

Provides a simple way of constructing API endpoint calls with IntelliSense and chainable syntax.
1
package main
2
3
import (
4
"encoding/json"
5
"fmt"
6
"log"
7
8
"github.com/koltyakov/gosip"
9
"github.com/koltyakov/gosip/api"
10
strategy "github.com/koltyakov/gosip/auth/addin"
11
)
12
13
func main() {
14
// Getting auth params and client
15
client, err := getAuthClient()
16
if err != nil {
17
log.Fatalln(err)
18
}
19
20
// Binding SharePoint API
21
sp := api.NewSP(client)
22
23
// Custom headers
24
headers := map[string]string{
25
"Accept": "application/json;odata=minimalmetadata",
26
"Accept-Language": "de-DE,de;q=0.9",
27
}
28
config := &api.RequestConfig{Headers: headers}
29
30
// Chainable request sample
31
data, err := sp.Conf(config).Web().Lists().Select("Id,Title").Get()
32
if err != nil {
33
log.Fatalln(err)
34
}
35
36
// Response object unmarshalling
37
// (struct depends on OData mode and API method)
38
res := &struct {
39
Value []struct {
40
ID string `json:"Id"`
41
Title string `json:"Title"`
42
} `json:"value"`
43
}{}
44
45
if err := json.Unmarshal(data, &res); err != nil {
46
log.Fatalf("unable to parse the response: %v", err)
47
}
48
49
for _, list := range res.Value {
50
fmt.Printf("%+v\n", list)
51
}
52
53
}
54
55
func getAuthClient() (*gosip.SPClient, error) {
56
configPath := "./config/private.spo-addin.json" // <- file with creds
57
auth := &strategy.AuthCnfg{}
58
if err := auth.ReadConfig(configPath); err != nil {
59
return nil, fmt.Errorf("unable to get config: %v", err)
60
}
61
return &gosip.SPClient{AuthCnfg: auth}, nil
62
}
Copied!

Generic HTTP-client helper

Provides generic GET/POST helpers for REST operations, reducing amount of http.NewRequest scaffolded code, can be used for custom or not covered with a Fluent API endpoints.
1
package main
2
3
import (
4
"fmt"
5
"log"
6
7
"github.com/koltyakov/gosip"
8
"github.com/koltyakov/gosip/api"
9
strategy "github.com/koltyakov/gosip/auth/ntlm"
10
)
11
12
func main() {
13
configPath := "./config/private.ntlm.json"
14
auth := &strategy.AuthCnfg{}
15
16
if err := auth.ReadConfig(configPath); err != nil {
17
log.Fatalf("unable to get config: %v\n", err)
18
}
19
20
sp := api.NewHTTPClient(&gosip.SPClient{AuthCnfg: auth})
21
22
endpoint := auth.GetSiteURL() + "/_api/web?$select=Title"
23
24
data, err := sp.Get(endpoint, nil)
25
if err != nil {
26
log.Fatalf("%v\n", err)
27
}
28
29
// sp.Post(endpoint, []byte(body), nil) // generic POST
30
31
// generic DELETE helper crafts "X-Http-Method"="DELETE" header
32
// sp.Delete(endpoint, nil)
33
34
// generic UPDATE helper crafts "X-Http-Method"="MERGE" header
35
// sp.Update(endpoint, nil)
36
37
// CSOM helper (client.svc/ProcessQuery)
38
// sp.ProcessQuery(endpoint, []byte(body))
39
40
fmt.Printf("response: %s\n", data)
41
}
Copied!

Low-level HTTP-client usage

Low-lever SharePoint-aware HTTP client from github.com/koltyakov/gosip package for custom or not covered with a Fluent API client endpoints with granular control for HTTP request, response, and http.Client parameters. Used internally but almost never required in a consumer code.
1
client := &gosip.SPClient{AuthCnfg: auth}
2
3
var req *http.Request
4
// Initiate API request
5
// ...
6
7
resp, err := client.Execute(req)
8
if err != nil {
9
fmt.Printf("Unable to request api: %v", err)
10
return
11
}
Copied!
SPClient has Execute method which is a wrapper function injecting SharePoint authentication and ending up calling http.Client's Do method.

Reference

Many auth flows have been "copied" from node-sp-auth library (used as a blueprint), which we intensively use in Node.js ecosystem for years.
Fluent API and wrapper syntax are inspired by PnPjs which is also the first-class citizen on almost all our Node.js and front-end projects with SharePoint involved.

License

Last modified 7mo ago