😽

【Part3】GoMSGraph で始める Microsoft Graph API 操作 — サービス層の実装解説と設計思想

2025/02/12に公開

過去の記事

前回の記事「【Part2】GoMSGraph で始める Microsoft Graph API 操作 — GraphHelper メソッドの実装解説」では、GraphHelper パッケージに実装された各メソッド(フォルダ作成、ファイルダウンロード、大容量ファイルアップロードなど)の詳細な実装と、その動作の流れについて解説しました。
また、GraphHelper の初期化処理や認証の仕組みについては、前々回の記事「【Part1】GoMSGraph で始める Microsoft Graph API 操作 — 認証とクライアント初期化の実装解説」で詳しく取り上げていますので、そちらもぜひご確認ください。

リポジトリについて

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

GraphService 実装解説 — Microsoft Graph API 操作をシンプルにするサービス層の設計

本記事では、GoMSGraph ライブラリの service/graphservice.go に実装された GraphService インターフェースとその実装クラス graphServiceImpl について解説します。
GraphService は、Microsoft Graph API を利用したファイル操作、サイト検索、アクセストークンの取得、大容量ファイルのアップロード・ダウンロードなどの機能を、利用者が低レベルの詳細を気にせずに使えるように抽象化しています。


1. GraphService インターフェースの概要

GraphService インターフェースは、Microsoft Graph API の操作をまとめた一連のメソッドを提供しています。
各メソッドは内部で GraphHelper のメソッドを呼び出しており、利用者はシンプルなインターフェースを通して API 操作を行うことができます。

具体的なメソッドは以下の通りです。

  • CreateFolder
    指定したドライブ内の対象アイテムの子要素として新規フォルダを作成します。

  • GetDriveRootItems
    指定したドライブのルートアイテムおよびその子要素を取得します。

  • GetDriveItem
    指定したドライブとアイテム ID に基づき、詳細なアイテム情報を取得します。

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

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

  • GetSiteByName
    指定したサイト名で SharePoint サイトを検索し、該当するサイト一覧を取得します。

  • UploadFile
    大容量ファイルの分割アップロードを実現するため、アップロードセッションを利用してファイルをアップロードします。

  • CreateUploadSession
    指定パスに対して大容量ファイルのアップロード用セッションを作成します。

  • DownloadDriveItem
    指定したファイルのコンテンツ(バイト列)を取得します。
    ※ フォルダの場合は、ダウンロード処理をサポートしていないためエラーとなります。

これらのメソッドは、内部で GraphHelper の実装を呼び出すことで、細かい認証処理や API 呼び出し、エラーハンドリングなどの詳細なロジックを隠蔽しています。

インターフェース定義のコード例

package service

import (
	"context"
	"fmt"
	"os"

	"github.com/Azure/azure-sdk-for-go/sdk/azcore"
	"github.com/Tsubasa-2005/GoMSGraph/graphhelper"
	"github.com/microsoftgraph/msgraph-sdk-go/models"
)

type GraphService interface {
	CreateFolder(ctx context.Context, driveID, driveItemID, folderName string) (models.DriveItemable, error)
	GetDriveRootItems(ctx context.Context, driveID string) ([]models.DriveItemable, error)
	GetDriveItem(ctx context.Context, driveID, driveItemID string) (models.DriveItemable, error)
	DeleteDriveItem(ctx context.Context, driveID, driveItemID string) error
	GetAppToken(ctx context.Context) (azcore.AccessToken, error)
	GetSiteByName(ctx context.Context, siteName string) ([]models.Siteable, error)
	UploadFile(uploadSession models.UploadSessionable, file *os.File) (models.DriveItemable, error)
	CreateUploadSession(ctx context.Context, driveID, itemPath string) (models.UploadSessionable, error)
	DownloadDriveItem(ctx context.Context, driveID, driveItemID string) ([]byte, error)
}

2. 実装クラス graphServiceImpl の解説

graphServiceImpl は GraphService インターフェースの実装クラスであり、内部に graphhelper.GraphHelper を保持しています。
GraphHelper には、Microsoft Graph API との低レベルなやり取り(認証、各種 API リクエストの実行、エラーチェックなど)が実装されており、graphServiceImpl はそのラッパーとして機能します。

コンストラクタ

