[Angular] 與 O365 跳舞系列 - OneDrive

自從去年寫了兩篇跟 O365 Graph 有關的文章後,就停了好長的一段時間,長到連登入的方法都改變了,(登入篇 也做了相對應的更新)

存取檔案可以算是很常見的需求,所以這次要來研究如何讀寫在 OneDrive 上的檔案

權限

當然要存取檔案系統,就必須申請權限,操作檔案需要請求 Files.ReadFiles.ReadWrite 讀寫權限。

基本概念

Microsoft Graph 針對檔案操作有兩種類型的物件

  1. Drive : 代表著使用者裝檔案的容器或檔案的基本資訊
  2. DriveItem: 呈現檔案或是資料夾本身的詳細資訊

這裡我只會針對 DriveItem 去做展示,大部分的操作也是針對 DriveItem 資料類型去做操作。

API 操作

列表

  • /drivers/{drive-id} : 取得特定 drive 的 metadata

  • /drive/root : 取得目前使用者預設根目錄

  • /drive/root/children 列出目前使用者根目錄下的所有資料夾和檔案項目

  • /drive/root/search: 搜尋根目錄

  • /drive/sharedWithMe: 列出分享給使用者的檔案清單

  • /drive/special/{special-folder-id}: 進入特定的資料夾,特殊資料夾有以下

    Name ID
    Documents documents
    Photos photos
    Camera Roll cameraroll
    App Root approot
    Music music

範例程式

1
2
3
4
5
6
7
8
9
getPhotos() {
const headers = new HttpHeaders().append(
'Authorization',
`Bearer ${this.accessToken}`
);
return this.http.get(
'https://graph.microsoft.com/v1.0/me/drive/special/photos',{headers}
);
}
  • 此 API 呼叫會回傳 Drive 型別的資訊

    1564120526642

1
2
3
4
5
6
7
8
9
10
11
12
getPhotos() {
const header = new HttpHeaders().append(
'Authorization',
`Bearer ${this.accessToken}`
);
return this.http.get(
'https://graph.microsoft.com/v1.0/me/drive/special/photos/children',
{
headers: header
}
);
}
  • 取得 Photos 資料夾下所有的檔案項目

  • 回傳的資料型別為 DriveItem

    1564120647528

  • 如果是檔案,就會出現 @microsoft.graph.downloadUrl ,如果是資料夾就不會

新增資料夾

建立資料夾當然需要擁有寫入資料夾的權限,記得要授權 Files.ReadWrite

可以使用的 API 有

  • POST /drives/{drive-id}/items/{parent-item-id}/children
  • POST /groups/{group-id}/drive/items/{parent-item-id}/children
  • POST /me/drive/items/{parent-item-id}/children
  • POST /sites/{site-id}/drive/items/{parent-item-id}/children
  • POST /users/{user-id}/drive/items/{parent-item-id}/children

範例程式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
createFolder() {
const driveItem = {
name: 'New Folder',
folder: {},
'@microsoft.graph.conflictBehavior': 'rename'
};
const headers = new HttpHeaders().append(
'Authorization',
`Bearer ${this.accessToken}`
);
return this.http.post<any>(
'https://graph.microsoft.com/v1.0/me/drive/items/689EA0E484C3AFBF!33462/children',
driveItem,
{ headers }
);
}
  • line 5: 決定當遇到名稱重複時的動作
    • fail
    • replace
    • rename : 在名稱後給予流水號,例如 fnamefname 1fname 2
  • 回傳的 response 內就會包含這一次建立資料夾的相關資訊

修改名稱 / 移動檔案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
renameItem() {
const driveItem = {
name: 'Folder After Rename'
};
const headers = new HttpHeaders().append(
'Authorization',
`Bearer ${this.accessToken}`
);
return this.http.patch<any>(
'https://graph.microsoft.com/v1.0/me/drive/items/{item-id}',
driveItem,
{ headers }
);
}
  • 要使用 patch 的方法

  • 如果移動資料夾或是檔案,要修改的對象為 parentReference 裡的 id

    1
    2
    3
    4
    5
    6
    const driveItem = {
    parentReference: {
    id: '{new-parent-folder-id}'
    },
    name: 'new-item-name.txt'
    };

刪除檔案

刪除檔案就比較直覺了

可以使用的 API 有

  • DELETE /drives/{drive-id}/items/{item-id}
  • DELETE /groups/{group-id}/drive/items/{item-id}
  • DELETE /me/drive/items/{item-id}
  • DELETE /sites/{siteId}/drive/items/{itemId}
  • DELETE /users/{userId}/drive/items/{itemId}

範例程式

1
2
3
4
5
6
7
8
9
10
11
 deleteItem() {
const headers = new HttpHeaders().append(
'Authorization',
`Bearer ${this.accessToken}`
);

return this.http.delete<any>(
'https://graph.microsoft.com/v1.0/me/drive/items/{item-id}',
{ headers }
);
}

下載檔案

透過 API 方式取得檔案的內容,可以使用的 API 有

  • GET /drives/{drive-id}/items/{item-id}/content
  • GET /groups/{group-id}/drive/items/{item-id}/content
  • GET /me/drive/root:/{item-path}:/content
  • GET /me/drive/items/{item-id}/content
  • GET /sites/{siteId}/drive/items/{item-id}/content
  • GET /users/{userId}/drive/items/{item-id}/content

範例程式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { saveAs } from 'file-saver';
downloadFile() {
const headers = new HttpHeaders().append(
'Authorization',
`Bearer ${this.accessToken}`
);
return this.http
.get(
'https://graph.microsoft.com/v1.0/me/drive/items/{item-id}/content',
{ headers, responseType: 'blob' }
)
.subscribe(res => {
const blob = new Blob([res], { type: res.type });
const filename = 'example.txt';
saveAs(blob, filename);
});
}
  • 偷懶一下,安裝 file-saver 套件
  • 設定 responseTypeblob

結語

更多的相關操作可以參閱官方文件,文件的部分寫得算是很詳細。文件的連結我就放在下面的參考資料內

參考資料