Problematika Adopsi HTTP QUERY (RFC 10008) pada Tooling OpenAPI

Spesifikasi HTTP QUERY (RFC 10008) menstandarkan method yang aman (safe) dan idempoten untuk membaca resource dengan membawa payload request body. Method ini memecahkan keterbatasan panjang URI dan kompleksitas URL-encoding pada method GET tanpa menyalahgunakan semantik method POST.

Masalah utama muncul pada ekosistem developer tooling. Spesifikasi OpenAPI v3.0 dan v3.1 mendefinisikan objek Path Item dengan daftar method tetap: get, put, post, delete, options, head, patch, dan trace. Default ruleset linter seperti Stoplight Spectral (spectral:oas) akan menandai penambahan properti query pada root path sebagai schema violation:

paths./search.query: Property `query` is not allowed. [oas3-schema]

Sebagian tim menyiasatinya menggunakan POST dengan header kustom atau x-http-method: QUERY, namun pendekatan ini merusak kontrak dokumentasi standar. Solusi yang benar adalah memodifikasi pipeline linting agar mengenali method query sekaligus memvalidasi struktur payload dan integritas header.

Menyusun Ruleset Spectral Kustom

Untuk mendukung method query pada OpenAPI tanpa mematikan validasi esensial lainnya, buat ruleset khusus yang mengekstrak dan memvalidasi operasi tersebut. Simpan konfigurasi ini pada file .spectral.yaml.

extends: [spectral:oas]

rules:
  # Matikan validasi strict schema bawaan untuk properti method yang belum final
  oas3-schema:
    severity: warn

  # Wajibkan deklarasi requestBody untuk method QUERY
  query-requires-request-body:
    description: "Operasi HTTP QUERY harus mendefinisikan requestBody."
    message: "Path {{path}} dengan method QUERY wajib menyertakan properti requestBody."
    severity: error
    given: "$.paths.*.query"
    then:
      field: requestBody
      defined: true

  # Validasi media type pada payload QUERY
  query-content-type-json:
    description: "Request body HTTP QUERY harus mendukung Content-Type application/json."
    message: "Content-Type application/json tidak ditemukan pada {{path}}."
    severity: error
    given: "$.paths.*.query.requestBody.content"
    then:
      field: "application/json"
      defined: true

  # Pastikan skema payload terdefinisi dengan tipe object
  query-body-schema-object:
    description: "Schema JSON untuk payload QUERY harus bertipe object."
    message: "Skema payload pada {{path}} harus memiliki tipe object."
    severity: error
    given: "$.paths.*.query.requestBody.content['application/json'].schema"
    then:
      field: type
      enumeration:
        - object

Ruleset di atas memastikan setiap endpoint dengan method query tidak hanya lolos audit schema, melainkan juga tetap terikat pada kontrak data ketat: wajib menyediakan payload JSON berformat objek terstruktur.

Implementasi Dokumen OpenAPI untuk QUERY

Berikut adalah contoh pendefinisian endpoint pencarian katalog menggunakan method query dalam file openapi.yaml:

openapi: 3.1.0
info:
  title: Catalog Query Service
  version: 1.0.0
paths:
  /items:
    query:
      summary: Pencarian item berbasis filter kompleks
      operationId: queryItems
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - filters
              properties:
                filters:
                  type: object
                  properties:
                    category:
                      type: string
                    priceRange:
                      type: object
                      properties:
                        min:
                          type: number
                        max:
                          type: number
      responses:
        '200':
          description: Berhasil mengambil data
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
        '422':
          description: Payload query tidak valid

Otomasi Validasi di Pipeline CI (GitHub Actions)

Terapkan step linting pada pipeline pull request untuk mencegah developer mendistribusikan kontrak API yang tidak memenuhi standar RFC 10008.

Simpan workflow berikut di .github/workflows/lint-contract.yaml:

name: Contract Linting

on:
  pull_request:
    paths:
      - 'openapi.yaml'
      - '.spectral.yaml'

jobs:
  spectral-lint:
    name: Validate OpenAPI Specification
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Repository
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 20

      - name: Install Spectral CLI
        run: npm install -g @stoplight/spectral-cli

      - name: Run Spectral Lint
        run: |
          spectral lint openapi.yaml --ruleset .spectral.yaml --fail-severity=error --display-only-failures

Flag --fail-severity=error memastikan proses build CI langsung berhenti ketika ditemukan pelanggaran pada kontrak QUERY, sementara warning non-kritis tidak mengganggu alur deployment.

DX: Mock Server Lokal dan Validasi Error Handling

Untuk keperluan pengujian lokal tanpa menunggu backend selesai diimplementasikan, jalankan mock server berbasis spek menggunakan Node.js atau Prism CLI:

npx @stoplight/prism-cli mock openapi.yaml -p 4010

Lakukan verifikasi penolakan payload terhadap mock server menggunakan curl:

# Test 1: Request valid
curl -X QUERY http://127.0.0.1:4010/items \
  -H "Content-Type: application/json" \
  -d '{"filters": {"category": "hardware"}}'

# Test 2: Request tidak valid (missing required field: filters)
curl -X QUERY http://127.0.0.1:4010/items \
  -H "Content-Type: application/json" \
  -d '{"invalidKey": 123}'

Jika kontrak divalidasi dengan benar, mock engine akan merespons request kedua dengan kode status 422 Unprocessable Content yang mencantumkan detail schema violation.

Checklist Pencegahan Breaking Changes

  • Reverse Proxy Readiness: Pastikan NGINX, Cloudflare, atau AWS ALB di depan service tidak memblokir method QUERY atau menghapus body request pada layer L7.
  • Fallback Semantics: Bila upstream proxy membatasi method kustom, tentukan apakah service menerima header alternatif X-HTTP-Method-Override: QUERY.
  • Idempotency Validation: Hindari mutasi status database di sisi backend saat memproses method ini. Kontrak RFC 10008 menuntut operasi bersifat safe.