🚀

【Part2】GoMSGraph で始める Microsoft Graph API 操作 — GraphHelper メソッドの実装解説

2025/02/12に公開

前回

今回の記事では、GraphHelper の各メソッドの実装部分について詳しく解説しています。
なお、今回のコードで使用しているレシーバ(g *GraphHelper)の初期化部分については、前回の記事【Part1】GoMSGraph で始める Microsoft Graph API 操作 — 認証とクライアント初期化の実装解説で詳細に解説しています。
まだそちらをご覧になっていない方は、ご確認ください。

リポジトリについて

GoMSGraph ライブラリは、GitHub 上で公開されています。
ライブラリの最新のソースコードやドキュメント、Issue の管理などは、下記のリポジトリページからご覧いただけます。
ぜひリポジトリも併せてご確認ください。
https://github.com/Tsubasa-2005/GoMSGraph

GraphHelper の各メソッド解説

本記事では、GoMSGraph ライブラリの graphhelper パッケージに実装されている各メソッドについて解説します。
前回の Part1 でクライアント初期化や認証の基礎について触れましたが、今回は実際に Microsoft Graph API を利用してファイルやサイト、ドライブアイテムを操作する具体的な処理に焦点を当てます。


1. フォルダの作成 (CreateFolder)

概要

CreateFolder メソッドは、指定したドライブ内の任意のドライブアイテム(通常はフォルダ)に対して、新規フォルダを作成する機能を提供します。

主な処理の流れ

  • 新規フォルダのインスタンス生成
    models.NewDriveItem() で新たなドライブアイテムを生成し、SetName でフォルダ名を設定、さらに SetFolder でフォルダ属性を付与します。
  • フォルダ作成リクエスト
    作成したフォルダ情報を、対象ドライブの特定の親アイテムの子要素として Children().Post(...) を呼び出すことで実際に作成します。
  • エラーハンドリング
    作成処理に失敗した場合は、詳細なエラーメッセージを返します。

コード例


package graphhelper

import (
	"fmt"

	"golang.org/x/net/context"

	"github.com/microsoftgraph/msgraph-sdk-go/models"
)

func (g *GraphHelper) CreateFolder(ctx context.Context, driveID, driveItemID, folderName string) (models.DriveItemable, error) {
	newFolder := models.NewDriveItem()
	newFolder.SetName(&folderName)
	newFolder.SetFolder(models.NewFolder())

	item, err := g.appClient.Drives().ByDriveId(driveID).Items().ByDriveItemId(driveItemID).Children().Post(ctx, newFolder, nil)
	if err != nil {
		return nil, fmt.Errorf("failed to create folder '%s' in drive '%s' at item '%s': %w", folderName, driveID, driveItemID, err)
	}

	return item, nil
}


2. ルートアイテムの取得 (GetDriveRootItems)

概要

GetDriveRootItems メソッドは、指定したドライブのルートアイテム(通常はルートフォルダ)の情報と、その子要素の一覧を取得します。

主な処理の流れ

  • ルートアイテムの取得
    Drives().ByDriveId(driveID).Root().Get(ctx, nil) により、ルートアイテムの情報を取得します。
  • 子アイテムの一覧取得
    ルートアイテムの ID を用い、Children().Get(ctx, nil) を呼び出して子要素を取得し、返却します。
  • エラーチェック
    どちらの処理でもエラーが発生した場合、詳細なエラー内容を返します。

コード例


package graphhelper

import (
	"context"
	"fmt"

	"github.com/microsoftgraph/msgraph-sdk-go/models"
)

func (g *GraphHelper) GetDriveRootItems(ctx context.Context, driveID string) ([]models.DriveItemable, error) {
	get, err := g.appClient.Drives().ByDriveId(driveID).Root().Get(ctx, nil)
	if err != nil {
		return nil, fmt.Errorf("failed to get drive root for drive %s: %w", driveID, err)
	}

	items, err := g.appClient.Drives().ByDriveId(driveID).Items().ByDriveItemId(*get.GetId()).Children().Get(ctx, nil)
	if err != nil {
		return nil, fmt.Errorf("failed to get children for drive item %s in drive %s: %w", *get.GetId(), driveID, err)
	}

	return items.GetValue(), nil
}


3. アイテムの詳細取得 (GetDriveItem)

概要

GetDriveItem メソッドは、指定したドライブアイテムの詳細情報を取得します。
ドライブIDとアイテムIDを用いて、特定のファイルやフォルダの情報を取得します。

主な処理の流れ

  • リクエスト送信
    Drives().ByDriveId(driveID).Items().ByDriveItemId(driveItemID).Get(ctx, nil) により、該当アイテムの詳細情報を取得します。
  • エラーハンドリング
    リクエストが失敗した場合は、エラーを返します。

コード例

package graphhelper

import (
	"context"
	"fmt"

	"github.com/microsoftgraph/msgraph-sdk-go/models"
)

