markdown

はじめに (対象読者・この記事でわかること)

この記事は、Go言語を使ってGoogle Drive APIを操作したい方、特に共有ドライブの設定を一括で変更したい方を対象にしています。 この記事を読むことで、Go言語からGoogle Drive API v3を使用して共有ドライブの各種設定(名前、制限事項、色など)をプログラムから変更する方法がわかります。 また、OAuth認証の設定方法やAPIの呼び出し方、エラーハンドリングの実装方法も学べます。

前提知識

この記事を読み進める上で、以下の知識があるとスムーズです。 - Go言語の基本的な文法 - Google Cloud Consoleの基本的な操作 - REST APIの基礎知識

Google Drive APIと共有ドライブの基礎

Google Drive API v3は、Googleドライブのファイルやフォルダ、共有ドライブをプログラムから操作できる強力なAPIです。 共有ドライブは、チーム全体で所有するファイルを管理するための機能で、個人のマイドライブとは異なり、メンバーが退職してもファイルが残るという特徴があります。

GUI上では「共有ドライブの設定」から変更できる項目には以下のものがあります: - 共有ドライブの名前 - 背景色の変更 - メンバーの追加・削除 - 各メンバーのロール設定(管理者、コンテンツ管理者、コントリビューターなど) - 共有ドライブの制限設定(外部ユーザーのアクセス制限、共有設定の制限など)

これらの設定をプログラムから自動化することで、大規模な組織でのドライブ管理を効率化できます。

Go言語で共有ドライブの設定を変更する実装

それでは、実際にGo言語で共有ドライブの設定を変更する方法を見ていきましょう。

プロジェクトのセットアップと認証設定

まず、Google Cloud Consoleでプロジェクトを作成し、Google Drive APIを有効化します。

Bash
mkdir go-drive-manager cd go-drive-manager go mod init github.com/yourname/go-drive-manager

必要なパッケージをインストールします:

Bash
go get google.golang.org/api/drive/v3 go get golang.org/x/oauth2/google

次に、サービスアカウントを作成します: 1. Google Cloud Console → IAMと管理 → サービスアカウント 2. 「サービスアカウントを作成」をクリック 3. 適切な名前と説明を入力 4. ロールとして「Google Drive API管理者」を付与 5. JSONキーを作成してダウンロード

基本的な認証とクライアント作成

以下のコードで、認証情報を読み込み、Drive APIクライアントを作成します:

