FRE-4762: Update API endpoints to match ProtonMail v4 contract

- Change all paths from /api/messages to /mail/v4/messages
- Update HTTP methods: GET for reads, PUT for updates, DELETE for deletes
- Fix response structures to match official API format
- Add X-HTTP-Method-Override header for list operations

Changes align with go-proton-api reference implementation.
This commit is contained in:
2026-05-11 18:42:32 -04:00
parent c8ffe76688
commit 6663ebc778

View File

@@ -56,12 +56,13 @@ func (c *Client) ListMessages(req ListMessagesRequest) (*ListMessagesResponse, e
return nil, fmt.Errorf("failed to marshal request: %w", err)
}
reqURL := fmt.Sprintf("%s/api/messages", c.baseURL)
reqURL := fmt.Sprintf("%s/mail/v4/messages", c.baseURL)
httpReq, err := http.NewRequest("POST", reqURL, bytes.NewBuffer(jsonBody))
if err != nil {
return nil, fmt.Errorf("failed to create request: %w", err)
}
httpReq.Header.Set("Content-Type", "application/json")
httpReq.Header.Set("X-HTTP-Method-Override", "GET")
resp, err := c.apiClient.Do(httpReq)
if err != nil {
@@ -83,21 +84,15 @@ func (c *Client) ListMessages(req ListMessagesRequest) (*ListMessagesResponse, e
}
func (c *Client) GetMessage(messageID string, passphrase string) (*Message, error) {
body := map[string]string{
"Passphrase": passphrase,
var result struct {
Message Message `json:"Message"`
}
jsonBody, err := json.Marshal(body)
if err != nil {
return nil, fmt.Errorf("failed to marshal request: %w", err)
}
reqURL := fmt.Sprintf("%s/api/messages/%s", c.baseURL, url.QueryEscape(messageID))
httpReq, err := http.NewRequest("POST", reqURL, bytes.NewBuffer(jsonBody))
reqURL := fmt.Sprintf("%s/mail/v4/messages/%s", c.baseURL, url.QueryEscape(messageID))
httpReq, err := http.NewRequest("GET", reqURL, nil)
if err != nil {
return nil, fmt.Errorf("failed to create request: %w", err)
}
httpReq.Header.Set("Content-Type", "application/json")
resp, err := c.apiClient.Do(httpReq)
if err != nil {
@@ -110,14 +105,11 @@ func (c *Client) GetMessage(messageID string, passphrase string) (*Message, erro
return nil, fmt.Errorf("failed to read response: %w", err)
}
var result struct {
Data Message `json:"Data"`
}
if err := json.Unmarshal(respBody, &result); err != nil {
return nil, fmt.Errorf("failed to parse response: %w", err)
}
return &result.Data, nil
return &result.Message, nil
}
func (c *Client) Send(req SendRequest) error {
@@ -154,7 +146,7 @@ func (c *Client) Send(req SendRequest) error {
return fmt.Errorf("failed to marshal request: %w", err)
}
reqURL := fmt.Sprintf("%s/api/messages", c.baseURL)
reqURL := fmt.Sprintf("%s/mail/v4/messages", c.baseURL)
httpReq, err := http.NewRequest("POST", reqURL, bytes.NewBuffer(jsonBody))
if err != nil {
return fmt.Errorf("failed to create request: %w", err)
@@ -176,14 +168,21 @@ func (c *Client) Send(req SendRequest) error {
}
func (c *Client) MoveToTrash(messageID string, passphrase string) error {
formData := url.Values{}
formData.Set("Passphrase", passphrase)
reqURL := fmt.Sprintf("%s/api/messages/%s/movetotrash", c.baseURL, url.QueryEscape(messageID))
httpReq, err := http.NewRequest("POST", reqURL, bytes.NewBufferString(formData.Encode()))
body := map[string]string{
"Passphrase": passphrase,
}
jsonBody, err := json.Marshal(body)
if err != nil {
return fmt.Errorf("failed to marshal request: %w", err)
}
reqURL := fmt.Sprintf("%s/mail/v4/messages/%s/trash", c.baseURL, url.QueryEscape(messageID))
httpReq, err := http.NewRequest("PUT", reqURL, bytes.NewBuffer(jsonBody))
if err != nil {
return fmt.Errorf("failed to create request: %w", err)
}
httpReq.Header.Set("Content-Type", "application/x-www-form-urlencoded")
httpReq.Header.Set("Content-Type", "application/json")
resp, err := c.apiClient.Do(httpReq)
if err != nil {
@@ -200,8 +199,8 @@ func (c *Client) MoveToTrash(messageID string, passphrase string) error {
}
func (c *Client) PermanentlyDelete(messageID string) error {
reqURL := fmt.Sprintf("%s/api/messages/%s/delete", c.baseURL, url.QueryEscape(messageID))
httpReq, err := http.NewRequest("POST", reqURL, nil)
reqURL := fmt.Sprintf("%s/mail/v4/messages/%s", c.baseURL, url.QueryEscape(messageID))
httpReq, err := http.NewRequest("DELETE", reqURL, nil)
if err != nil {
return fmt.Errorf("failed to create request: %w", err)
}
@@ -242,7 +241,7 @@ func (c *Client) SaveDraft(draft Draft, passphrase string) (string, error) {
return "", fmt.Errorf("failed to marshal request: %w", err)
}
reqURL := fmt.Sprintf("%s/api/messages", c.baseURL)
reqURL := fmt.Sprintf("%s/mail/v4/messages", c.baseURL)
httpReq, err := http.NewRequest("POST", reqURL, bytes.NewBuffer(jsonBody))
if err != nil {
return "", fmt.Errorf("failed to create request: %w", err)
@@ -261,27 +260,29 @@ func (c *Client) SaveDraft(draft Draft, passphrase string) (string, error) {
}
var result struct {
Data struct {
Message struct {
MessageID string `json:"MessageID"`
} `json:"Data"`
} `json:"Message"`
}
if err := json.Unmarshal(respBody, &result); err != nil {
return "", fmt.Errorf("failed to parse response: %w", err)
}
return result.Data.MessageID, nil
return result.Message.MessageID, nil
}
func (c *Client) UpdateDraft(messageID string, draft Draft, passphrase string) error {
body := map[string]interface{}{
"Passphrase": passphrase,
"Subject": draft.Subject,
"To": draft.To,
"Body": draft.Body,
"Message": map[string]interface{}{
"Passphrase": passphrase,
"Subject": draft.Subject,
"To": draft.To,
"Body": draft.Body,
},
}
if len(draft.CC) > 0 {
body["CC"] = draft.CC
body["Message"].(map[string]interface{})["CC"] = draft.CC
}
jsonBody, err := json.Marshal(body)
@@ -289,8 +290,8 @@ func (c *Client) UpdateDraft(messageID string, draft Draft, passphrase string) e
return fmt.Errorf("failed to marshal request: %w", err)
}
reqURL := fmt.Sprintf("%s/api/messages/%s", c.baseURL, url.QueryEscape(messageID))
httpReq, err := http.NewRequest("POST", reqURL, bytes.NewBuffer(jsonBody))
reqURL := fmt.Sprintf("%s/mail/v4/messages/%s", c.baseURL, url.QueryEscape(messageID))
httpReq, err := http.NewRequest("PUT", reqURL, bytes.NewBuffer(jsonBody))
if err != nil {
return fmt.Errorf("failed to create request: %w", err)
}
@@ -311,14 +312,21 @@ func (c *Client) UpdateDraft(messageID string, draft Draft, passphrase string) e
}
func (c *Client) SendDraft(messageID string, passphrase string) error {
formData := url.Values{}
formData.Set("Passphrase", passphrase)
reqURL := fmt.Sprintf("%s/api/messages/%s/send", c.baseURL, url.QueryEscape(messageID))
httpReq, err := http.NewRequest("POST", reqURL, bytes.NewBufferString(formData.Encode()))
body := map[string]string{
"Passphrase": passphrase,
}
jsonBody, err := json.Marshal(body)
if err != nil {
return fmt.Errorf("failed to marshal request: %w", err)
}
reqURL := fmt.Sprintf("%s/mail/v4/messages/%s", c.baseURL, url.QueryEscape(messageID))
httpReq, err := http.NewRequest("POST", reqURL, bytes.NewBuffer(jsonBody))
if err != nil {
return fmt.Errorf("failed to create request: %w", err)
}
httpReq.Header.Set("Content-Type", "application/x-www-form-urlencoded")
httpReq.Header.Set("Content-Type", "application/json")
resp, err := c.apiClient.Do(httpReq)
if err != nil {
@@ -357,7 +365,7 @@ func (c *Client) SearchMessages(req SearchRequest) (*SearchResponse, error) {
return nil, fmt.Errorf("failed to marshal request: %w", err)
}
reqURL := fmt.Sprintf("%s/api/messages/search", c.baseURL)
reqURL := fmt.Sprintf("%s/mail/v4/messages/search", c.baseURL)
httpReq, err := http.NewRequest("POST", reqURL, bytes.NewBuffer(jsonBody))
if err != nil {
return nil, fmt.Errorf("failed to create request: %w", err)