Golang google sheets API V4 - Write/Update example? - go

Trying to write a simple three column table ([][]string) with Go, but can't.
The quick start guide is very nice, I now can read sheets, but there no any example of how to write data to a sheet, maybe it is trivial, but not for me it seems.
The Golang library for my brains is just too complicated to figure out.
And there not a single example I could google...
This C# example very looks close, but I am not sure I clearly understand C#

Well after some tryouts, there is an answer. Everything is same as in https://developers.google.com/sheets/quickstart/go Just changes in the main function
func write() {
ctx := context.Background()
b, err := ioutil.ReadFile("./Google_Sheets_API_Quickstart/client_secret.json")
if err != nil {
log.Fatalf("Unable to read client secret file: %v", err)
}
// If modifying these scopes, delete your previously saved credentials
// at ~/.credentials/sheets.googleapis.com-go-quickstart.json
config, err := google.ConfigFromJSON(b, "https://www.googleapis.com/auth/spreadsheets")
if err != nil {
log.Fatalf("Unable to parse client secret file to config: %v", err)
}
client := getClient(ctx, config)
srv, err := sheets.New(client)
if err != nil {
log.Fatalf("Unable to retrieve Sheets Client %v", err)
}
spreadsheetId := "YOUR SPREADSHEET ID"
writeRange := "A1"
var vr sheets.ValueRange
myval := []interface{}{"One", "Two", "Three"}
vr.Values = append(vr.Values, myval)
_, err = srv.Spreadsheets.Values.Update(spreadsheetId, writeRange, &vr).ValueInputOption("RAW").Do()
if err != nil {
log.Fatalf("Unable to retrieve data from sheet. %v", err)
}
}

Well if you are looking for Service Account based authentication, then the following worked for me.
Download the client secret file for service account from https://console.developers.google.com
import (
"fmt"
"golang.org/x/net/context"
"google.golang.org/api/option"
"google.golang.org/api/sheets/v4"
"log"
)
const (
client_secret_path = "./credentials/client_secret.json"
)
func NewSpreadsheetService() (*SpreadsheetService, error) {
// Service account based oauth2 two legged integration
ctx := context.Background()
srv, err := sheets.NewService(ctx, option.WithCredentialsFile(client_secret_path), option.WithScopes(sheets.SpreadsheetsScope))
if err != nil {
log.Fatalf("Unable to retrieve Sheets Client %v", err)
}
c := &SpreadsheetService{
service: srv,
}
return c, nil
}
func (s *SpreadsheetService) WriteToSpreadsheet(object *SpreadsheetPushRequest) error {
var vr sheets.ValueRange
vr.Values = append(vr.Values, object.Values)
res, err := s.service.Spreadsheets.Values.Append(object.SpreadsheetId, object.Range, &vr).ValueInputOption("RAW").Do()
fmt.Println("spreadsheet push ", res)
if err != nil {
fmt.Println("Unable to update data to sheet ", err)
}
return err
}
type SpreadsheetPushRequest struct {
SpreadsheetId string `json:"spreadsheet_id"`
Range string `json:"range"`
Values []interface{} `json:"values"`
}