func NewGraphService(clientId, tenantId, clientSecret string, logger *graphhelper.Logger) (GraphService, error) {
	gh, err := graphhelper.NewGraphHelper(clientId, tenantId, clientSecret, logger)
	if err != nil {
		return nil, fmt.Errorf("failed to initialize GraphHelper: %w", err)
	}
	return &graphServiceImpl{
		helper: gh,
	}, nil
}
  • 役割
    • クライアント ID、テナント ID、クライアントシークレット、ロガーなどの初期化パラメータを受け取り、GraphHelper を生成します。
    • これにより、認証処理や API クライアントの初期化などの共通処理を GraphHelper に任せ、サービス層はシンプルなメソッド呼び出しのみとなっています。

メソッド実装例

各メソッドは内部で GraphHelper の対応するメソッドを呼び出すだけのシンプルな実装になっています。たとえば、フォルダ作成のメソッドは以下のようになります。

func (s *graphServiceImpl) CreateFolder(ctx context.Context, driveID, driveItemID, folderName string) (models.DriveItemable, error) {
	return s.helper.CreateFolder(ctx, driveID, driveItemID, folderName)
}

その他のメソッドも同様に、GraphHelper の機能をそのまま呼び出しているため、利用者は複雑な処理を意識せずに API 操作を行うことが可能です。


3. ダウンロード処理におけるドメインロジック

DownloadDriveItem メソッドは、単純にファイルのダウンロードを行うだけではありません。内部では、複数のメソッドを組み合わせることで「対象がファイルであるか」を確認するドメインロジックが実装されています。

ダウンロード処理の流れ

  1. 対象アイテムの詳細情報の取得
    • s.helper.GetDriveItem(ctx, driveID, driveItemID) により、ダウンロード対象のアイテム情報を取得します。
  2. ファイルであるかの検証
    • 取得したアイテムに対して item.GetFile() を呼び出し、ファイルかどうかを判定します。
    • フォルダの場合は nil となるため、ファイルでない場合はエラーを返します。
  3. ファイルコンテンツのダウンロード
    • ファイルであると確認できた場合、s.helper.DownloadDriveItem(ctx, driveID, driveItemID) を呼び出して、実際のダウンロード処理を行います。

コード例

func (s *graphServiceImpl) DownloadDriveItem(ctx context.Context, driveID, driveItemID string) ([]byte, error) {
	item, err := s.helper.GetDriveItem(ctx, driveID, driveItemID)
	if err != nil {
		return nil, fmt.Errorf("failed to retrieve drive item: %w", err)
	}

	// フォルダの場合はダウンロード不可のためエラーを返す
	if item.GetFile() == nil {
		return nil, fmt.Errorf("download is only supported for files, not folders")
	}

	return s.helper.DownloadDriveItem(ctx, driveID, driveItemID)
}

この実装のメリット

  • 利用者はシンプルな呼び出しのみで操作可能
    API 利用者は DownloadDriveItem を呼び出すだけで、内部でファイルであるかの検証やエラーチェックが実施されるため、細かいロジックを意識する必要がありません。

  • 柔軟な拡張性
    同様のインターフェースを自分で実装する場合、GraphHelper の各種メソッドを組み合わせることで、必要なビジネスロジックや追加の検証処理を容易にカスタマイズできます。
    たとえば、ファイルの種類やサイズに応じた独自のチェックを挟むなど、用途に応じた柔軟な設計が可能です。


4. 設計思想とまとめ

今回の GraphService の実装は、以下の設計思想に基づいています。

  1. 抽象化と隠蔽によるシンプルな API 操作

    • GraphService インターフェースにより、利用者は細かい認証処理や API 呼び出しの実装詳細を意識することなく、シンプルなメソッド呼び出しで Microsoft Graph API を操作できます。
  2. 再利用性とメンテナンス性の向上

    • GraphHelper によって共通の処理(認証、エラーハンドリング、各種 API 呼び出し)が一元管理されるため、コードの再利用性が高く、メンテナンスもしやすくなっています。
  3. 柔軟な拡張性

    • 特にダウンロード処理のように複数のメソッドを組み合わせたドメインロジックは、開発者が自身のニーズに合わせてカスタマイズしやすい設計となっています。
    • このため、独自のインターフェース実装を行う場合でも、GraphHelper の各種メソッドを組み合わせることで、柔軟に設計を拡張できます。

以上の設計思想により、開発者は GraphService インターフェースを利用することで、Microsoft Graph API の複雑な処理を意識せずに、シンプルで安全な API 操作を実現できます。
また、必要に応じて独自の実装を行う場合でも、GraphHelper の柔軟性を活かして自由にカスタマイズできる点が、このライブラリの大きな強みとなっています。


参考リンク

Discussion