ADR 0002: Multi-dialect URL API over one canonical model
- Status: accepted
- Date: 2026-09-26
Context
Section titled “Context”Adoption depends on drop-in compatibility: existing imgproxy URLs, and front-end tooling such as unpic that generates URLs for imgix, Cloudinary, ImageKit, Cloudflare, Bunny, wsrv and 20 other providers. Each vendor grammar differs in syntax, units, defaults and signing.
Decision
Section titled “Decision”- imgproxy’s grammar is the canonical dialect: default at
/, complete option coverage (including Pro options), presets,plain/, base64 andenc/sources,/info. - Every dialect is a pure-Go parser producing
transform.Request; nothing downstream knows which dialect was used. Unit conversions (blur radius → sigma, −100..100 → multipliers) happen in the parser. - Dialects are mounted by host binding, path prefix or default (in that order) and can bind a named source for relative paths, so a vendor-shaped URL on a vendor-shaped host works unchanged.
- Low-feature providers from the unpic list are table-driven “simple” dialects, not bespoke code.
- Options scheduled for later milestones are parsed from day one and reported as ignored; unknown options are errors only in strict mode.
- Each dialect’s native signing scheme is implemented; an
xi_sigHMAC and an “unsigned policy” (allow|restricted|deny) cover dialects that have none.
Consequences
Section titled “Consequences”- One cache entry serves equivalent URLs across dialects; features land once in the pipeline and appear in all dialects.
- The model must be rich enough for the union of dialects (borders, masks, radius, arbitrary rotation), which widens the pipeline surface.
- Some vendor features (generative AI, conditional transformations, blend modes) are explicitly unsupported and documented as such.
- Compatibility is proven with fixtures generated by upstream SDKs, which must be refreshed when vendors change.