You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
adding if-match support as a proof of concept that
it is possible for grpc APIs to support this behavior,
allowing removal of other methods such as etags.
This document describes the If-Match header support that has been added to all update endpoints in the AEPC bookstore example.
4
+
5
+
## Overview
6
+
7
+
The If-Match header provides optimistic concurrency control for update operations. When provided, the server validates that the current resource matches the expected ETag before performing the update. If the ETags don't match, the update is rejected with a `412 Precondition Failed` status.
8
+
9
+
## Features
10
+
11
+
### Supported Operations
12
+
13
+
The If-Match header is supported for all update operations:
14
+
-`UpdateBook`
15
+
-`UpdatePublisher`
16
+
-`UpdateStore`
17
+
-`UpdateItem`
18
+
19
+
### ETag Generation
20
+
21
+
ETags are generated by:
22
+
1. Serializing the protobuf message using `proto.Marshal`
23
+
2. Computing an MD5 hash of the serialized data
24
+
3. Encoding the hash as a hexadecimal string
25
+
4. Wrapping in quotes (e.g., `"a1b2c3d4..."`)
26
+
27
+
### Header Processing
28
+
29
+
The grpc-gateway is configured to forward the `If-Match` HTTP header to gRPC metadata:
-`200 OK`: Update successful with valid If-Match header
58
+
-`412 Precondition Failed`: If-Match header value doesn't match current resource ETag
59
+
-`404 Not Found`: Resource doesn't exist
60
+
- No If-Match header: Update proceeds normally (backwards compatible)
61
+
62
+
### gRPC API
63
+
64
+
The If-Match header is automatically extracted from gRPC metadata by the service methods. No additional client configuration is required when using grpc-gateway.
65
+
66
+
## Implementation Details
67
+
68
+
### Core Components
69
+
70
+
1.**ETag Generation** (`types.go`):
71
+
-`GenerateETag(msg proto.Message)`: Creates ETag from protobuf message
72
+
-`ValidateETag(provided, current string)`: Compares ETags with quote handling
73
+
74
+
2.**Header Extraction** (`service.go`):
75
+
-`extractIfMatchHeader(ctx context.Context)`: Extracts If-Match from gRPC metadata
76
+
77
+
3.**Gateway Configuration** (`gateway.go`):
78
+
- Custom header matcher forwards `If-Match` header to `grpcgateway-if-match` metadata
79
+
80
+
4.**Update Methods**: All update methods now:
81
+
- Extract If-Match header from context
82
+
- Fetch current resource if header is present
83
+
- Generate ETag for current resource
84
+
- Validate provided ETag against current ETag
85
+
- Reject with `FailedPrecondition` if validation fails
86
+
- Proceed with normal update logic if validation passes
87
+
88
+
### Error Handling
89
+
90
+
-**Missing Resource**: Returns `NotFound` when trying to validate ETag for non-existent resource
91
+
-**ETag Mismatch**: Returns `FailedPrecondition` when If-Match header doesn't match current ETag
92
+
-**ETag Generation Failure**: Returns `Internal` if ETag generation fails
93
+
-**No If-Match Header**: Proceeds normally for backwards compatibility
94
+
95
+
## Testing
96
+
97
+
### Unit Tests
98
+
99
+
The implementation includes comprehensive unit tests:
100
+
-`TestUpdateBookWithIfMatchHeader`: Tests successful and failed ETag validation
0 commit comments