LabHub
学习 学习路径 课程

FastAPI — 타입이 곧 계약이다 · ETag로 덮어쓰기 충돌을 막는 API · 讲解

ETag로 덮어쓰기 충돌을 막는 API의 설계 원리

在 LabHub 中继续学习

한 줄 요약

‘내가 읽은 버전일 때만 수정’이라는 조건을 DB의 쓰기 문장까지 전달해야 변경 유실을 막는다.

概念图: 한 줄 요약 · 왜 이게 필요했나 · 어떻게 동작하나 · 현장에서 만나는 모습

왜 이게 필요했나

A와 B가 같은 메모 v1을 읽었다. A가 제목을 수정한 뒤 B가 오래된 화면에서 저장하면
조건 없는 UPDATE는 A의 변경을 조용히 덮어쓴다. 저장 직전에 SELECT로 버전을
확인해도 확인과 UPDATE 사이에 다른 요청이 끼어들 수 있다. 비교와 갱신은 한 SQL
문장으로 묶고 변경된 행 수를 확인해야 한다. 여기서는 SQLite 파일을 실제로 열어
별도 연결의 두 요청이 경쟁하게 만든다. 프로세스 메모리의 딕셔너리만 검사하지 않는다.

어떻게 동작하나

GET → ETag: "v1"  ├─ A: PUT If-Match "v1" → UPDATE WHERE version=1 → 204, version=2  └─ B: PUT If-Match "v1" → 변경 행 0             → 412

ETag는 표현의 검증자다. 이 실습에서는 id별 title이 바뀔 때 version이 정확히 증가하고
응답 표현의 다른 요소는 바뀌지 않는다는 제한 아래 강한 태그를 만든다. 실서비스에서
표현의 압축·언어·권한별 필드가 달라진다면 같은 버전 문자열을 무조건 재사용하면 안 된다.

현장에서 만나는 모습

If-Match는 강한 비교를 사용한다. 이 교육용 API는 단일 태그만 받으며 weak 태그,
와일드카드, 목록은 지원하지 않는다. 이는 HTTP 전체 문법을 구현한 것이 아니라
API에 명시한 좁은 계약이다. 없는 메모는 404, 조건 누락은 428, 지원하지 않는 조건이나
오래된 버전은 412로 정한다. 클라이언트는 412를 무한 재시도하지 않고 최신 메모를
읽어 사용자에게 병합을 요청해야 한다. 입력 오류인 빈 제목은 422로 구분한다.

다음 실습에서 할 것

스키마 → 생성 → 조회 → 태그 → 조건 해석 → 원자적 갱신 → 결과 코드 → FastAPI 순으로
완성한다. 원래 제목이 보존되는지도 확인한다. 412라는 숫자만 맞고 뒤에서 UPDATE를
해 버리는 구현은 통과하면 안 된다. DB 연결은 작업마다 닫아 테스트 간 상태 누출을 막는다.

참고: [HTTP 조건부 요청](https://www.rfc-editor.org/rfc/rfc9110.html#name-if-match)