func (g *GraphHelper) GetDriveItem(ctx context.Context, driveID, driveItemID string) (models.DriveItemable, error) {
	item, err := g.appClient.Drives().ByDriveId(driveID).Items().ByDriveItemId(driveItemID).Get(ctx, nil)
	if err != nil {
		return nil, fmt.Errorf("failed to get drive item %s in drive %s: %w", driveItemID, driveID, err)
	}
	return item, nil
}


4. アイテムの削除 (DeleteDriveItem)

概要

DeleteDriveItem メソッドは、指定したドライブ内のファイルまたはフォルダを削除します。

主な処理の流れ

  • 削除リクエストの実行
    Drives().ByDriveId(driveID).Items().ByDriveItemId(driveItemID).Delete(ctx, nil) を呼び出して、削除処理を実施します。
  • エラーチェック
    削除に失敗した場合、エラーメッセージを返します。

コード例


package graphhelper

import (
	"context"
	"fmt"
)

func (g *GraphHelper) DeleteDriveItem(ctx context.Context, driveID, driveItemID string) error {
	if err := g.appClient.Drives().ByDriveId(driveID).Items().ByDriveItemId(driveItemID).Delete(ctx, nil); err != nil {
		return fmt.Errorf("failed to delete drive item %s in drive %s: %w", driveItemID, driveID, err)
	}
	return nil
}


5. ファイルのダウンロード (DownloadDriveItem)

概要

DownloadDriveItem メソッドは、指定したファイルのコンテンツ(バイト列)を取得するためのメソッドです。
※ フォルダの場合は、ダウンロードはサポートされずエラーとなります。

主な処理の流れ

  • ファイルコンテンツの取得
    Drives().ByDriveId(driveID).Items().ByDriveItemId(driveItemID).Content().Get(ctx, nil) により、対象ファイルのコンテンツをダウンロードします。
  • エラーチェック
    ダウンロード処理に失敗した場合、詳細なエラー内容を返します。

コード例


package graphhelper

import (
	"context"
	"fmt"
)

func (g *GraphHelper) DownloadDriveItem(ctx context.Context, driveID, driveItemID string) ([]byte, error) {
	bytes, err := g.appClient.Drives().ByDriveId(driveID).Items().ByDriveItemId(driveItemID).Content().Get(ctx, nil)
	if err != nil {
		return nil, fmt.Errorf("failed to download drive item %s in drive %s: %w", driveItemID, driveID, err)
	}
	return bytes, nil
}


6. アプリケーショントークンの取得 (GetAppToken)

概要

GetAppToken メソッドは、Azure AD のクライアントシークレット認証情報を利用して、Microsoft Graph API へのアクセスに必要なアクセストークンを取得します。

主な処理の流れ

  • トークン取得リクエスト
    clientSecretCredential.GetToken を呼び出し、スコープ "https://graph.microsoft.com/.default" を指定してアクセストークンをリクエストします。
  • エラーチェック
    トークン取得に失敗した場合、エラーとして返します。

コード例

package graphhelper

import (
	"context"
	"fmt"

	"github.com/Azure/azure-sdk-for-go/sdk/azcore"
	"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
)

func (g *GraphHelper) GetAppToken(ctx context.Context) (azcore.AccessToken, error) {
	token, err := g.clientSecretCredential.GetToken(ctx, policy.TokenRequestOptions{
		Scopes: []string{"https://graph.microsoft.com/.default"},
	})
	if err != nil {
		return azcore.AccessToken{}, fmt.Errorf("failed to get app token: %w", err)
	}

	return token, nil
}

7. サイトの検索 (GetSiteByName)

概要

GetSiteByName メソッドは、指定したサイト名を元に Microsoft 365 内の SharePoint サイトを検索し、該当するサイトの一覧を取得します。

主な処理の流れ

  • 検索クエリの作成
    引数のサイト名を引用符で囲んだ上で、検索用のクエリパラメータを作成します。
  • サイト検索リクエスト
    Sites().Get(ctx, config) を呼び出し、該当サイトの一覧を取得します。
  • 結果のチェック
    検索結果が空の場合は、エラーとして通知します。

コード例

package graphhelper

import (
	"context"
	"fmt"

	"github.com/microsoftgraph/msgraph-sdk-go/models"
	"github.com/microsoftgraph/msgraph-sdk-go/sites"
)

func (g *GraphHelper) GetSiteByName(ctx context.Context, siteName string) ([]models.Siteable, error) {
	quotedSiteName := fmt.Sprintf("\"%s\"", siteName)
	query := &sites.SitesRequestBuilderGetQueryParameters{
		Search: &quotedSiteName,
	}
	config := &sites.SitesRequestBuilderGetRequestConfiguration{
		QueryParameters: query,
	}
	sitesResponse, err := g.appClient.Sites().Get(ctx, config)
	if err != nil {
		return nil, fmt.Errorf("site search error: %w", err)
	}
	siteList := sitesResponse.GetValue()
	if len(siteList) == 0 {
		return nil, fmt.Errorf("no sites found matching the search query '%s'", siteName)
	}
	return siteList, nil
}

