Category: HTTP Headers
Description
GET responses should include the Last-Modified header to enable efficient caching and conditional requests.
What It Checks
This rule validates that all successful GET responses (2XX status codes) include the Last-Modified header. It checks:
- All GET operations in your OpenAPI specification
- Only successful responses (status codes starting with "2")
- The presence of the
Last-Modifiedheader in response definitions - All endpoints that retrieve resource data
Why It Matters
The Last-Modified header is essential for efficient HTTP caching and client-server synchronization:
- Caching efficiency: Enables browsers and intermediary caches to determine if cached content is still fresh
- Bandwidth optimization: Supports conditional requests with If-Modified-Since, reducing unnecessary data transfer
- Performance: Allows clients to skip re-downloading unchanged resources, improving response times
- Cache validation: Provides a reliable mechanism for cache invalidation and revalidation
Examples
Good ✅
paths:
/users/{userId}:
get:
summary: Get a user
responses:
'200':
description: User details
headers:
Last-Modified:
description: The date and time the resource was last modified
schema:
type: string
format: date-time
content:
application/json:
schema:
$ref: '#/components/schemas/User'
/products/{productId}:
get:
summary: Get product details
responses:
'200':
description: Product information
headers:
Last-Modified:
description: When the product was last updated
schema:
type: string
format: date-time
ETag:
description: Entity tag for cache validation
schema:
type: string
content:
application/json:
schema:
$ref: '#/components/schemas/Product'
/articles:
get:
summary: List articles
responses:
'200':
description: Array of articles
headers:
Last-Modified:
description: When the collection was last modified
schema:
type: string
format: date-time
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Article'
Bad ❌
paths:
/users/{userId}:
get:
summary: Get a user
responses:
'200':
description: User details
# Missing Last-Modified header
content:
application/json:
schema:
$ref: '#/components/schemas/User'
/products/{productId}:
get:
summary: Get product details
responses:
'200':
description: Product information
headers:
ETag:
schema:
type: string
# Has ETag but missing Last-Modified
content:
application/json:
schema:
$ref: '#/components/schemas/Product'
/articles:
get:
summary: List articles
responses:
'200':
description: Array of articles
# No caching headers at all
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Article'
Configuration
This rule has no configuration options. It is either enabled or disabled.
How to Fix
-
Add Last-Modified header to all GET responses:
responses: '200': description: Success headers: Last-Modified: description: The date and time the resource was last modified schema: type: string format: date-time -
Implement server-side tracking:
- Store
updated_atormodified_attimestamps in your database - Include these timestamps in the Last-Modified header value
- Use RFC 7231 format:
Wed, 21 Oct 2015 07:28:00 GMT
- Store
-
Support conditional requests (recommended):
parameters: - name: If-Modified-Since in: header description: Only return the resource if modified after this date schema: type: string format: date-time responses: '200': description: Resource has been modified headers: Last-Modified: schema: type: string format: date-time '304': description: Not Modified - resource unchanged since If-Modified-Since -
Consider combining with ETag:
- Use both Last-Modified and ETag headers for robust caching
- Last-Modified for time-based validation
- ETag for content-based validation
-
Handle collection resources appropriately:
- For collections, use the most recent modification time of any item
- Or use the time the collection itself was last changed (items added/removed)
Related Rules
- Rule 59: ETag Usage - Complementary cache validation mechanism
- Rule 60: Cache-Control Headers - General caching directives
- Rule 37: HTTP Status Codes - Including 304 Not Modified for conditional requests