Codifying Your Team's FHIR Search Conventions

Editorial illustration in vaporwave-pastel style depicting a team convention doc flowing through a client wrapper and CI linter into a FHIR server

Every team that ships FHIR search queries eventually notices the same pattern: two developers write the same-shaped query with different conventions, and the second one costs a review round. Codifying the conventions is small work up front and saves the round trips permanently. The site's FHIR search query auditor is the public checker; a team-local convention document is what turns it into consistent output. For the wider FHIR framing, the SDC and forms reference collects supporting material.

What A Convention Document Covers

  • Parameter naming rules (canonical FHIR names only, no shortcuts)
  • Value encoding rules (percent-encode reserved chars at build time)
  • Date encoding rules (always UTC with Z, always second precision or better)
  • Sort defaults (always end with _id)
  • Pagination default (next link, not _offset)
  • Modifier defaults (:missing explicit when relevant, :not guarded)
  • Error handling (what to do on 400, 404, 412, 422)
  • Retry semantics (which codes retry, which do not)

That is eight sections and roughly one page of prose. Every team has them de facto; writing them down is the work.

Format That Actually Gets Read

A convention document in a wiki that nobody opens is not a convention. The formats that actually get used:

  • A short markdown file in the repo root, next to the code
  • Rules encoded as lint tests that fail CI on violation
  • Named helper functions in the client wrapper that enforce the rules by construction

The third is the strongest — a client.searchObservations({subject: patient.id, category: "vital-signs"}) helper that always emits canonical parameter names, encodes values, and adds the standard sort tail can prevent whole classes of mistake without a doc.

Encode the Rules in the Client Wrapper

The pattern that survives team rotation is a thin wrapper around the raw HTTP client that knows the conventions. Callers pass structured parameters, the wrapper emits the compliant query string. That means:

  • Reserved-character encoding is centralized
  • Date-timezone marker is added automatically
  • _sort gets _id appended if missing
  • Pagination uses the next link by default
  • The wrapper reads Bundle.link and provides an iterator that follows it

That is a few hundred lines of code. It saves a large multiple of that in review time and incident time.

Wire the Linter Into CI

Every query string emitted by the codebase should pass the linter in CI. The rules from linter rules to catch the ten most common search mistakes are a solid starting set. The CI check runs the linter against a captured set of production-shaped queries and fails on new violations.

The trap: a linter that runs against test-shaped queries is not the same as one that runs against production-shaped queries. Capture real queries, run the linter, iterate the rules.

Enforce Sort And Pagination Together

Sort and pagination interact. A convention that specifies "always end sort with _id" only pays off if the pagination convention says "follow next, not _offset". For the two mechanics, sort order that survives resource updates and the pagination article are the entries.

What Happens Without Conventions

  • Two developers write the same-shape query with different parameter names
  • Bug reports blame the server when the query is silently wrong
  • Rewrites happen every time a new server implementation is added
  • Onboarding takes twice as long

For the class of quiet-wrong queries these conventions prevent, the FHIR searches that look correct but are wrong is the entry.

The Short Version

Write the conventions down, encode them in a client wrapper, wire the linter into CI. Small work, permanent savings.

Vaporwave-pastel diagram of a team convention document flowing into a shared client wrapper and CI linter, feeding consistent query strings into a FHIR server, on a soft dusk-purple background

Sources