nylas / nylas/nylas-python

drafts.create() fails with "only JSON and multipart supported" error since v6.13.1

オープン
#455 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

bug
主要言語
Python
スター
109
フォーク
85
平均マージ
1日 21時間
マージ済み PR(30日)
1

説明

Describe the bug

Draft creation fails with NylasApiError: only JSON and multipart supported when using the Nylas Python SDK v6.13.1+. The Nylas API returns
a 400 error rejecting the draft creation request, even though the request appears to be properly formatted JSON.

Root Cause:

In v6.13.1 (commit d226ff113a62, PR #442), the HTTP client was changed to manually serialize JSON using json.dumps(request_body,
ensure_ascii=False) and pass it via the data= parameter instead of using the json= parameter in requests.request(). While this fixed UTF-8
encoding for multipart requests, it appears to have broken JSON-only requests for draft creation.

The issue is that when using data=json_string instead of json=dict, the requests library doesn't automatically set the correct
Content-Type header, or the manually added application/json; charset=utf-8 header is not being accepted by the Nylas API for draft
creation.

To Reproduce
from nylas import Client                                                                                                                  
 from nylas.models.drafts import CreateDraftRequest                                                                                        
                                                                                                                                           
 # Initialize client                                                                                                                       
 nylas = Client(api_key="your_api_key", api_uri="https://api.us.nylas.com")                                                                
                                                                                                                                           
 # Attempt to create a draft                                                                                                               
 draft_request = CreateDraftRequest(                                                                                                       
     to=[{"email": "recipient@example.com"}],                                                                                              
     subject="Test Subject",                                                                                                               
     body="Test body content"                                                                                                              
 )                                                                                                                                         
                                                                                                                                           
 try:                                                                                                                                      
     # This will fail with "only JSON and multipart supported"                                                                             
     response = nylas.drafts.create(                                                                                                       
         grant_id="your_grant_id",                                                                                                         
         request_body=draft_request                                                                                                        
     )                                                                                                                                     
 except Exception as e:                                                                                                                    
     print(f"Error: {e}")                                                                                                                  
     # Output: NylasApiError: only JSON and multipart supported                   
Expected behavior

The draft should be created successfully without errors. The Nylas API should accept the JSON request and return the created draft object.

Workaround:

Bypass the SDK's drafts.create() method and use requests directly with the json= parameter:

import requests                                                                                                                           
from nylas.models.response import Response                                                                                                
from nylas.models.drafts import Draft                                                                                                     
                                                                                                                                          
# Get API credentials from the SDK client                                                                                                 
api_server = nylas.drafts._http_client.api_server                                                                                         
api_key = nylas.drafts._http_client.api_key                                                                                               
                                                                                                                                          
url = f"{api_server}/v3/grants/{grant_id}/drafts"                                                                                         
headers = {                                                                                                                               
    "Authorization": f"Bearer {api_key}",                                                                                                 
    "X-Nylas-API-Wrapper": "python",                                                                                                      
}                                                                                                                                         
                                                                                                                                          
# Use requests directly with json= parameter                                                                                              
http_response = requests.post(url, headers=headers, json=draft_request_dict, timeout=30)                                                  
                                                                                                                                          
if http_response.status_code >= 400:                                                                                                      
    raise Exception(f"Draft creation failed: {http_response.json()}")                                                                     
                                                                                                                                          
draft_data = http_response.json()                                                                                                         
response = Response.from_dict(draft_data, Draft, http_response.headers)                            

This workaround succeeds because requests.post() with json=dict properly handles Content-Type headers.

SDK Version:
  • Broken: v6.13.1 and later (including v6.13.1, v6.14.0, v6.14.1, v6.14.2)
  • Last working: v6.13.0 and earlier
Additional context

The breaking change was introduced in commit d226ff113a62 (PR #442) which modified nylas/handler/http_client.py:

  • Changed from: requests.request(..., json=request_body, data=data)
  • Changed to: requests.request(..., data=json_data or data) where json_data = json.dumps(request_body, ensure_ascii=False)
  • Changed Content-Type header from application/json to application/json; charset=utf-8

While PR #442 successfully fixed UTF-8 encoding issues for multipart requests with large attachments, it appears to have broken standard
JSON requests for draft creation. The requests library handles the json= parameter differently than data= with a pre-serialized JSON
string, particularly regarding header management.

Suggested Fix:

Consider using json= parameter for JSON-only requests and data= with manual serialization only for multipart/form-data requests where
UTF-8 encoding is needed.

コントリビューションガイド

コントリビューションガイドを開く

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

調査の方向性

nylas/handler/http_client.py と drafts.create() で使用されるリクエストパスを読み、json= パラメーターから手動でシリアライズされたデータへの変更に注目してください。提供されたドラフト作成の再現手順を実行し、JSON ドラフトリクエストが成功すること、および PR #442 で対処された multipart の動作が維持されていることを確認してください。

索引モデルが issue の本文から書いたものです。

評価

技術スタック
python
領域
api
issue の種類
バグ
難易度
2/5
見積もり時間
1〜3時間
活発さ
停滞
明瞭さ
明確に書かれている
初心者へのやさしさ
48/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。