投稿を編集する際の正しい`content-type`は何ですか?

みなさん、こんにちは。API を通じて投稿を更新する際、Content-Typeapplication/json を使用することは可能でしょうか?ドキュメント では可能と書かれていますが、実際にはできないのではないかと思い始めています。

常に [\"BAD CSRF\"] というエラーが返され、その意味が全くわかりません。


もし multipart/form-data を使用する必要がある場合、PUT リクエスト(特に data の部分)をどのように構築すればよいか、ご教示いただけますでしょうか。

header = CaseInsensitiveDict()
header["Authorization"] = '{"api-key": "longapikey", "api-username": "myusername"}'
{
  "post": {
      "raw": "Cool post, but here's an updated to the post's body",
      "edit_reason": "I changed this because I can."
   }
}

resp = requests.put(url, headers=headers, data=data)

よろしくお願いいたします。

Api-Key と Api-Username は、Authorization ヘッダーの中に含めるのではなく、それぞれ独立したヘッダーとして送信する必要があります。以下のようにすると、よりうまくいくはずです。

header = CaseInsensitiveDict()
header["Api-Key"] = 'longapikey'
header["Api-Username"] = 'myusername'

これは、あなたの前のトピックと同じ問題のようです。

「いいね!」 2

返信ありがとうございます、David。

とても奇妙なことに、あなたが示した方法でヘッダーをフォーマットすると、以下のエラーが表示されます:

{"errors":["You are not permitted to view the requested resource. The API username or key is invalid."],"error_type":"invalid_access"}

しかし、["Authorization"] を追加すると、正常に動作します。

これは単純な GET リクエストの場合の話ですが、PUT リクエストはまだうまくいきません。

ある操作で機能するヘッダーは、(キーがグローバルであることが前提ですが)すべての操作で機能するはずだと期待していました。そのため、現時点ではヘッダーについてはあまり心配していません。ただ、気にするべきでしょうか?

ありがとうございます!

GET リクエストが、Authorization ヘッダーの扱いを誤っているにもかかわらず動作しているなら、おそらく PUT リクエストに何か不正な部分があるのでしょう。GET リクエストはそもそも認証が不要なため動作しています。ヘッダーを渡しても、当方は Authorization ヘッダーを確認することすらありません。パブリックエンドポイントへの GET リクエストは、ヘッダーなしでも問題なく動作します。

「いいね!」 1

@pedroleaoc 認証付きリクエストの作成方法と、PUT/POST リクエストでリクエストデータを送信する方法を示す、小さな Python スクリプトのサンプルです。

# discourse-api-demo.py
import requests
from requests.structures import CaseInsensitiveDict

# ヘッダー不要なパブリック URL への基本的な GET リクエスト
url = "http://localhost:3000/posts/10.json"

resp = requests.get(url)

print(resp.status_code)
print(resp.content)

# 認証ヘッダーが必要なプライベートエンドポイントへの GET リクエスト
url = "http://localhost:3000/admin/users/list/active.json"
headers = {'Api-Username': 'system', 'Api-Key': '5c1c57915e2...'}
resp = requests.get(url, headers=headers)

print(resp.status_code)
print(resp.content)

# リクエストボディ付きの PUT リクエスト
url = "http://localhost:3000/posts/10.json"
data = { 'raw': "Cool post, but here's an updated to the post's body", 'edit_reason': "I changed this because I can." }

resp = requests.put(url, headers=headers, json=data)
print(resp.status_code)
print(resp.content)

Quickstart — Requests 2.33.1 documentation より

dict を自分でエンコードする代わりに、json パラメータ(バージョン 2.4.2 で追加)を直接使用して渡すこともできます。これにより自動的にエンコードされます:

url = 'https://api.github.com/some/endpoint' >>> payload = {'some': 'data'} >>> r = requests.post(url, json=payload)

なお、data または files のいずれかが渡された場合、json パラメータは無視されます。

リクエストで json パラメータを使用すると、ヘッダー内の Content-Typeapplication/json に変更されます。

「いいね!」 1

ああ、そっか!GETリクエストすべてにAuthorizationが必要ってわけじゃないんだ!
そんな貴重なヒントをありがとう、調べてみるね。感謝!

リバースエンジニアリングですでにわかっていること:

  • api_key ではなく api-key
  • PUT リクエストには "content-type": "application/x-www-form-urlencoded" が必要
  • データはJSONではない(暗号化されているが、正しいエンコーディングがまだ見つからない)

この直前の私の投稿をご覧ください。リクエストで data=data 形式の代わりに json=data を使用すると、Python の requests ライブラリが content-type を自動的に処理し、application/json に設定してくれます。これが使用するべき形式です。

「いいね!」 2

素晴らしい、これで投稿を編集できるようになりました!お手伝いいただきありがとうございます。

残るはもう一つの問題です。現在使用しているキーは global です。writeread の権限のみを持つキーで試すと、「指定されたリソースを表示する権限がありません。API ユーザー名またはキーが無効です」というエラーになります。GUI を通じて投稿を編集すると、実際に投稿を編集する posts/post_id.json へのリクエストとは別に、トピックの URL への PUT リクエストが発生しているようですが、これは制限付きの API キーでは再現できず、global キーでのみ発生します。しかし、なぜか、この GUI 側で発生する余分な PUT リクエストがなくても、API を通じて投稿を編集できない理由がわかりません。

追記:技術的には、私の API キーは PUT リクエストが向かっている /t/:slug/:topic_id をカバーしています。

API キーに「投稿の編集」スコープが選択されていますか?

いいえ!そのオプションは私にはありません!確認してみます。またもやご助力いただき、ありがとうございます。

「いいね!」 1

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.