8. 大容量ファイルのアップロード (UploadFile)

概要

UploadFile メソッドは、大容量ファイルのアップロード処理を分割アップロード方式で実現しています。
アップロードセッションを利用して、ファイルを複数のチャンクに分割して送信し、途中で失敗した場合の再開もサポートします。

主な処理の流れ

  • アップロードタスクの作成
    最大スライスサイズ(ここでは 320KB)を設定し、NewLargeFileUploadTask を利用してアップロードタスクを初期化します。
  • 進捗状況のコールバック
    アップロード中に、進捗状況をログに出力するコールバック関数を登録します。
  • アップロードの実行と再開
    最初のアップロード試行が失敗した場合、タスクの Resume メソッドを呼び出してアップロード再開を試みます。
    再開時も失敗した場合、エラー内容を集約して返します。

コード例

package graphhelper

import (
	"fmt"
	"os"
	"strings"

	"github.com/microsoftgraph/msgraph-sdk-go-core/fileuploader"
	"github.com/microsoftgraph/msgraph-sdk-go/models"
)

func (g *GraphHelper) UploadFile(uploadSession models.UploadSessionable, byteStream *os.File) (models.DriveItemable, error) {
	maxSliceSize := int64(320 * 1024)
	fileUploadTask := fileuploader.NewLargeFileUploadTask[models.DriveItemable](
		g.appClient.RequestAdapter,
		uploadSession,
		byteStream,
		maxSliceSize,
		models.CreateDriveItemFromDiscriminatorValue,
		nil,
	)

	progress := func(uploaded int64, total int64) {
		g.Logger.Debugf("Uploaded %d of %d bytes", uploaded, total)
	}

	uploadResult := fileUploadTask.Upload(progress)
	if uploadResult.GetUploadSucceeded() {
		return uploadResult.GetItemResponse(), nil
	}

	g.Logger.Warnf("Initial upload failed. Attempting to resume...")

	resumeResult, err := fileUploadTask.Resume(progress)
	if err != nil {
		return nil, fmt.Errorf("upload resume failed: %w", err)
	}
	if resumeResult.GetUploadSucceeded() {
		return resumeResult.GetItemResponse(), nil
	}

	var errMessages []string
	for _, e := range resumeResult.GetResponseErrors() {
		errMessages = append(errMessages, e.Error())
	}

	return nil, fmt.Errorf("upload failed: %s", strings.Join(errMessages, "; "))
}

9. アップロードセッションの作成 (CreateUploadSession)

概要

CreateUploadSession メソッドは、指定したパスに対して大容量ファイルのアップロード用のセッションを作成します。
ファイルが既存の場合は上書き、存在しない場合は新規作成を行う設定(ここでは "replace")がされています。

主な処理の流れ

  • アップロードプロパティの設定
    NewDriveItemUploadableProperties を用いて、アップロード時の動作(例: コンフリクト時の挙動)を設定します。
  • アップロードセッション作成リクエスト
    リクエストボディを生成し、CreateUploadSession().Post(ctx, ...) を呼び出してセッションを作成します。
  • エラーチェック
    セッションの作成に失敗した場合、詳細なエラーメッセージを返します。

コード例

package graphhelper

import (
	"context"
	"fmt"

	"github.com/microsoftgraph/msgraph-sdk-go/drives"
	"github.com/microsoftgraph/msgraph-sdk-go/models"
)

func (g *GraphHelper) CreateUploadSession(ctx context.Context, driveID, itemPath string) (models.UploadSessionable, error) {
	itemUploadProperties := models.NewDriveItemUploadableProperties()
	itemUploadProperties.SetAdditionalData(map[string]any{"@microsoft.graph.conflictBehavior": "replace"})
	uploadSessionRequestBody := drives.NewItemItemsItemCreateUploadSessionPostRequestBody()
	uploadSessionRequestBody.SetItem(itemUploadProperties)

	session, err := g.appClient.Drives().ByDriveId(driveID).Items().ByDriveItemId("root:/"+itemPath+":").CreateUploadSession().Post(ctx, uploadSessionRequestBody, nil)
	if err != nil {
		return nil, fmt.Errorf("failed to create upload session for drive %s and item path %s: %w", driveID, itemPath, err)
	}

	return session, nil
}

まとめ

今回の Part2 では、GoMSGraph の graphhelper パッケージに実装されている各種メソッドについて解説しました。
Microsoft Graph API を利用したファイル操作、サイト検索、トークン取得、大容量ファイルのアップロードなど、多岐にわたる処理がこのライブラリによってシンプルなメソッドとして提供されています。

次回の Part3 では、これらのメソッドを活用した実際のアプリケーションでの利用例や、エラーハンドリング、カスタムロガーの応用例などについてさらに詳しく解説していく予定です。


参考リンク

Discussion