REST APIでRedmineアクセス(3)
2025/06/14
今回はWikiの編集
Project情報の取得
  • WikiページはProjectに属するデータなので、Wikiページを操作するには、まずProjectの情報が必要です。下記がProject情報の取得コードです。
  • import requests
    import json
    
    # Project情報のURL
    strUrl = 'http://localhost:3000/projects.json'
    
    # requestsヘッダ
    dicHead = {
        'X-Redmine-API-Key': '8dc1f63aeうんぬん',
        'Content-Type': 'application/json'
    }
    
    # requests get実行
    resProjects = requests.get(strUrl, headers=dicHead)
    
    # 実行ステータス取得
    print(f"request_status=[{resProjects.status_code}]")
    
    # 情報表示
    if resProjects.status_code < 300:
      # request response jsonデータをdicへ変換
        dicProjects = resProjects.json()
      # dicデータを表示用jsonへ整形変換
        jsoProjects = json.dumps(dicProjects, indent=2, ensure_ascii=False)
      # project情報表示
        print(jsoProjects)
    
    >test0.py
    request_status=[200]
    {
      "projects": [
        {
          "id": 1,
          "name": "Sandbox",
          "identifier": "sandbox",
          "description": "Test project",
          ...中略...
        }
      ],
      "total_count": 1,
      "offset": 0,
      "limit": 25
    }
    
  • サンプルは1個なのでわかりにくいですが、取得したjsonデータを見ると、'projects'はリストのデータになります。Projectの識別子は各リスト要素のdicデータから 'identifier'キーで取得することができます。

  • 大きなRedmineになるとProject数も増えると思いますが、一度のgetで得られるのはデフォルト25です。ここも issues と同じように 'total_count' が25を超える場合は 'offset' と 'limit' パラメータを操作してください。

Project毎Wikiページ名リストの取得
  • Projectの識別名を取得することでWikiページの情報へアクセスするURLを確定させることができます。今回の例では 'sandbox' がProject識別名です。Project毎のWikiページ名リスト取得コードは下記です。
  • import requests
    import json
    
    # Project毎Wikiページ名情報のURL
    strProjId = 'sandbox'
    strUrl = f"http://localhost:3000/projects/{strProjId}/wiki/index.json"
    
    # requestsヘッダ
    dicHead = {
        'X-Redmine-API-Key': '8dc1f63aうんぬん',
        'Content-Type': 'application/json'
    }
    
    # requests get実行
    resWikis = requests.get(strUrl, headers=dicHead)
    
    # 実行ステータス取得
    print(f"request_status=[{resWikis.status_code}]")
    
    # 情報表示
    if resWikis.status_code < 300:
      # request response jsonデータをdicへ変換
        dicWikis = resWikis.json()
      # dicデータを表示用jsonへ整形変換
        jsoWikis = json.dumps(dicWikis, indent=2, ensure_ascii=False)
      # Wiki情報表示
        print(jsoWikis)
    
    >test1.py
    request_status=[200]
    {
      "wiki_pages": [
        {
          "title": "Sub_page_0",
          "parent": {
            "title": "Wiki"
          },
          "version": 1,
          "created_on": "2025-06-13T04:36:33Z",
          "updated_on": "2025-06-13T04:36:33Z"
        },
        {
          "title": "Wiki",
          "version": 1,
          "created_on": "2025-06-13T04:31:21Z",
          "updated_on": "2025-06-13T04:31:21Z"
        }
      ]
    }
    
  • 'wiki_pages'リストとしてデータ取得できますが、Wikiページ識別名のキーが'title'なのは御愛嬌ということで。

  • ちなみにProject SandboxのWikiは下記のようになっています。

Wikiページ記述情報の取得
  • Project及びWikiページの識別子が取得できれば、次は記述内容の取得です。
  • import requests
    import json
    
    # WikiページのURL
    strProjId = 'sandbox'
    strWikiId = 'Sub_page_0'
    strUrl = f"http://localhost:3000/projects/{strProjId}/wiki/{strWikiId}.json"
    
    # requestsヘッダ
    dicHead = {
        'X-Redmine-API-Key': '8dc1f63aeうんぬん',
        'Content-Type': 'application/json'
    }
    
    # requests get実行
    resWiki = requests.get(strUrl, headers=dicHead)
    
    # 実行ステータス取得
    print(f"request_status=[{resWiki.status_code}]")
    
    # 情報表示
    if resWiki.status_code < 300:
      # request response jsonデータをdicへ変換
        dicWiki = resWiki.json()
      # dicデータを表示用jsonへ整形変換
        jsoWiki = json.dumps(dicWiki, indent=2, ensure_ascii=False)
      # Wiki記述情報表示
        print(jsoWiki)
    
    >test2.py
    request_status=[200]
    {
      "wiki_page": {
        "title": "Sub_page_0",
        "parent": {
          "title": "Wiki"
        },
        "text": "# Project: Sandobox: Sub wiki page [0]\r\n* サブWikiページ[0]",
        "version": 1,
        "author": {
          "id": 5,
          "name": "Altmo Test"
        },
        "comments": "",
        "created_on": "2025-06-13T04:36:33Z",
        "updated_on": "2025-06-13T04:36:33Z"
      }
    }
    
  • 'text'キーで記述内容を取得できることがわかりますね。ちなみに下記のようなページです

