＃49　Kibelaの記事をBacklogのWikiへ移行する〜Backlog APIを利用する

## はじめに

自社でこれまで作成してきたKibelaの記事をBacklogのWikiページに移行させたい、という要請を受けたため、まとめて記事を移行させるスクリプトをpythonで作成してみました。  
こちらでは備忘録として、移行までの調査内容や実際に作成したコードについて、3部に分けてまとめていきたいと思います。  
記事の第2部にあたる今回は、実際にスクリプトに使用したBacklogが公開しているAPIに関する説明を中心に取り上げます。  
スクリプトとの連携方法からまとめていきますので、初学者の方のご参考になれば幸いです。  
<br>
第1部の記事をご覧になりたい方は以下から確認できます。  
  
  
**本記事に関連するブログ記事**  

 - （第1部）[Kibelaの記事をBacklogのWikiへ移行する〜移行のための調査と準備](https://qiita.com/nxted_sapporo/items/d4a74dfa7af59c75e704)

## Backlog APIとは

ブラウザ上のBacklogで行える操作の多くを公開APIを用いて実行することができます。  
詳細については「[Backlog APIとは](https://developer.nulab.com/ja/docs/backlog/#)」をご参照ください。  
BacklogではAPI Key 方式と OAuth 2.0 方式の2パターンでAPIを提供していますが、今回はAPI Key 方式を利用してスクリプトを作成していきたいと思います。  
※API Keyの発行にはBacklogのアカウントが必要です  
<br>
BacklogではAPI Key 方式について、以下のように説明されています。  
  

> API Key
> 
> リクエストパラメーターにユーザーごとに発行された API キーを付加して認証する方式です。
> リソースへのアクセス時に、発行されたAPIキーをパラメータ名 “apiKey” として付加することで認証が行えます。  
> 引用：[https://developer.nulab.com/ja/docs/backlog/auth#](https://developer.nulab.com/ja/docs/backlog/auth#)

  
  
さて、今回作成するスクリプトで必要な機能は以下の通りです。  

 1. Wikiページを追加する
 2. 画像付きの記事に対応するWikiには該当画像を添付ファイルとして送信する

そして、これらを実現するために必要なAPIが表のようになります。  
それぞれのAPIに関して、より詳しく知りたい方はそれぞれのリンクを参照してください。  
  
|No.|やりたいこと|使用するAPI|
|:--:|----|----|  
|1|Wikiページを追加する|[Wikiページの追加](https://developer.nulab.com/ja/docs/backlog/api/2/add-wiki-page/#)|
|2|（No.3で使用するIDを発行）|[添付ファイルの送信](https://developer.nulab.com/ja/docs/backlog/api/2/post-attachment-file/#)| 
|3|画像を添付ファイルとして送る|[Wiki添付ファイルの追加](https://developer.nulab.com/ja/docs/backlog/api/2/attach-file-to-wiki/#)|
  

## API Key を取得する

Backlogの個人設定からAPI Keyを発行します。  
共通のAPI Keyを使用できるので、今回のように複数のAPIを使用する場合でも発行するAPI Keyは1つで大丈夫です。  
参考：[https://support-ja.backlog.com/hc/ja/articles/360035641754](https://support-ja.backlog.com/hc/ja/articles/360035641754)  
  
<br>
API Keyの他、各API共通で使用する値を先に定義してしまいましょう。  
  
```python
 # Backlogの個人設定から発行したAPIキー  
apikey = "aaaa"  
  
 # Backlog Wiki一覧などのアドレスバーにある"projectId="以下を参照  
projectId = "pppp"  
  
 # URLが[backlog.com](http://backlog.com/)の場合  
url = "[https://xx.backlog.com](https://xx.backlog.com/)"  
```

## Wikiページの追加

リクエストパラメータとして以下の情報を渡すことでAPIを実行することができます。  
  
|パラメータ名|必須|型|内容|
|----|:--:|----|----|  
|projectId|⚪︎|数値|プロジェクトID|  
|name|⚪︎|文字列|Wikiタイトル| 
|content|⚪︎|文字列|Wiki本文| 
|mailNotify||真偽値|ページの追加をメールで通知する場合はtrue| 

今回はrequestsライブラリを使用してHTTPリクエストを送信していこうと思います。  
リクエストパラメータの設定方法としては  
**①送信するurlの後ろに&projectId=のように直接加える  
②requests.post()の引数にクエリパラメータを指定する**  
がありますが、ここでは解説も兼ねて、両方のパターンを使用して関数`backlogAddWiki()`を作成してみます。  
また、Wiki添付ファイルの追加APIで使用するため、戻り値としてレスポンスボディの[id]を返すようにしておきます。  

### ①送信するurlの後ろに直接加える

パラメータ名`projectId`,`name`をこちらの方法で設定します。  
ここでは書式化演算子%を使用して、送信するurlを新たに作成してみましょう。  

<br>
以下のような形にすることで、書式を指定して新しい文字列を作成することができます。  

  ```python
"[変換指定子を含む文字列]" % (値1, 値2, ...)  
```

今回は特にオプションを設定しない文字列型を変換型として指定したいので、%sを含む文字列とします。  
`requests.post()`の引数に設定したいurlは
`https://xx.backlog.com/api/v2/wikis?apiKey='aaaa'&projectId='pppp'&name='[Wikiタイトル]`
です。  
それぞれ分解すると、  

|URL|値|
|----|----| 
|`https://xx.backlog.com`|変数urlの値|  
|/api/v2/wikis|Wikiページの追加APIのURL| 
|aaaa|変数apiKeyの値| 
|pppp|変数projectIdの値| 
|[Wikiタイトル]| Wikiのタイトルにしたい文字列（変数wikiNameに格納されていることとします）|  

となります。  
`?`以下の`apiKey=`,`projectId=`,`name=`がパラメータ名となり、&で各パラメータを繋ぎます。  
ここからわかるように、上のURLには変数の値が使用できる箇所がいくつかあります。  
変数をそのまま挿入することはできないので、%sを利用して以下のようにします。
  
```python  
 # "[url]/api/v2/wikis?apiKey=[apikey]&projectId=[projectId]&name=[wikiName]"としたい ※[]内は変数名  
uploadUrl = "%s/api/v2/wikis?apiKey=%s&projectId=%s&name=%s" % (url, apikey, projectId, wikiName)  
requests.post(uploadUrl)  
```


### ②requests.post()の引数にクエリパラメータを指定する

パラメータ名`content`,`mailNotify`をこちらの方法で設定します。  
こちらは送信したいURLの他に、データを辞書型で指定して引数として渡します。params引数に指定したクエリパラメータは、自動的にURLの末尾に追加してくれます。
  
```python
payload = {  
'content': [Wiki本文],  
'mailNotify': 'false', # ページの追加をメールで通知しないのでfalse  
}  
requests.post([URL], params = payload)  
```

以上を踏まえて作成した`backlogAddWiki()`が以下です。  
ご参考ください。  

```python
import requests  
  
 # wikiName = "[カテゴリ名]/[置換済Kibela記事タイトル]"  
 # wikiTitle = "[置換済Kibela記事タイトル]"  
  
def backlogAddWiki(wikiName, wikiTitle):  
 # 「①送信するurlの後ろに直接加える」を参考  
  uploadUrl = "%s/api/v2/wikis?apiKey=%s&projectId=%s&name=%s" % (url, apikey, projectId, wikiName)  
  
 # Wiki本文として掲載したい内容を取得してaddFileに格納  
  addFilePath = "added/" + wikiTitle + ".md"  
  readFile = open(addFilePath, 'r', encoding="utf-8_sig")  
  addFile = readFile.read()  
  readFile.close()  
  
 # 「②requests.post()の引数にクエリパラメータを指定する」を参考  
  payload = {  
    'content': addFile,  
    'mailNotify': 'false',  
  }  
  
 # HTTPレスポンスをJSON形式で取得する  
  jsonData = requests.post(uploadUrl, params = payload).json()  
  
 # JSON形式でエンコードして["id"]の値を取得する  
  id = json.dumps(jsonData["id"], indent=4)  
  
  return id
```


## 添付ファイルの送信  

 
続いて関数`backlogSendAttachment()`を作成します。  
リクエストパラメータとして添付したいファイルの情報を渡すことでAPIを実行することができます。  
なお、Wiki添付ファイルの追加APIで使用するため`backlogAddWiki()`同様、戻り値としてレスポンスボディの[id]を返すようにしておきます。  
参考：[添付ファイルの送信APIのURL](https://developer.nulab.com/ja/docs/backlog/api/2/post-attachment-file/#url)
<br>
`backlogSendAttachment()`では.glob()関数を用いて、指定したフォルダの中を画像ファイル名で検索しています。  
こちらの解説は[前回記事](https://qiita.com/nxted_sapporo/items/d4a74dfa7af59c75e704)にあるので、ご参考ください。 

```python
 # ATTACHMENT_FOLDER = Path("[Kibelaからエクスポートした画像フォルダのパス]")  
 # attachmentFileName = "[Kibelaからエクスポートした画像ファイル名]"  
  
def backlogSendAttachment(attachmentFileName):  
 # フォルダの中を画像ファイル名で検索、ヒットするかで分岐させる  
  for a in ATTACHMENT_FOLDER.glob(attachmentFileName + ".png"):  
    res = re.search(attachmentFileName, str(a))  
    if res == None: # ファイル名での検索がヒットしない場合  
      return  
    else: # ファイル名での検索がヒットした場合  
      fileName = attachmentFileName + '.png'  
      filePath = str(a)  
 # urlにパラメータを直接追加  
      uploadUrl = "%s/api/v2/space/attachment?apiKey=%s" % (url, apikey)  
 # 辞書型にしてrequests.post()の引数に渡す  
      files = {'file': (fileName ,open(filePath, 'rb'))}  
  
      jsonData = requests.post(uploadUrl, files = files).json()  
      id = json.dumps(jsonData["id"], indent=4)  
  
  return id  
```


## Wiki添付ファイルの追加  

続いて関数`backlogAddAttachment()`を作成します。  
URLパラメータとして画像を添付させたいWikiページのIDを指定し、リクエストパラメータとして添付ファイルの送信APIから返却されたIDを渡すことでAPIを実行することができます。  
参考：[Wiki添付ファイルの追加APIのURL](https://developer.nulab.com/ja/docs/backlog/api/2/attach-file-to-wiki/#url)  
<br>
`backlogAddAttachment()`ではformat メソッドを使って新しい文字列を作成してみます。  
基本の形は  

```python
"[置換フィールドを含む文字列]".format(値1, 値2, ...)  
```

となり、書式化演算子の%の形と似ていることがわかるかと思います。  
また、このメソッドは以下のように説明されています。  
  

> 文字列中の置換フィールドに先頭から順番に 0 , 1 , 2, … と割り当てる場合には数値を省略することができます。その為、次の
> 2つは同じです。      “名前{0}です。{1}歳。住所は{2}です。”.format(“Yamada”, 18, “Tokyo”)  
> “名前{}です。{}歳。住所は{}です。”.format(“Yamada”, 18, “Tokyo”)  
> 引用：formatメソッドを使った文字列の書式設定

 
  
以下では書式化演算子の%とformat メソッドをそれぞれ使用して新しい文字列を作成してみているので、そちらも併せてご参考いただけると幸いです。  
  
```python
 # wikiId = [画像を添付させたいWikiページのID]  
 # attachIdLists = [添付ファイルの送信APIから返却されたIDのリスト]  
  
def backlogAddAttachment(wikiId, attachIdLists):  
  attachStr = '&attachmentId[]='  
  for attachIdList in attachIdLists:  
    if attachIdList == attachIdLists[0]:  
 # format メソッド  
      attachmentId = '{}{}'.format(attachStr, attachIdList)  
    else:  
 # format メソッド  
      attachmentId = '{}{}{}'.format(attachmentId, attachStr, attachIdList)  
 # 書式化演算子の%  
      uploadUrl = "%s/api/v2/wikis/%s/attachments?apiKey=%s%s" % (url, wikiId, apikey, attachmentId)  
  
  requests.post(uploadUrl).json()  
```


## おわりに  

 
今回はKibelaの記事をBacklogのWikiへ移行する記事の第2部として、Backlogが公開しているAPIについて取り上げました。  
初学者の方の公開APIの連携方法やリクエストパラメータの送り方の参考になれば幸いです。  
  
<br>
「Wikiページの追加：①送信するurlの後ろに直接加える」をはじめ、本記事では書式化演算子%を使用して新しい文字列を作成する方法も紹介しましたが、現在の主流は「Wiki添付ファイルの追加」で触れた文字列型の format メソッドを使った方法やフォーマット済み文字列リテラルを利用する方法のようです。  
機会があれば、これらの方法を使用した場合と今回の書式化演算子%を使用した場合で、もう少し詳しい解説を交えつつ、それぞれのパターンを比較する記事も書いてみたいです。  
  
<br>
次回は実際に作成したスクリプトのコードの紹介をしていこうと思います。  
最後まで閲覧いただきありがとうございます。  
  
<br><br>
参考：  
  
[https://blog.serverworks.co.jp/backlogwikipythonadd](https://blog.serverworks.co.jp/backlogwikipythonadd)  
[https://www.javadrive.jp/python/string/index23.html](https://www.javadrive.jp/python/string/index23.html)