fix(api): handle 204 No Content в apiFetch (#1219) #1249
No reviewers
Labels
No labels
admin
analytics
auth
automation
bug
business
chore
ci
compliance
data
data-moat
docs
duplicate
dx
enhancement
Fable 5 ревью
feedback/max
generative
GG-форсайт
needs-discussion
needs-human
observability
pause-bots
performance
priority/p0
priority/p1
priority/p2
priority/p3
scope/backend
scope/db
scope/devops
scope/frontend
scope/qa
scrapers
security
site-finder
stage/1
stage/2
status/blocked
status/done
status/needs-analysis
status/needs-fix
status/qa
status/ready
status/review
status/wip
tech-debt
tradein
ux
week ревью 1
wontfix
вторичка
ИРД
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: lekss361/gendesign#1249
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "fix/api-fetch-204-no-content"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Closes #1219 (P2 silent prod-bug).
apiFetchбезусловно звалresponse.json()на пустом теле 204 → SyntaxError → mutation реджектится →onSuccess/invalidateQueriesне срабатывают → POI/профиль виден в UI до случайного рефетча.Воспроизведение
DELETE /api/v1/custom-pois/{id}→ backend отдаёт 204 пустой body.useDeleteCustomPoi→apiFetch<unknown>(...)→response.json()на""→SyntaxError: Unexpected end of JSON input.useMutationpromise rejects →onSuccessне вызывается →queryClient.invalidateQueries(['custom-pois'])не выполняется.staleTime: 5min,refetchOnWindowFocus: false). 100% repro.Что в PR
В
apiFetchпосле!response.ok-check добавлена обработка 204 / пустого тела:Семантика выровнена с уже существующим
apiFetchWithStatus. СигнатураPromise<T>сохранена — 80 не-204 callers backward-compatible; DELETE-хуки уже типизированы<unknown>/<void>и игнорируют возврат.Альтернатива (отклонена)
Перевести
useDeleteCustomPoi/useDeleteProfileнаapiFetchWithStatus— больше изменений по чужим файлам, без выигрыша. Fix в одном месте лучше.Test plan
npx vitest run src/lib/__tests__/api.test.ts→ 6 / 6 green (3 ms). Кейсы: 204 No Content, regression guard, 200+JSON, 200+empty-body edge case, 404, 500.npm run test(full) → 73 / 73 green, никаких регрессий.npx tsc --noEmit→ clean.npm run lint→ no warnings/errors.Closes #1219
apiFetch безусловно звал response.json() после !response.ok-check, что падало SyntaxError'ом на пустом теле 204. DELETE /custom-pois/{id} и DELETE /admin/site-finder/weight-profiles/{id} объявлены status_code=204 → mutation promise реджектился → onSuccess/invalidateQueries не срабатывали → POI/профиль виден в UI до случайного рефетча, хотя реально удалён на сервере. Silent fail для DELETE кастомных POI на SiteMap (#1219, P2). Fix: на 204 или пустом теле resolve'имся с undefined (аналог семантики apiFetchWithStatus). Сигнатура Promise<T> сохранена — 80 не-204 callers backward-compatible; два DELETE-хука уже типизированы <unknown>/<void> и корректно игнорируют возврат. 6 новых vitest кейсов (api.test.ts): 204, empty-body-200, 200+JSON, 404, 500, regression guard. 73/73 frontend тестов зелёные, lint+tsc clean. Closes #1219