Wikiページ記述の変更
  • Wiki記述の情報をget後、'text'キーの値を変更してputします。
  • import requests
    import json
    
    # WikiページのURL
    strProjId = 'sandbox'
    strWikiId = 'Sub_page_0'
    strUrl = f"http://localhost:3000/projects/{strProjId}/wiki/{strWikiId}.json"
    
    # requestsヘッダ
    dicHead = {
        'X-Redmine-API-Key': '8dc1f63aeうんぬん',
        'Content-Type': 'application/json'
    }
    
    # requests get実行
    resWiki = requests.get(strUrl, headers=dicHead)
    
    # 実行ステータス取得
    print(f"request_get_status=[{resWiki.status_code}]")
    
    # 取得jsonデータをdicに変換
    dicWiki = resWiki.json()
    
    # 変更前記述表示
    print(f"変更前記述:\n{dicWiki['wiki_page']['text']}")
    
    # textキーの内容を変更
    dicWiki['wiki_page']['text'] += "\n* REST APIで追加した記述"
    print(f"変更後記述:\n{dicWiki['wiki_page']['text']}")
    
    # putのためにdicデータをjsonへ変換
    jsoWiki = json.dumps(dicWiki)
    
    # requests put実行
    resWikiPut = requests.put(strUrl, headers=dicHead, data=jsoWiki)
    
    # ステータス表示
    print(f"request_put_status=[{resWikiPut.status_code}]")
    
    >test3.py
    request_get_status=[200]
    変更前記述:
    # Project: Sandobox: Sub wiki page [0]
    * サブWikiページ[0]
    変更後記述:
    # Project: Sandobox: Sub wiki page [0]
    * サブWikiページ[0]
    * REST APIで追加した記述
    request_put_status=[204]
    
  • 実際にアクセスすると、変更の反映が確認できます。

Wikiページの追加
  • Wikiページの新規追加ですが、HTTP requestメソッドは新規追加だから post だと思いますよね。実は違います。新規作成するWikiページも putメソッド を使います

  • RedmineでWikiページを手編集で作る場合、とりあえずリンクを作ってクリックすれば編集できますよね。


  • 例えば上記のようにまだ存在していないページ(Sub_page_1)をクリックすると下記編集画面になります。


  • URLを見ると、新規ページのURLになっています。つまりWikiページについてはRequestすると常にアクセス先が用意されるので、postではなくputを使うことになります。


  • REST APIでWikiページを追加するコード例です。親Wikiページ指定に 'parent_title'キー を使う点がハマりやい(*1)です。
  • import requests
    import json
    
    # 新規追加でもWikiページを含むURLを設定
    strProjId = 'sandbox'
    strWikiId = 'Sub_page_1'
    strUrl = f"http://localhost:3000/projects/{strProjId}/wiki/{strWikiId}.json"
    print(f"new_wiki_url:[{strUrl}]")
    
    # requestsヘッダ
    dicHead = {
        'X-Redmine-API-Key': '8dc1f63aうんぬん',
        'Content-Type': 'application/json'
    }
    
    # Wikiのdicデータ作成
    dicWiki = {
        'wiki_page': {
            'text': "# Project: Sandbox: Sub wiki page [1]\n* REST APIで追加",
            'parent_title': 'Wiki'
        }
    }
    
    # 記述内容表示
    print(f"記述内容:\n{dicWiki['wiki_page']['text']}")
    
    # dicデータをjsonに変換
    jsoWiki = json.dumps(dicWiki)
    
    # requests put実行 (新規Wikiでもpostではなくput)
    resWiki = requests.put(strUrl, headers=dicHead, data=jsoWiki)
    
    # 実行ステータス取得
    print(f"request_status=[{resWiki.status_code}]")
    
    >test4.py
    new_wiki_url:[http://localhost:3000/projects/sandbox/wiki/Sub_page_1.json]
    記述内容:
    # Project: Sandbox: Sub wiki page [1]
    * REST APIで追加
    request_status=[201]
    
  • 親ページにアクセスすると、Sub_page_1へのリンクが有効になっています。


  • 中身も入っていますね。

Wikiページの削除
  • Wikiページの削除は、WikiのURLでdeleteメソッドを実行するだけです。先ほど作成したSub_page_1を削除してみます。
  • import requests
    import json
    
    # 削除対象WikiページのURLを設定
    strProjId = 'sandbox'
    strWikiId = 'Sub_page_1'
    strUrl = f"http://localhost:3000/projects/{strProjId}/wiki/{strWikiId}.json"
    print(f"delete_wiki_url:[{strUrl}]")
    
    # requestsヘッダ
    dicHead = {
        'X-Redmine-API-Key': '8dc1f63aeうんぬん',
        'Content-Type': 'application/json'
    }
    
    # requests delete実行
    resWiki = requests.delete(strUrl, headers=dicHead)
    
    # 実行ステータス取得
    print(f"request_status=[{resWiki.status_code}]")
    
    >test5.py
    delete_wiki_url:[http://localhost:3000/projects/sandbox/wiki/Sub_page_1.json]
    request_status=[204]
    


次回
  • 次回はRedmine REST APIに関する最後のレポートになりますが、添付ファイルを扱う予定です。
Notes
  1. 公式ページに書いていません。https://www.redmine.org/issues/14829 だけです...
2025-06-14: 初版
2025-06-15: 添付ファイルの記述を移動
Copyright(C) 2025 Altmo
本HPについて