Skip to content

POSTING 3 ~/research/import-postman/

Postman collection importer

Implemented for Posting 3 in internal/importing/postman, researched September 2026.

Sources and semantic decisions

  • The official v2.1 JSON schema describes nested item groups, URL strings/objects, disabled entries, descriptions, request-string shorthand, and request-body modes. v2.0 uses object auth attributes; v2.1 uses key/value arrays. Both are accepted. Inputs require info and an item array and at least one request. A provided schema must identify v2.0.0 or v2.1.0.
  • Postman's auth documentation describes parent inheritance. Collection/folder auth is carried down the item tree; absent or null auth inherits, while noauth stops inheritance. Supported helpers are Basic, Digest, Bearer and API key (header or query). Unsupported auth produces a request-specific warning.
  • The upstream URL implementation builds URLs from components, excluding disabled query fields. Components take precedence over an inconsistent raw. For compatibility with third-party exports, a raw-only URL object is also accepted. An explicit query array replaces the raw query, even when empty.
  • Environment exports are JSON objects with a name, a values array of key, value, type and enabled, and _postman_variable_scope: "environment". ParseEnvironment skips disabled values, applies the collection's name and reference rules, and reads non-string JSON values as their JSON text. A globals export has the same shape with scope globals. It is rejected, because Posting has no global layer. The CLI treats a JSON file with a values array and no item array as an environment export.
  • Upstream URL tests cover string/array hosts and paths, path variables, and suffixes such as :id.json. The importer preserves suffixes through an equivalent Posting path parameter. Query tests show that null/missing values omit = and that existing percent encoding is retained. Posting stores decoded editable parameter values and re-encodes on send. Repeated parameters and disabled entries are retained. A warning explains that bare parameters become empty values with = because the Posting parameter model cannot distinguish them.
  • Variable documentation establishes double-brace references and precedence of narrower scopes. Postman ranks local, data, environment, collection and global scopes from narrowest to widest. Collection defaults become the base environment, posting.env. Environment exports become named environments layered on it. Folder and request overrides outrank environments, so they are materialized per request, and sibling requests keep their own values. A reference inside a folder or request value to a name not bound at that scope stays a ${NAME} reference, so an environment can still override it. A collection default that refers to a folder or request variable is materialized for the requests in that scope.

Design

Parse([]byte) (importing.Result, error) is independent of the filesystem, CLI, and network. It returns suggested nested request paths for the shared writer to sanitize and disambiguate. Parsing is all-or-nothing for structural errors and unrepresentable HTTP methods; unsupported optional features generate stable, deduplicated warnings. Unknown unrelated JSON fields are tolerated for exporter compatibility.

Names, descriptions, order, repeated parameters, disabled headers/query/form fields, raw bodies and their MIME type, and URL-encoded bodies are preserved. Explicit enabled Content-Type headers override inferred raw-body types. An entirely disabled body is omitted. Literal dollar signs are escaped before {{NAME}} becomes ${NAME}, preserving shell-looking strings such as $HOME and passwords containing dollar signs. Variable values use the same placeholder syntax as request fields. References between variables stay references. The common writer orders and quotes them so that Posting's load-time expansion matches Postman's lazy resolution.

Folder nesting is limited to 128 levels. Variable substitution limits depth, recursive work, and expanded value size to avoid cyclic or exponentially growing substitutions. The importer never executes scripts, evaluates expressions, reads file bodies/certificates, or fetches URLs.

Limitations reported to users

  • Multipart/form-data, file and GraphQL body modes are omitted with warnings; they are not incorrectly relabeled as URL-encoded forms.
  • Postman scripts/tests, custom protocol settings, proxies and client certificates require manual migration.
  • OAuth, AWS signing, NTLM and other unsupported auth helpers require manual configuration. Digest helper overrides are dropped; Posting negotiates the challenge with the server.
  • Dynamic/vault variables and non-identifier variable names cannot become Posting variables. Their references remain literal and produce warnings. Only values present in the collection and environment exports are available. Runtime script values and globals are not imported.
  • Posting expands environment references when it loads each file, in file order. Variables that reference each other in a cycle are written in source order with a warning, and resolve differently from Postman.
  • Bare query flags normalize to flag=. URL query escaping normalizes on send. Posting path parameters escape slashes in values, so values intended to inject multiple path segments need manual adjustment.
  • Only Posting's supported HTTP methods are accepted; unsupported methods fail explicitly rather than writing unloadable request files.

Verification

The fixture covers nesting, auth inheritance/noauth, disabled values, string/object URLs, encoded and repeated query values, path suffixes, raw JSON, form bodies, and literal dollar escaping. Tests serialize/reload all imported fixture requests and compare their resolved behavior. A local HTTP server verifies actual method, path, query, body, MIME type, auth credentials and literal dollars after serialization. Additional tests cover v2 object auth, v2.1 array auth, API keys, scope isolation, invalid documents, unsupported-feature warnings and bounded variable expansion. FuzzParse checks deterministic output and that every successful imported request can be serialized and reloaded.