REST Lens
← Back to All Rules
Rule 12

No File Extensions

Category: URI Design

Description

URI paths should not include file extensions (e.g., .json, .xml, .html). Representation formats should be negotiated through HTTP headers (Accept/Content-Type) rather than being embedded in the URI structure.

What It Checks

This rule validates that URI path segments do not end with file extensions. It checks:

  • All path segments in the URI for file extension patterns (e.g., .json, .xml, .pdf)
  • Uses regex pattern matching to detect extensions: \.(\w+)$
  • Applies to all HTTP methods on paths containing file extensions
  • Flags violations on any operation defined for a path with a file extension

Why It Matters

Keeping file extensions out of URIs is fundamental to RESTful design:

  • Resource Identity: URIs should identify resources, not representations. The same resource can be represented in multiple formats (JSON, XML, HTML) without changing its identity.
  • Content Negotiation: HTTP provides built-in mechanisms (Accept/Content-Type headers) specifically designed for format negotiation, making extensions redundant.
  • URI Stability: Changing supported formats shouldn't require URI changes. A URI like /users/123.json becomes problematic if you later want to support XML or other formats.
  • API Evolution: Adding or removing support for formats doesn't break existing URI structures when using header-based negotiation.

Examples

Good ✅

paths:
  /users:
    get:
      summary: List all users
      produces:
        - application/json
        - application/xml
      responses:
        '200':
          description: Array of users

  /users/{userId}:
    get:
      summary: Get a specific user
      produces:
        - application/json
        - application/xml
      responses:
        '200':
          description: User details

  /reports/{reportId}:
    get:
      summary: Get report
      produces:
        - application/json
        - application/pdf
      responses:
        '200':
          description: Report data

Client request with content negotiation:

GET /users/123 HTTP/1.1
Accept: application/json
GET /users/123 HTTP/1.1
Accept: application/xml

Bad ❌

paths:
  /users.json:  # File extension in URI
    get:
      summary: List users in JSON format
      responses:
        '200':
          description: JSON array of users

  /users/{userId}.xml:  # File extension in URI
    get:
      summary: Get user in XML format

  /reports/{reportId}.pdf:  # File extension in URI
    get:
      summary: Get report as PDF

  /api/v1/data.json:  # File extension in URI
    get:
      summary: Get data

Anti-pattern examples:

# Wrong - format in URI
GET /users/123.json HTTP/1.1

# Wrong - limits flexibility
GET /reports/456.pdf HTTP/1.1

# Wrong - violates resource identity principle
GET /api/data.xml HTTP/1.1

Configuration

This rule has no configuration options. It is either enabled or disabled.

How to Fix

  1. Remove file extensions from URIs:

    # Before
    /users.json → /users
    /users/{userId}.xml → /users/{userId}
    /reports/{id}.pdf → /reports/{id}
    
    # After
    /users
    /users/{userId}
    /reports/{id}
    
  2. Implement content negotiation using HTTP headers:

    paths:
      /users/{userId}:
        get:
          summary: Get user
          parameters:
            - name: Accept
              in: header
              description: Desired response format
              schema:
                type: string
                enum:
                  - application/json
                  - application/xml
          produces:
            - application/json
            - application/xml
          responses:
            '200':
              description: User data
    
  3. Update client code to use Accept headers:

    // Before
    fetch('/users/123.json')
    
    // After
    fetch('/users/123', {
      headers: {
        'Accept': 'application/json'
      }
    })
    
  4. Configure server to handle content negotiation:

    • Inspect the Accept header to determine response format
    • Set appropriate Content-Type header in responses
    • Support multiple formats from the same endpoint
    • Return 406 Not Acceptable if requested format is unsupported
  5. Document supported formats in API specification:

    responses:
      '200':
        description: Successful response
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/User'
          application/xml:
            schema:
              $ref: '#/components/schemas/User'
      '406':
        description: Requested format not supported
    

Related Rules

  • Rule 28: Lowercase Letters - URI formatting and casing standards
  • Rule 26: Hyphens vs Underscores - URI naming conventions
  • Rule 75: Consistent Naming Conventions - Overall API naming patterns