fix(iot): 409 различает конфликт name vs device_id (ревью)
store.Create классифицирует 23505 по имени constraint: (namespace,device_id) → ErrDeviceIDExists, иначе ErrAlreadyExists. Handler отдаёт разные 409-сообщения. Помогает Terraform понять, какое поле конфликтует.
This commit is contained in:
@@ -215,6 +215,10 @@ func (h *Handler) CreateIoTDevice(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
if err := h.Devices.Create(r.Context(), device); err != nil {
|
||||
if errors.Is(err, store.ErrDeviceIDExists) {
|
||||
writeJSON(w, http.StatusConflict, errResp("device_id already exists in this namespace"))
|
||||
return
|
||||
}
|
||||
if errors.Is(err, store.ErrAlreadyExists) {
|
||||
writeJSON(w, http.StatusConflict, errResp("iot device already exists"))
|
||||
return
|
||||
|
||||
@@ -15,6 +15,10 @@ var ErrNotFound = errors.New("device not found")
|
||||
// ErrAlreadyExists — конфликт уникальности (namespace, name) или (namespace, device_id).
|
||||
var ErrAlreadyExists = errors.New("device already exists")
|
||||
|
||||
// ErrDeviceIDExists — конфликт именно по (namespace, device_id) (отличается от
|
||||
// конфликта по name для понятной ошибки API/Terraform, ревью 2026-10-10).
|
||||
var ErrDeviceIDExists = errors.New("device_id already exists")
|
||||
|
||||
// Device — устройство IoT из таблицы iot_devices.
|
||||
type Device struct {
|
||||
Namespace string
|
||||
|
||||
@@ -6,6 +6,9 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/lib/pq"
|
||||
)
|
||||
|
||||
// Create вставляет новое устройство. Конфликт (namespace, name) или
|
||||
@@ -26,6 +29,13 @@ VALUES ($1, $2, $3, $4, $5, $6, $7)`,
|
||||
)
|
||||
if err != nil {
|
||||
if isUniqueViolation(err) {
|
||||
// Различаем конфликт name и device_id по имени constraint (ревью
|
||||
// 2026-10-10): PK — iot_devices_pkey (namespace,name), уникальный
|
||||
// индекс — idx_iot_devices_ns_device (namespace,device_id).
|
||||
var pqErr *pq.Error
|
||||
if errors.As(err, &pqErr) && strings.Contains(pqErr.Constraint, "ns_device") {
|
||||
return ErrDeviceIDExists
|
||||
}
|
||||
return ErrAlreadyExists
|
||||
}
|
||||
return fmt.Errorf("store: insert device: %w", err)
|
||||
|
||||
Reference in New Issue
Block a user