From 504d13ed089dae819157075df1d0cbc0332251d7 Mon Sep 17 00:00:00 2001 From: Andriy Oblivantsev Date: Tue, 15 Sep 2026 07:19:42 +0000 Subject: [PATCH] fix(files): UpdateFile uses PUT /api/2.0/files/{id}/update (#25) --- files.go | 30 +++++++++++++++++++++--------- http.go | 10 +++++++++- 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/files.go b/files.go index 3fe2ea3..767d5d6 100644 --- a/files.go +++ b/files.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "io" + "net/http" "net/url" "path" "strconv" @@ -357,20 +358,31 @@ func (c *Client) UploadToFolder(ctx context.Context, folderID, localPath string) // UpdateFile uploads a new version of an existing file (same id, name and // folder). It does not delete and does not create a second file. +// +// The Documents API method is PUT /api/2.0/files/{id}/update; POST is kept as +// a fallback for older servers. The path is tried with and without .json. func (c *Client) UpdateFile(ctx context.Context, fileID, localPath string) (*FileEntry, error) { if fileID == "" || localPath == "" { return nil, fmt.Errorf("file id and local path are required") } - uploadPath := fmt.Sprintf("/api/2.0/files/%s/update", url.PathEscape(fileID)) - raw, err := c.uploadMultipart(ctx, uploadPath, "file", localPath) - if err != nil { - uploadPath = fmt.Sprintf("/api/2.0/files/%s/update.json", url.PathEscape(fileID)) - raw, err = c.uploadMultipart(ctx, uploadPath, "file", localPath) - if err != nil { - return nil, err - } + base := fmt.Sprintf("/api/2.0/files/%s/update", url.PathEscape(fileID)) + attempts := []struct { + method, path string + }{ + {http.MethodPut, base}, + {http.MethodPut, base + ".json"}, + {http.MethodPost, base}, + {http.MethodPost, base + ".json"}, } - return decodeResponseFileEntry(raw) + var lastErr error + for _, a := range attempts { + raw, err := c.uploadMultipartMethod(ctx, a.method, a.path, "file", localPath) + if err == nil { + return decodeResponseFileEntry(raw) + } + lastErr = err + } + return nil, lastErr } // FileFolderID returns the parent folder id string for a file entry, if known. diff --git a/http.go b/http.go index ac55efd..5cf8787 100644 --- a/http.go +++ b/http.go @@ -346,6 +346,14 @@ func (c *Client) putJSON(ctx context.Context, path string, body any) (json.RawMe // uploadMultipart posts a single file to path under the given form field name. func (c *Client) uploadMultipart(ctx context.Context, path, fieldName, filePath string) (json.RawMessage, error) { + return c.uploadMultipartMethod(ctx, http.MethodPost, path, fieldName, filePath) +} + +// uploadMultipartMethod sends a single-file multipart request with the given +// HTTP method. The OnlyOffice Documents API needs PUT for /update (a new +// version) and POST for /upload (a new file); sending POST to /update answers +// 500 on current servers. +func (c *Client) uploadMultipartMethod(ctx context.Context, method, path, fieldName, filePath string) (json.RawMessage, error) { auth, err := c.authHeader() if err != nil { return nil, err @@ -368,7 +376,7 @@ func (c *Client) uploadMultipart(ctx context.Context, path, fieldName, filePath if err := mw.Close(); err != nil { return nil, err } - req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.baseURL()+path, &buf) + req, err := http.NewRequestWithContext(ctx, method, c.baseURL()+path, &buf) if err != nil { return nil, err }