Go
package main import ( "context" "encoding/json" "fmt" "log" "os" "golang.org/x/oauth2" "golang.org/x/oauth2/google" "google.golang.org/api/drive/v3" "google.golang.org/api/option" ) type Config struct { ServiceAccountFile string `json:"service_account_file"` DelegatedUser string `json:"delegated_user"` SharedDriveID string `json:"shared_drive_id"` } func loadConfig(filename string) (*Config, error) { file, err := os.Open(filename) if err != nil { return nil, err } defer file.Close() var config Config decoder := json.NewDecoder(file) err = decoder.Decode(&config) if err != nil { return nil, err } return &config, nil } func createDriveService(ctx context.Context, config *Config) (*drive.Service, error) { credentials, err := os.ReadFile(config.ServiceAccountFile) if err != nil { return nil, fmt.Errorf("unable to read service account file: %v", err) } conf, err := google.JWTConfigFromJSON( credentials, drive.DriveScope, ) if err != nil { return nil, fmt.Errorf("unable to parse service account file: %v", err) } // 委任されたユーザーを設定 conf.Subject = config.DelegatedUser client := conf.Client(ctx) srv, err := drive.NewService(ctx, option.WithHTTPClient(client)) if err != nil { return nil, fmt.Errorf("unable to create Drive service: %v", err) } return srv, nil }

共有ドライブの基本情報を更新

共有ドライブの名前や背景色を変更するコードです:

Go
func updateSharedDriveInfo(srv *drive.Service, driveID string, newName string, colorRgb string) error { driveResource := &drive.Drive{ Name: newName, ColorRgb: colorRgb, } updatedDrive, err := srv.Drives.Update(driveID, driveResource).Do() if err != nil { return fmt.Errorf("unable to update shared drive: %v", err) } fmt.Printf("Successfully updated shared drive: %s (ID: %s)\n", updatedDrive.Name, updatedDrive.Id) return nil } func main() { ctx := context.Background() config, err := loadConfig("config.json") if err != nil { log.Fatalf("Unable to load config: %v", err) } srv, err := createDriveService(ctx, config) if err != nil { log.Fatalf("Unable to create Drive service: %v", err) } // 共有ドライブの名前と色を更新 err = updateSharedDriveInfo(srv, config.SharedDriveID, "新しいプロジェクトドライブ", "#4285F4") if err != nil { log.Fatalf("Unable to update shared drive info: %v", err) } }

メンバーの権限を一括変更

共有ドライブ内のメンバーのロールを一括で変更する例です:

Go
type MemberUpdate struct { Email string Role string } func updateMemberRoles(srv *drive.Service, driveID string, updates []MemberUpdate) error { // 共有ドライブの全ての権限を取得 permissionsList, err := srv.Permissions.List(driveID). Fields("permissions(id,emailAddress,role)"). Do() if err != nil { return fmt.Errorf("unable to list permissions: %v", err) } // メールアドレスをキーとしたマップを作成 permissionMap := make(map[string]string) for _, perm := range permissionsList.Permissions { if perm.EmailAddress != "" { permissionMap[perm.EmailAddress] = perm.Id } } // 各メンバーの権限を更新 for _, update := range updates { permissionID, exists := permissionMap[update.Email] if !exists { fmt.Printf("Warning: %s is not a member of this shared drive\n", update.Email) continue } permission := &drive.Permission{ Role: update.Role, } _, err := srv.Permissions.Update(driveID, permissionID, permission). Fields("id,role,emailAddress"). Do() if err != nil { fmt.Printf("Error updating permission for %s: %v\n", update.Email, err) continue } fmt.Printf("Updated role for %s to %s\n", update.Email, update.Role) } return nil } func main() { // 省略: 初期化処理 // メンバーの権限を一括更新 updates := []MemberUpdate{ {"tanaka@example.com", "organizer"}, {"sato@example.com", "fileOrganizer"}, {"suzuki@example.com", "writer"}, } err = updateMemberRoles(srv, config.SharedDriveID, updates) if err != nil { log.Fatalf("Unable to update member roles: %v", err) } }

共有ドライブの制限設定を変更

外部共有の制限やドメイン制限などの設定を変更します:

Go
type DriveRestrictions struct { DomainUsersOnly bool DriveMembersOnly bool AdminManagedRestrictions bool CopyRequiresWriterPermission bool } func updateDriveRestrictions(srv *drive.Service, driveID string, restrictions DriveRestrictions) error { driveResource := &drive.Drive{ Restrictions: &drive.DriveRestrictions{ DomainUsersOnly: restrictions.DomainUsersOnly, DriveMembersOnly: restrictions.DriveMembersOnly, AdminManagedRestrictions: restrictions.AdminManagedRestrictions, CopyRequiresWriterPermission: restrictions.CopyRequiresWriterPermission, }, } updatedDrive, err := srv.Drives.Update(driveID, driveResource). Fields("id,name,restrictions"). Do() if err != nil { return fmt.Errorf("unable to update drive restrictions: %v", err) } fmt.Printf("Updated restrictions for drive %s:\n", updatedDrive.Name) fmt.Printf(" Domain users only: %t\n", updatedDrive.Restrictions.DomainUsersOnly) fmt.Printf(" Drive members only: %t\n", updatedDrive.Restrictions.DriveMembersOnly) return nil }

ハマった点やエラー解決

実装中に遭遇する代表的なエラーとその解決方法です:

1. 「Insufficient permissions」エラー

エラーメッセージ:

googleapi: Error 403: The user does not have sufficient permissions for this shared drive., insufficientPermissions

原因と解決策: このエラーは、サービスアカウントに適切な権限が付与されていないか、委任されたユーザーが共有ドライブの管理者でない場合に発生します。

  1. Google Cloud Consoleで、サービスアカウントに「Google Drive API管理者」ロールを付与
  2. 委任されたユーザー(config.jsonのdelegated_user)が共有ドライブの管理者であることを確認

2. 「File not found」エラー

エラーメッセージ:

googleapi: Error 404: Shared drive not found: XXXXXXXXXXXXX, notFound

原因と解決策: 共有ドライブIDが間違っているか、アクセス権限がありません。

Go
// 正しいドライブIDを取得する関数 func listSharedDrives(srv *drive.Service) error { drivesList, err := srv.Drives.List().PageSize(10).Do() if err != nil { return fmt.Errorf("unable to list drives: %v", err) } fmt.Println("Available shared drives:") for _, drive := range drivesList.Drives { fmt.Printf(" Name: %s, ID: %s\n", drive.Name, drive.Id) } return nil }

3. 「Rate limit exceeded」エラー

エラーメッセージ:

googleapi: Error 429: Rate limit exceeded, rateLimitExceeded

原因と解決策: APIの呼び出し回数が制限を超えています。バッチ処理やリトライロジックを実装します:

Go
import ( "time" "google.golang.org/api/googleapi" ) func executeWithRetry(fn func() error) error { const maxRetries = 3 const baseDelay = 1 * time.Second for i := 0; i < maxRetries; i++ { err := fn() if err == nil { return nil } // レート制限エラーの場合は待機してリトライ if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 429 { delay := baseDelay * time.Duration(i+1) time.Sleep(delay) continue } return err } return fmt.Errorf("max retries exceeded") }

完全な実装例

以下は、共有ドライブの設定を一括変更する完全な実装例です:

Go
package main import ( "context" "encoding/json" "fmt" "log" "os" "time" "golang.org/x/oauth2" "golang.org/x/oauth2/google" "google.golang.org/api/drive/v3" "google.golang.org/api/googleapi" "google.golang.org/api/option" ) type DriveConfig struct { Name string `json:"name"` ColorRgb string `json:"color_rgb"` Description string `json:"description"` } type BatchUpdateRequest struct { DriveID string `json:"drive_id"` DriveConfig DriveConfig `json:"drive_config"` MemberRoles []MemberUpdate `json:"member_roles"` Restrictions DriveRestrictions `json:"restrictions"` } func batchUpdateSharedDrive(srv *drive.Service, request BatchUpdateRequest) error { // 1. ドライブ基本情報の更新 if request.DriveConfig.Name != "" { err := executeWithRetry(func() error { return updateSharedDriveInfo(srv, request.DriveID, request.DriveConfig.Name, request.DriveConfig.ColorRgb) }) if err != nil { return fmt.Errorf("failed to update drive info: %v", err) } } // 2. メンバーの権限更新 if len(request.MemberRoles) > 0 { err := executeWithRetry(func() error { return updateMemberRoles(srv, request.DriveID, request.MemberRoles) }) if err != nil { return fmt.Errorf("failed to update member roles: %v", err) } } // 3. 制限設定の更新 err := executeWithRetry(func() error { return updateDriveRestrictions(srv, request.DriveID, request.Restrictions) }) if err != nil { return fmt.Errorf("failed to update restrictions: %v", err) } return nil } func main() { ctx := context.Background() config, err := loadConfig("config.json") if err != nil { log.Fatalf("Unable to load config: %v", err) } srv, err := createDriveService(ctx, config) if err != nil { log.Fatalf("Unable to create Drive service: %v", err) } // バッチ更新の実行 batchRequest := BatchUpdateRequest{ DriveID: config.SharedDriveID, DriveConfig: DriveConfig{ Name: "開発チーム共有ドライブ", ColorRgb: "#34A853", }, MemberRoles: []MemberUpdate{ {"yamada@example.com", "organizer"}, {"kobayashi@example.com", "fileOrganizer"}, }, Restrictions: DriveRestrictions{ DomainUsersOnly: true, DriveMembersOnly: false, AdminManagedRestrictions: true, CopyRequiresWriterPermission: true, }, } err = batchUpdateSharedDrive(srv, batchRequest) if err != nil { log.Fatalf("Batch update failed: %v", err) } fmt.Println("Successfully completed all updates!") }

まとめ

本記事では、Go言語とGoogle Drive API v3を使用して、共有ドライブの各種設定をプログラムから変更する方法を解説しました。

  • Google Drive APIの基本的な使い方 - 認証設定からAPIクライアントの作成まで
  • 共有ドライブ情報の更新 - 名前や色などの基本情報の変更
  • メンバー権限の一括更新 - 複数のメンバーのロールを効率的に変更
  • 制限設定の管理 - セキュリティに関わる各種制限の設定
  • エラーハンドリング - 実装時に遭遇する代表的なエラーと解決方法

この記事を通して、大規模な組織でのGoogleドライブ管理の自動化が実現できます。特に、数十、数百の共有ドライブを管理する場合、GUI操作では大変な作業も、プログラムなら一瞬で完了します。

今後は、バッチ処理の最適化や、Cloud Functionsを使ったサーバーレスでの実装、SlackやTeamsとの連携による通知機能の追加についても記事にする予定です。

参考資料