Files
webshare-api/doc/structure/ui-api.md
Michal Pemcak 99dcb298f8 feat(queue): 404 on unknown hash, show error in UI
POST /api/queue/cancel answers 404 {"error":"hash not in queue"} for
untracked hashes instead of 200 ok:true. The UI surfaces the server's
error message instead of swallowing it.
2026-10-19 19:14:15 +02:00

2.6 KiB

type, title, description, tags, timestamp
type title description tags timestamp
API Web UI JSON API The UI-facing JSON routes served by src/ui-api.js (search, queue add/list/cancel), the 404-on-cancel contract, and the UI error surfacing.
api
ui
queue
express
2026-10-19T00:00:00Z

Web UI JSON API

The Web UI talks to the app over four JSON routes registered by registerUiApi(app, { qbt, client }) in src/ui-api.js, which src/index.js mounts before static file serving so /api/* is never swallowed. __tests__/ui-api.test.js covers all four routes.

Route Success Error
GET /api/search?q=… 200 result array ([] when q is empty) 500 {error} when the Webshare client fails
POST /api/queue/add 200 {ok: true} 400 {error: 'ident required'}, 409 {error: 'already in queue'}, 500 {error}
GET /api/queue 200 queue array 500 {error}
POST /api/queue/cancel 200 {ok: true} 400 {error: 'hash required'}, 404 {error: 'hash not in queue'} when the hash is not in the queue, 500 {error}

Cancel returns 404 for unknown hashes

POST /api/queue/cancel honors the return value of qbt.cancelDownload(hash) (see Project Overview), which is a boolean: false means no queued download matched the hash, and the route responds 404 {error: 'hash not in queue'}. Before this, the route always answered 200 {ok: true} even when nothing was cancelled.

The 404 body message is deliberately human-readable — the UI surfaces error verbatim (below), and a raw body read is still intelligible.

The UI surfaces the error

apiFetch in ui/scripts.js parses a failed response's JSON body when content-type is application/json and throws new Error(data.error) (falling back to the raw text or HTTP <status> for non-JSON or malformed bodies). The cancel-button handler then shows the failure inline as a transient [err] button state (re-enabled after 2 s) instead of swallowing it in catch {}; the 2 s queue poll repaints the row. This mirrors the established inline-error pattern of the add button — the codebase has no toasts or alerts.

The fake qBittorrent API is intentionally different

The fake qBittorrent Web API in src/qbt.js (POST /api/v2/torrents/delete and friends) was not changed: it answers Ok. for real qBittorrent-API clients such as Sonarr, whose contract is always Ok., and Sonarr deletes finished entries — a 404 there would break it. The two APIs serve different consumers and keep different error contracts on purpose.