Insomnia v4¶
Parses an Insomnia "Export v4" JSON document into the Vayu draft model. Insomnia exports are a single flat array of typed resources joined by _id/parentId; the parser reconstructs the workspace → request_group → request tree and emits one root collection per workspace.
- Source:
app/src/services/importers/insomnia-v4.ts - Exports:
| Class | formatName |
formatKey |
|---|---|---|
InsomniaV4Parser |
Insomnia Export v4 |
insomnia-v4 |
Implements ImportParser (detect + parse) from ./types. meta.format is set to this.formatName ("Insomnia Export v4").
Detection¶
Both conditions must hold: the top-level object must have _type === "export" and __export_format === 4 (numeric). No other format versions are accepted by this parser.
Structure & tree reconstruction¶
An Insomnia v4 export has the shape { _type: "export", __export_format: 4, resources: Resource[] }. Each resource carries _id, _type, an optional parentId, and type-specific fields. There is no nesting in the JSON - hierarchy is expressed entirely through parentId references.
Reconstruction steps in parse():
- Index by parent. Build
byParent: Map<parentId, Resource[]>, grouping every resource under itsparentId(resources with noparentIduse the empty-string key""). This is the single adjacency index used for the whole tree walk. - Find roots. Filter
resourcesfor_type === "workspace". Each workspace becomes one rootCollectionDraft. Multiple workspaces ⇒ multiple root collections inImportResult.collections. - Recursive build.
buildCollection(node, isWorkspace)walksbyParent.get(node._id)and dispatches each child by_type: request_group→ incrementsfolderCount, recurses viabuildCollection(child, false), pushed tochildren.request→buildRequest(child), pushed torequests.- other handled
_types (gRPC / WebSocket / spec / tests) → counted inskippedCounts(see Resource type handling). - any unlisted
_type(includingenvironment) → silently ignored by the collection walk; environments are processed separately. buildRequest(r)incrementsrequestCountand produces aRequestDraft.
Key internal functions: parse (entry), buildCollection, buildRequest, insomniaAuth, insomniaBody, toEnvVars. Counters (requestCount, folderCount, authCtx.nonExec) are closures mutated during the walk.
Resource type handling¶
Insomnia _type |
Vayu outcome | Notes |
|---|---|---|
workspace |
Root CollectionDraft |
One per workspace. isWorkspace = true. |
request_group |
Nested CollectionDraft (folder) |
Increments folderCount. |
request |
RequestDraft |
Increments requestCount. |
environment |
EnvironmentDraft (flattened) |
Processed in a separate pass, not in the collection walk. Gated by importEnvironments. See Environments. |
grpc_request |
Dropped | meta.skipped kind "grpc". |
websocket_request |
Dropped | meta.skipped kind "websocket". |
api_spec |
Dropped | meta.skipped kind "api_spec". |
unit_test |
Dropped | meta.skipped kind "unit_test". |
unit_test_suite |
Dropped | meta.skipped kind "unit_test" (folded into the same unit_test bucket). |
anything else (e.g. cookie_jar, proto_file, request_meta, environment outside its pass) |
Dropped silently | Not counted in meta.skipped. |
Skip counting nuance. Only the five _types listed above (grpc_request, websocket_request, api_spec, unit_test, unit_test_suite) are tallied in skippedCounts, and only when they appear as a direct child of a workspace or request_group during the tree walk. A dropped resource parented under something else (or any other _type) does not increment meta.skipped. When emitting SkippedItem[], the raw keys are remapped: grpc_request → "grpc", websocket_request → "websocket", unit_test_suite → "unit_test"; unit_test and api_spec pass through unchanged. Because unit_test and unit_test_suite both map to "unit_test" but are aggregated by their raw key first, an export containing both can yield two separate SkippedItem entries with kind: "unit_test".
Field mapping¶
Collection (workspace / request_group)¶
Both build through buildCollection. Differences are gated by isWorkspace.
| Insomnia field | Vayu CollectionDraft field |
Notes |
|---|---|---|
name |
name |
Falls back to "Imported". |
description |
description |
Falls back to "". |
environment (object, workspace only) |
variables |
toEnvVars(node.environment ?? {}) for workspaces; request_groups always get variables: {} (their inline environment, if any, is not read). |
authentication |
auth |
Mapped via insomniaAuth. Collections may not be inherit: a resulting inherit is coerced to { mode: "none" }. |
| - | preRequestScript / postRequestScript |
Always "" for collections (workspace/group-level scripts are not imported). |
| (reconstructed children) | children / requests |
Built from byParent. |
Request¶
Built by buildRequest.
| Insomnia field | Vayu RequestDraft field |
Notes |
|---|---|---|
name |
name |
Falls back to "Untitled". |
description |
description |
Falls back to "". |
method |
method |
Upper-cased; restricted to GET/POST/PUT/PATCH/DELETE/HEAD/OPTIONS, otherwise defaults to GET. |
url |
url |
normalizeVars(asString(url)). |
parameters[] ({name,value,disabled}) |
params |
mapKeyValues: name → key, disabled !== true → enabled. Rows without a key are dropped. |
headers[] ({name,value,disabled}) |
headers |
Same mapping as params. |
body |
body |
Via insomniaBody. See Body mapping. |
authentication |
auth |
Via insomniaAuth. See Auth mapping. |
preRequestScript |
preRequestScript |
Only if opts.importScripts; else "". |
afterResponseScript |
postRequestScript |
Only if opts.importScripts; else "". Note the source field is afterResponseScript. |
_id |
- | Not propagated to the draft id; used only for tree reconstruction. |
mapKeyValues runs normalizeVars over every value and preserves duplicate keys and order.
Template normalization¶
All variable-bearing strings are run through normalizeVars (var-normalize.ts). It converts foreign template syntax to Vayu's {{var}} form:
{{ x }}and{{ _.x }}(identifier only, whitespace tolerant) →{{x}}. The leading_.namespace Insomnia uses is stripped.- OpenAPI single-brace
{x}→{{x}}, but only when not already part of a{{...}}pair (it checks the adjacent characters). This rule is shared with the OpenAPI parsers and rarely fires on Insomnia input. - Left verbatim: Nunjucks tags
{% ... %}and filtered expressions{{ x | filter }}. The simple-var regex requires an identifier-only body ([\w.$-]+), so a|filter never matches and is passed through unchanged. Vayu has no equivalent, so these remain as literal text.
Applied to: request url; every params and headers value (inside mapKeyValues); JSON/text/graphql body content and urlencoded/form-data field values; every auth token/username/password/key/value string; and every environment value (inside toEnvVars).
Body mapping¶
insomniaBody keys off body.mimeType, stripping any ;charset=... suffix and trimming.
Insomnia body.mimeType |
Vayu RequestBody |
Notes |
|---|---|---|
application/json |
{ mode: "json", content } |
content = normalizeVars(body.text). |
text/plain |
{ mode: "text", content } |
content = normalizeVars(body.text). |
application/graphql |
{ mode: "graphql", content } |
content = normalizeVars(body.text). |
application/x-www-form-urlencoded |
{ mode: "x-www-form-urlencoded", fields } |
body.params[] → mapKeyValues (name → key, disabled honored). |
multipart/form-data |
{ mode: "form-data", fields } |
body.params[] filtered to drop entries where type === "file", then mapKeyValues. File parts are silently discarded - note this is not recorded in meta.skipped (no "file_body" item is emitted by this parser). |
| anything else, missing, or empty | { mode: "none" } |
Includes raw/binary/file-only bodies. |
Auth mapping¶
insomniaAuth(authentication, ctx):
Insomnia authentication.type |
Vayu RequestAuth |
nonExecutableAuth? |
|---|---|---|
(absent / no type) |
{ mode: "inherit" } |
no |
any type with disabled === true |
{ mode: "none" } |
no |
bearer |
{ mode: "bearer", token } |
no |
basic |
{ mode: "basic", username, password } |
no |
apikey |
{ mode: "apikey", key, value, in } - in is "query" when addTo === "queryParams", else "header" |
no |
oauth2 |
{ mode: "oauth2", config: OAuth2Config } via mapInsomniaOAuth2 - executable |
no |
digest |
{ mode: "digest", config } |
yes |
ntlm |
{ mode: "ntlm", config } |
yes |
iam |
{ mode: "aws", config } - Insomnia names AWS IAM "iam"; Vayu stores it as the aws config bag |
yes |
| any other / unrecognized type | { mode: "inherit" } |
no |
Notes:
disabledtakes precedence overtype. Ifauthentication.disabled === true, the result is{ mode: "none" }regardless oftype. Ifauthenticationis missing or has notype(and is not disabled), the result is{ mode: "inherit" }.oauth2is mapped to an executableOAuth2Config(mapInsomniaOAuth2) and does not count.digest/ntlm/iamare stored as opaqueconfigbags (the auth object withtypeanddisabledremoved) and are not executed by Vayu - each occurrence incrementsmeta.nonExecutableAuth.- The same
insomniaAuthis called for collection-level auth (workspace/request_group), sharing the sameauthCtx. So a non-executable auth on a workspace or folder also counts towardnonExecutableAuth. For collections, aninheritresult is coerced to{ mode: "none" }(collections can never inherit).
Environments¶
Environments are imported only when opts.importEnvironments is true. They are reconstructed and flattened per workspace:
- Base environments:
environmentresources whoseparentIdis the workspace_id. - Sub-environments:
environmentresources whoseparentIdis a base environment_id.
Flattening per base:
- No sub-envs: emit one
EnvironmentDraftfrom the base'sdata. Name =base.name ?? workspace.name ?? "Environment". - Has sub-envs: emit one
EnvironmentDraftper sub-env, with variables{ ...baseVars, ...subVars }(sub-env values override base on key collision). Name =sub.name ?? "Environment". The standalone base environment is not emitted when sub-envs exist - its values survive only merged into each sub-env.
Each variable is produced by toEnvVars: keys come straight from the env data object; values are normalizeVars(asString(v)) (objects/arrays are JSON-stringified, numbers/booleans coerced to strings), and every variable is { value, enabled: true }. secret is never set. meta.environmentCount equals the number of emitted EnvironmentDrafts.
Options & lossy behavior¶
ImportOptions:
importScripts- when false, requestpreRequestScript/postRequestScriptare forced to"". When true, they come frompreRequestScriptandafterResponseScript. (Collection-level scripts are always""regardless.)importEnvironments- when false, the entire environment pass is skipped;environmentsis[]andenvironmentCountis0. Workspace-levelenvironmentdata still populates the root collection'svariablesindependently of this flag.
Lossy / dropped, summary:
- gRPC, WebSocket, API spec, unit test, and unit-test-suite resources are dropped and counted in
meta.skipped(only when encountered as direct children of a workspace/request_group during the tree walk; see counting nuance above). multipart/form-datafile parts are dropped silently - not reflected inmeta.skipped.- Non-executable auth types (
digest,ntlm,iam→aws) are stored but not run; each occurrence (request or collection level) incrementsmeta.nonExecutableAuth.oauth2is executable and excluded. - Nunjucks tags and filtered template expressions are preserved as literal text.
- request_group inline environments, collection/group scripts, and resource
_ids are not carried into the draft model.
meta: { format: "Insomnia Export v4", requestCount, folderCount, environmentCount, skipped, nonExecutableAuth } (no fileName set by the parser itself).
Shared helpers used¶
| Helper | Source | Used for |
|---|---|---|
asString |
./shared.ts |
Coerce any scalar/object to its string form (objects → JSON.stringify). |
mapKeyValues |
./shared.ts |
Map {name,value,disabled} arrays → KeyValueEntry[] (filters keyless rows, normalizes values, derives enabled from disabled). |
normalizeVars |
./var-normalize.ts |
Template syntax normalization (see Template normalization). |
See ./README.md for the full shared-helper reference.