change the scope in the quickstart example from spreadsheets.readonly to spreadsheets for r/w access
here is the write snippet:
writeRange := "A1" // or "sheet1:A1" if you have a different sheet
values := []interface{}{"It worked!"}
var vr sheets.ValueRange
vr.Values = append(vr.Values,values
_, err = srv.Spreadsheets.Values.Update(spreadsheetId,writeRange,&vr).ValueInputOption("RAW").Do()
and that should work:

Related

Go googleapis/google-api-go-client gmail, blank response on some requests?

func Callback(w http.ResponseWriter, r *http.Request){
ctx := context.Background()
state := r.FormValue("state")
code := r.FormValue("code")
client := getClient(state, code)
srv, err := gmail.NewService(ctx, option.WithHTTPClient(client))
if err != nil {
log.Fatalf("Unable to retrieve Gmail client: %v", err)
}
user := "me"
result, err := srv.Users.Messages.List(user).Do()
// result, err := srv.Users.GetProfile(user).Do() // This part works
if err != nil {
log.Fatalf("Unable to retrieve labels: %v", err)
}
// fmt.Fprintf(w, "Labels: %s", result.EmailAddress) // This part works
snippet := result.Messages[0].Snippet
fmt.Fprint(w, string(snippet)) // For some reason give a blank output
}
Gmail API Go Client
Some parts like the snippet and the body do print out an output.
But the profile and listing of labels works.
I'm not sure what I'm doing incorrectly :(

Share Google Doc via Golang SDK

I am using service account JSON to create google Doc via Golang SDK but as this doc is only accessible to Service account I am not able to access it with my Personal Google Account. In the Google Doc SDK documentation I couldn't find any function to share the Doc.
This is my sample Code:
package googledoc
import (
"context"
"fmt"
log "github.com/sirupsen/logrus"
"golang.org/x/oauth2/google"
"google.golang.org/api/docs/v1"
"google.golang.org/api/option"
func CreateDoc(title string) error {
ctx := context.Background()
cred, err := GetSecrets("ap-south-1", "GOOGLE_SVC_ACC_JSON")
if err != nil {
return fmt.Errorf("unable to get the SSM %v", err)
}
config, err := google.JWTConfigFromJSON(cred, docs.DocumentsScope)
if err != nil {
log.Fatalf("Unable to parse client secret file to config: %v", err)
}
client := config.Client(ctx)
srv, err := docs.NewService(ctx, option.WithHTTPClient(client))
if err != nil {
log.Fatalf("Unable to retrieve Docs client: %v", err)
}
docObj := docs.Document{
Title: title,
}
doc, err := srv.Documents.Create(&docObj).Do()
if err != nil {
log.Fatalf("Unable to retrieve data from document: %v", err)
return err
}
fmt.Printf("The title of the doc is: %s %s\n", doc.Title, doc.DocumentId)
return nil
}
Any help with this would be really appreciated Thanks.
I believe your goal is as follows.
You want to share the created Google Document by the service account with your Google account.
You want to achieve this using googleapis for golang.
Unfortunately, Google Docs API cannot be used for sharing the Document with users. In this case, Drive API is used. When your script is modified using Drive API, how about the following modification?
Sample script:
Please add this script just after the line of fmt.Printf("The title of the doc is: %s %s\n", doc.Title, doc.DocumentId). By this, the created Google Document is shared with the user.
driveSrv, err := drive.NewService(ctx, option.WithHTTPClient(client)) // Please use your client and service for using Drive API.
if err != nil {
log.Fatal(err)
}
permission := &drive.Permission{
EmailAddress: "###", // Please set the email address you want to share.
Role: "writer",
Type: "user",
}
res, err := driveSrv.Permissions.Create(doc.DocumentId, permission).Do()
if err != nil {
log.Fatal(err)
return err
}
fmt.Println(res)
When this script is added to your script, the created Document is shared with the user as the writer.
Reference:
Permissions: create

Unauthorized when using gocosmos to create a document

I got go-sql-driver for Azure CosmosDB from https://github.com/btnguyen2k/gocosmos.
It goes well when i call gocosmos.NewRestClient to get a rest client, CreateDatabase() to create database and CreateCollection() to create collection.
The problem is when i use CreateDocument(), i get response with statuscode 401 and body like this
{"code":"Unauthorized","message":"The input authorization token can't serve the request. Please check that the expected payload is built as per the protocol, and check the key being used. Server used the following payload to sign: 'post\ndocs\ndbs/ToDoList/colls/Items\nmon, 31 may 2021 13:31:44 gmt\n\n'\r\nActivityId: a9bbd729-3495-400f-9d79-ddec3737aa92, Microsoft.Azure.Documents.Common/2.11.0"}
i've tried all the solutions I've seen, but i haven't solved the problem.
I followed this tutorial and with this sample code, I can successfully create database, collection and document. Here's my testing result, can it help you?
// connects to MongoDB
func connect() *mongo.Client {
mongoDBConnectionString := os.Getenv(mongoDBConnectionStringEnvVarName)
if mongoDBConnectionString == "" {
log.Fatal("missing environment variable: ", mongoDBConnectionStringEnvVarName)
}
database = os.Getenv(mongoDBDatabaseEnvVarName)
if database == "" {
log.Fatal("missing environment variable: ", mongoDBDatabaseEnvVarName)
}
collection = os.Getenv(mongoDBCollectionEnvVarName)
if collection == "" {
log.Fatal("missing environment variable: ", mongoDBCollectionEnvVarName)
}
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
defer cancel()
clientOptions := options.Client().ApplyURI(mongoDBConnectionString).SetDirect(true)
c, err := mongo.NewClient(clientOptions)
err = c.Connect(ctx)
if err != nil {
log.Fatalf("unable to initialize connection %v", err)
}
err = c.Ping(ctx, nil)
if err != nil {
log.Fatalf("unable to connect %v", err)
}
return c
}
// creates a todo
func create(desc string) {
c := connect()
ctx := context.Background()
defer c.Disconnect(ctx)
todoCollection := c.Database(database).Collection(collection)
r, err := todoCollection.InsertOne(ctx, Todo{Description: desc, Status: statusPending})
if err != nil {
log.Fatalf("failed to add todo %v", err)
}
fmt.Println("added todo", r.InsertedID)
}

how to edit an existing data in cloud storage of GCP using an api in golang

I am creating an application which is communicating with google datastore, to fetch the existing data, and perform add, edit and delete operations on that existing data. I am able to fetch the existing data, and delete the data there. But not getting how to edit/update the data there through api in golang.
Giving the code snippet which I am trying to execute for this :
func EditCustomer(w http.ResponseWriter, r *http.Request){
ctx := context.Background()
params := mux.Vars(r)
customer_id :=params["partner_id"]
projectID := util.MustGetenv("GOOGLE_CLOUD_PROJECT")
client, err := datastore.NewClient(ctx, projectID)
if err != nil {
log.Fatalf("Failed to create client: %v", err)
}
var customer models.Customer
kind := util.MustGetenv("DATA_STORE_KIND")
ds.EditCustomer(client,kind,customer_id,&customer,ctx)
json.NewEncoder(w).Encode(customer)
}
EditCustomer method in dao is as :
func EditCustomer(client *datastore.Client,kind string ,name string,dst interface{},ctx context.Context) {
taskKey := datastore.NameKey(kind, name, nil)
< some methos here to edit and update itin datstorage >
}
Please advise for this. Anybody there who working with api's dev in golang ?
I would update like this:
currentCustomer := &Customer{}
_, err := client.RunInTransaction(ctx, func(tx *datastore.Transaction) error {
if getErr := tx.Get(key, currentCustomer); getErr != nil {
return getErr
}
// edit your object
var putErr error
_, putErr = tx.Put(key, updatedCustomer)
return putErr
})
if err != nil {
return nil, err
}
_, err = client.Put(ctx, key, customer)

Google Sheets API: golang BatchUpdateValuesRequest

I'm trying to follow the Google Sheets API quickstart here:
https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets.values/batchUpdate
(scroll down to "Examples" then click "GO")
This is how I tried to update a spreadsheet:
package main
// BEFORE RUNNING:
// ---------------
// 1. If not already done, enable the Google Sheets API
// and check the quota for your project at
// https://console.developers.google.com/apis/api/sheets
// 2. Install and update the Go dependencies by running `go get -u` in the
// project directory.
import (
"errors"
"fmt"
"log"
"net/http"
"golang.org/x/net/context"
"google.golang.org/api/sheets/v4"
)
func main() {
ctx := context.Background()
c, err := getClient(ctx)
if err != nil {
log.Fatal(err)
}
sheetsService, err := sheets.New(c)
if err != nil {
log.Fatal(err)
}
// The ID of the spreadsheet to update.
spreadsheetId := "1diQ943LGMDNkbCRGG4VqgKZdzyanCtT--V8o7r6kCR0"
var jsonPayloadVar []string
monthVar := "Apr"
thisCellVar := "A26"
thisLinkVar := "http://test.url"
jsonRackNumberVar := "\"RACKNUM01\""
jsonPayloadVar = append(jsonPayloadVar, fmt.Sprintf("(\"range\": \"%v!%v\", \"values\": [[\"%v,%v)\"]]),", monthVar, thisCellVar, thisLinkVar, jsonRackNumberVar))
rb := &sheets.BatchUpdateValuesRequest{"ValueInputOption": "USER_ENTERED", "data": jsonPayloadVar}
resp, err := sheetsService.Spreadsheets.Values.BatchUpdate(spreadsheetId, rb).Context(ctx).Do()
if err != nil {
log.Fatal(err)
}
fmt.Printf("%#v\n", resp)
}
func getClient(ctx context.Context) (*http.Client, error) {
// https://developers.google.com/sheets/quickstart/go#step_3_set_up_the_sample
//
// Authorize using the following scopes:
// sheets.DriveScope
// sheets.DriveFileScope
sheets.SpreadsheetsScope
return nil, errors.New("not implemented")
}
Output:
hello.go:43: invalid field name "ValueInputOption" in struct initializer
hello.go:43: invalid field name "data" in struct initializer
hello.go:58: sheets.SpreadsheetsScope evaluated but not used
There are 2 things that aren't working:
It's not obvious how to enter the fields into variable rb
I need to use sheets.SpreadsheetsScope
Can anyone provide a working example that does a BatchUpdate?
References:
This article shows how to do an update that is not a BatchUpdate: Golang google sheets API V4 - Write/Update example?
Google's API reference - see the ValueInputOption section starting at line 1437: https://github.com/google/google-api-go-client/blob/master/sheets/v4/sheets-gen.go
This article shows how to do a BatchUpdate in Java: Write data to Google Sheet using Google Sheet API V4 - Java Sample Code
How about the following sample script? This is a simple sample script for updating sheet on Spreadsheet. So if you want to do various update, please modify it. The detail of parameters for spreadsheets.values.batchUpdate is here.
Flow :
At first, in ordet to use the link in your question, please use Go Quickstart. In my sample script, the script was made using the Quickstart.
The flow to use this sample script is as follows.
For Go Quickstart, please do Step 1 and Step 2.
Please put client_secret.json to the same directory with my sample script.
Copy and paste my sample script, and create it as new script file.
Run the script.
When Go to the following link in your browser then type the authorization code: is shown on your terminal, please copy the URL and paste to your browser. And then, please authorize and get code.
Put the code to the terminal.
When Done. is displayed, it means that the update of spreadsheet is done.
Request body :
For Spreadsheets.Values.BatchUpdate, BatchUpdateValuesRequest is required as one of parameters. In this case, the range, values and so on that you want to update are included in BatchUpdateValuesRequest. The detail information of this BatchUpdateValuesRequest can be seen at godoc. When it sees BatchUpdateValuesRequest, Data []*ValueRange can be seen. Here, please be carefull that Data is []*ValueRange. Also ValueRange can be seen at godoc. You can see MajorDimension, Range and Values in ValueRange.
When above infomation is reflected to the script, the script can be modified as follows.
Sample script :
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"golang.org/x/net/context"
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
"google.golang.org/api/sheets/v4"
)
// getClient uses a Context and Config to retrieve a Token
// then generate a Client. It returns the generated Client.
func getClient(ctx context.Context, config *oauth2.Config) *http.Client {
cacheFile := "./go-quickstart.json"
tok, err := tokenFromFile(cacheFile)
if err != nil {
tok = getTokenFromWeb(config)
saveToken(cacheFile, tok)
}
return config.Client(ctx, tok)
}
// getTokenFromWeb uses Config to request a Token.
// It returns the retrieved Token.
func getTokenFromWeb(config *oauth2.Config) *oauth2.Token {
authURL := config.AuthCodeURL("state-token", oauth2.AccessTypeOffline)
fmt.Printf("Go to the following link in your browser then type the "+
"authorization code: \n%v\n", authURL)
var code string
if _, err := fmt.Scan(&code); err != nil {
log.Fatalf("Unable to read authorization code %v", err)
}
tok, err := config.Exchange(oauth2.NoContext, code)
if err != nil {
log.Fatalf("Unable to retrieve token from web %v", err)
}
return tok
}
// tokenFromFile retrieves a Token from a given file path.
// It returns the retrieved Token and any read error encountered.
func tokenFromFile(file string) (*oauth2.Token, error) {
f, err := os.Open(file)
if err != nil {
return nil, err
}
t := &oauth2.Token{}
err = json.NewDecoder(f).Decode(t)
defer f.Close()
return t, err
}
func saveToken(file string, token *oauth2.Token) {
fmt.Printf("Saving credential file to: %s\n", file)
f, err := os.Create(file)
if err != nil {
log.Fatalf("Unable to cache oauth token: %v", err)
}
defer f.Close()
json.NewEncoder(f).Encode(token)
}
type body struct {
Data struct {
Range string `json:"range"`
Values [][]string `json:"values"`
} `json:"data"`
ValueInputOption string `json:"valueInputOption"`
}
func main() {
ctx := context.Background()
b, err := ioutil.ReadFile("client_secret.json")
if err != nil {
log.Fatalf("Unable to read client secret file: %v", err)
}
config, err := google.ConfigFromJSON(b, "https://www.googleapis.com/auth/spreadsheets")
if err != nil {
log.Fatalf("Unable to parse client secret file to config: %v", err)
}
client := getClient(ctx, config)
sheetsService, err := sheets.New(client)
if err != nil {
log.Fatalf("Unable to retrieve Sheets Client %v", err)
}
spreadsheetId := "### spreadsheet ID ###"
rangeData := "sheet1!A1:B3"
values := [][]interface{}{{"sample_A1", "sample_B1"}, {"sample_A2", "sample_B2"}, {"sample_A3", "sample_A3"}}
rb := &sheets.BatchUpdateValuesRequest{
ValueInputOption: "USER_ENTERED",
}
rb.Data = append(rb.Data, &sheets.ValueRange{
Range: rangeData,
Values: values,
})
_, err = sheetsService.Spreadsheets.Values.BatchUpdate(spreadsheetId, rb).Context(ctx).Do()
if err != nil {
log.Fatal(err)
}
fmt.Println("Done.")
}
Result :
References :
The detail infomation of spreadsheets.values.batchUpdate is here.
The detail infomation of Go Quickstart is here.
The detail infomation of BatchUpdateValuesRequest is here.
The detail infomation of ValueRange is here.
If I misunderstand your question, I'm sorry.

Resources