Skip to content

Add support for importing Swagger 2.0 specifications into Bruno collections#7622

Merged
bijin-bruno merged 7 commits intousebruno:mainfrom
gopu-bruno:feat/swagger2-spec-support
Apr 1, 2026
Merged

Add support for importing Swagger 2.0 specifications into Bruno collections#7622
bijin-bruno merged 7 commits intousebruno:mainfrom
gopu-bruno:feat/swagger2-spec-support

Conversation

@gopu-bruno
Copy link
Copy Markdown
Collaborator

@gopu-bruno gopu-bruno commented Mar 30, 2026

Description

JIRA

Add support for importing Swagger / OpenAPI 2.0 specifications into Bruno collections. Previously, Bruno only supported importing newer OpenAPI formats (3.0+). With this change, users can now import Swagger 2.0 API definitions directly into Bruno.

Key Changes:

  • Added support for parsing Swagger / OpenAPI 2.0 specification format.
  • Enabled importing Swagger 2.0 specifications via file uploads and URL-based import

Contribution Checklist:

  • I've used AI significantly to create this pull request
  • The pull request only addresses one issue or adds one feature.
  • The pull request does not introduce any breaking changes
  • I have added screenshots or gifs to help explain the change if applicable.
  • I have read the contribution guidelines.
  • Create an issue and link to the pull request.

Note: Keeping the PR small and focused helps make it easier to review and merge. If you have multiple changes you want to make, please consider submitting them as separate pull requests.

Publishing to New Package Managers

Please see here for more information.

Summary by CodeRabbit

  • New Features
    • Import Swagger 2.0 (OpenAPI v2) specs with full conversion: environments, auth mapping, params/body handling, example generation, grouping, and circular-reference resilience.
  • UI
    • Clarified import text to say "OpenAPI 3.x / Swagger 2.0"; updated grouping option copy and disabled/OpenAPI Sync note for Swagger 2.0 imports.
  • Tests
    • Added extensive test coverage for Swagger 2.0 conversion: auth, bodies, parameters, examples, grouping, tags, and circular references.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 30, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: c4feeb9f-b71d-4430-865e-00efdcd7233e

📥 Commits

Reviewing files that changed from the base of the PR and between 23a5669 and 7f3fe36.

📒 Files selected for processing (3)
  • packages/bruno-app/src/components/OpenAPISyncTab/ConnectSpecForm/index.js
  • packages/bruno-app/src/components/Sidebar/ImportCollectionLocation/index.js
  • packages/bruno-converters/src/openapi/openapi-common.js
✅ Files skipped from review due to trivial changes (2)
  • packages/bruno-app/src/components/OpenAPISyncTab/ConnectSpecForm/index.js
  • packages/bruno-converters/src/openapi/openapi-common.js
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/bruno-app/src/components/Sidebar/ImportCollectionLocation/index.js

Walkthrough

Detects Swagger/OpenAPI v2 in the OpenAPI entrypoint and routes to a new Swagger 2.0 converter, extracts shared OpenAPI helpers into openapi-common.js, adjusts request grouping/signature usage, removes an early return in request transform flow, adds extensive Swagger 2.0 tests, and updates some UI copy and spec-validation behavior.

Changes

Cohort / File(s) Summary
OpenAPI Entry Point
packages/bruno-converters/src/openapi/openapi-to-bruno.js
Now detects swagger v2 specs and dispatches to swagger2ToBruno; relaxed v3-only enforcement in parseOpenApiCollection; imports helper functions from openapi-common; updated call-site to groupRequestsByPath(..., transformFn, options); removed early return in transformOpenapiRequestItem.
Swagger 2.0 Converter
packages/bruno-converters/src/openapi/swagger2-to-bruno.js
New module implementing Swagger 2.0 → Bruno conversion: $ref resolution, environments from schemes/host/basePath, securityDefinitions→auth mapping, param merging, body/form/multipart/XML handling, response examples, grouping, and shared post-processing. Exports parseSwagger2Collection and swagger2ToBruno.
Shared helpers
packages/bruno-converters/src/openapi/openapi-common.js
New shared utilities: content-type → body-type mapping, ensureUrl, statusText, schema→example builders, XML builder, BODY_TYPE_HANDLERS, populateRequestBody, createBrunoExample, and grouping helpers (groupRequestsByTags, groupRequestsByPath).
Tests — Swagger2 & entry
packages/bruno-converters/tests/openapi/...
Many new Jest suites covering Swagger2 import, auth, body handling, parameters, examples, grouping, circular refs, tags, and overall conversion behavior. Includes integration spec for openApiToBruno routing.
UI & validation
packages/bruno-app/src/components/...
Text/copy updates to reference “OpenAPI/Swagger”; ImportCollectionLocation disables OpenAPI sync for Swagger2; ConnectSpecForm adds client-side rejection for Swagger 2.0 local files.
Small call-site updates
multiple files
Updated function call signatures and imports where helpers moved to openapi-common (notably grouping and example/body population).

Sequence Diagram(s)

sequenceDiagram
    participant User as "User"
    participant Entry as "openApiToBruno"
    participant Swagger as "swagger2ToBruno"
    participant Resolver as "RefResolver"
    participant Auth as "AuthMapper"
    participant Body as "BodyConverter"
    participant Post as "PostProcessor"
    participant Bruno as "Bruno Collection"

    User->>Entry: openApiToBruno(spec, options)
    alt spec.swagger startsWith "2"
        Entry->>Swagger: swagger2ToBruno(spec, options)
        Swagger->>Resolver: resolve $ref
        Resolver-->>Swagger: resolved spec
        Swagger->>Auth: map securityDefinitions -> auth config
        Auth-->>Swagger: collection auth
        loop per path/operation
            Swagger->>Swagger: merge path & operation params
            Swagger->>Body: populate request body / examples
            Body-->>Swagger: formatted body/examples
            Swagger->>Swagger: generate request item
        end
        Swagger->>Post: group & post-process (tags/path)
        Post-->>Bruno: final collection
    else
        Entry->>Post: parseOpenApiCollection(spec, options)
        Post-->>Bruno: final collection
    end
    Bruno-->>User: collection
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • helloanoop
  • bijin-bruno
  • lohit-bruno
  • naman-bruno

Poem

🧭 A swagger found a different road,
🔁 Routed neat to Bruno's code,
🧩 Helpers shared and folders grown,
🔐 Auths and bodies all well-known,
✨ Tests applaud the conversion ode.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding Swagger 2.0 import support to Bruno collections, which is the primary objective of the PR.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gopu-bruno
Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 31, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/bruno-converters/src/openapi/openapi-to-bruno.js`:
- Around line 1624-1625: The current check uses
openApiSpecification.swagger.startsWith('2'), which throws if swagger is a
numeric YAML scalar; update the guard in the openApiSpecification
swagger-version branch (where swagger2ToBruno is called) to handle numbers and
strings by coercing the value to a string (e.g.,
String(openApiSpecification.swagger).startsWith('2')) or by checking typeof and
comparing numerically (e.g., typeof swagger === 'number' ? Math.floor(swagger)
=== 2 : swagger.startsWith('2')), so the code safely detects Swagger 2.x
versions for both numeric and string YAML scalars before calling
swagger2ToBruno.

In `@packages/bruno-converters/src/openapi/swagger2-to-bruno.js`:
- Around line 768-770: The code currently drops the per-operation OAuth2 scope
array (op.security) and always uses all scopes on the scheme; fix by capturing
the requested scopes from op.security (e.g., const requested =
op.security[0][schemeName]) and then restrict the security definition returned
by request.global.security.getDefinition(schemeName) to only those scopes—either
by attaching requestedScopes (securityDef.requestedScopes = requested) or by
replacing securityDef.scopes with a filtered object that only includes keys in
requested (so later code that uses Object.keys(def.scopes) will see only the
operation's scopes). Update the same pattern at the other occurrences mentioned
(the blocks around the other line ranges).
- Around line 762-765: The code sets brunoRequestItem.request.auth.mode to
'inherit' when op.security is an empty array, but per Swagger 2.0 an empty
security array should clear inherited auth; change the branch that checks
Array.isArray(op.security) && op.security.length === 0 so that it explicitly
clears request auth (e.g., set brunoRequestItem.request.auth.mode = 'none' or
remove/empty brunoRequestItem.request.auth) instead of using 'inherit' to ensure
collection/folder credentials are not applied to that operation.
- Around line 244-257: The visited Map in buildEmptyJsonBody is never unwound so
repeated $ref schemas get treated as circular; after adding bodySchema to
visited with visited.set(bodySchema, true) you must remove it when the branch is
finished (e.g., use a try/finally and call visited.delete(bodySchema) after
building _jsonBody) so sibling refs that reuse the same schema are processed
normally; ensure the same visited Map is still passed into
getDefaultValueForSchema calls so backtracking works across recursive calls.
- Around line 523-546: The function currently serializes array defaults with
JSON.stringify(param.default), which breaks CSV/TSV/pipes/multi formats;
instead, when param.default is an array use param.collectionFormat (or default
'csv') to serialize: if collectionFormat === 'multi' create one entry per
default element (push into entries using the same enabled logic you use for
param.items.enum), otherwise join the default array using the same separators
map (csv, pipes, ssv, tsv) and return a single entry with that joined string and
enabled set like the enum-case; use the existing symbols param.default,
param.collectionFormat, param.items.enum, entries and the separators map so
defaults are emitted in the same format as enums.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 56120f09-a901-4e54-9171-39c2aeeba8f7

📥 Commits

Reviewing files that changed from the base of the PR and between 53aa9ed and 08b2e19.

📒 Files selected for processing (11)
  • packages/bruno-converters/src/openapi/openapi-to-bruno.js
  • packages/bruno-converters/src/openapi/swagger2-to-bruno.js
  • packages/bruno-converters/tests/openapi/openapi-to-bruno/swagger2-import.spec.js
  • packages/bruno-converters/tests/openapi/swagger2-to-bruno/swagger2-auth.spec.js
  • packages/bruno-converters/tests/openapi/swagger2-to-bruno/swagger2-body.spec.js
  • packages/bruno-converters/tests/openapi/swagger2-to-bruno/swagger2-circular-references.spec.js
  • packages/bruno-converters/tests/openapi/swagger2-to-bruno/swagger2-examples.spec.js
  • packages/bruno-converters/tests/openapi/swagger2-to-bruno/swagger2-grouping.spec.js
  • packages/bruno-converters/tests/openapi/swagger2-to-bruno/swagger2-parameters.spec.js
  • packages/bruno-converters/tests/openapi/swagger2-to-bruno/swagger2-tags.spec.js
  • packages/bruno-converters/tests/openapi/swagger2-to-bruno/swagger2-to-bruno.spec.js

Comment on lines +244 to +257
const buildEmptyJsonBody = (bodySchema, visited = new Map()) => {
// Check for circular references
if (visited.has(bodySchema)) {
return {};
}

// Add this schema to visited map
visited.set(bodySchema, true);

let _jsonBody = {};
each(bodySchema.properties || {}, (prop, name) => {
_jsonBody[name] = getDefaultValueForSchema(prop, visited);
});
return _jsonBody;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Backtrack visited after each schema branch.

resolveRefs() reuses the same object for repeated $refs. Because this map is never unwound, the second sibling that points at the same definition is treated as circular and collapses to {}. Shared models like shippingAddress and billingAddress will therefore import one populated object and one empty one.

Suggested fix
 const buildEmptyJsonBody = (bodySchema, visited = new Map()) => {
   // Check for circular references
   if (visited.has(bodySchema)) {
     return {};
   }

   // Add this schema to visited map
   visited.set(bodySchema, true);

-  let _jsonBody = {};
+  const _jsonBody = {};
   each(bodySchema.properties || {}, (prop, name) => {
     _jsonBody[name] = getDefaultValueForSchema(prop, visited);
   });
+  visited.delete(bodySchema);
   return _jsonBody;
 };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/bruno-converters/src/openapi/swagger2-to-bruno.js` around lines 244
- 257, The visited Map in buildEmptyJsonBody is never unwound so repeated $ref
schemas get treated as circular; after adding bodySchema to visited with
visited.set(bodySchema, true) you must remove it when the branch is finished
(e.g., use a try/finally and call visited.delete(bodySchema) after building
_jsonBody) so sibling refs that reuse the same schema are processed normally;
ensure the same visited Map is still passed into getDefaultValueForSchema calls
so backtracking works across recursive calls.

@naman-bruno naman-bruno marked this pull request as ready for review April 1, 2026 08:43
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/bruno-converters/src/openapi/openapi-common.js`:
- Around line 269-274: The array example generation uses
buildEmptyJsonBody(bodySchema.items) which only expands object schemas, causing
primitive item types (e.g., { type: 'string' }) to render as {} — update the
array branch in the code that sets body.json to detect primitive item types and
produce a sensible primitive placeholder (e.g., "" for string, 0 for
number/integer, true/false for boolean, null) when bodySchema.items.type is a
primitive, while still delegating to buildEmptyJsonBody(bodySchema.items) for
object/array item types; modify the logic around the body.json assignment that
currently calls buildEmptyJsonBody(bodySchema.items) so it branches on
bodySchema.items.type (primitive vs object/array) and serializes the chosen
placeholder into JSON.stringify as before.
- Around line 477-479: createBrunoExample() always JSON.stringify()s object
examples which causes application/xml responses to be emitted as JSON even
though response.body.type is set to 'xml'; update createBrunoExample (and the
call sites that use getBodyTypeFromContentType) to only JSON.stringify object
examples when the body type is not 'xml' (for 'xml' leave the object as-is or
serialize to XML using the appropriate XML serializer), so response.body.content
matches response.body.type; if XML element names are required, thread the
response schema into createBrunoExample() so schema-derived XML serialization
can be produced instead of blindly stringifying the example object.
- Around line 337-343: The current media-type handler's match only checks for
'text/plain', 'application/octet-stream', and '*/*' so mime types like
'text/csv' or 'text/markdown' aren't recognized; update the match logic in the
handler object (the match function in
packages/bruno-converters/src/openapi/openapi-common.js) to also accept any
mimeType that starts with 'text/' (e.g., mimeType?.startsWith('text/')) in
addition to the existing checks so those text/* media types will set body.mode =
'text' and be processed by the existing handle function.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 076b2b83-a658-4c82-b2ff-b193bb98aa45

📥 Commits

Reviewing files that changed from the base of the PR and between 08b2e19 and 23a5669.

📒 Files selected for processing (9)
  • packages/bruno-app/src/components/Sidebar/BulkImportCollectionLocation/index.js
  • packages/bruno-app/src/components/Sidebar/ImportCollection/FileTab.js
  • packages/bruno-app/src/components/Sidebar/ImportCollectionLocation/index.js
  • packages/bruno-app/src/components/WelcomeModal/GetStartedStep/index.js
  • packages/bruno-converters/src/openapi/openapi-common.js
  • packages/bruno-converters/src/openapi/openapi-to-bruno.js
  • packages/bruno-converters/src/openapi/swagger2-to-bruno.js
  • packages/bruno-converters/tests/openapi/swagger2-to-bruno/swagger2-auth.spec.js
  • packages/bruno-converters/tests/openapi/swagger2-to-bruno/swagger2-to-bruno.spec.js
✅ Files skipped from review due to trivial changes (4)
  • packages/bruno-app/src/components/Sidebar/ImportCollection/FileTab.js
  • packages/bruno-app/src/components/WelcomeModal/GetStartedStep/index.js
  • packages/bruno-app/src/components/Sidebar/BulkImportCollectionLocation/index.js
  • packages/bruno-app/src/components/Sidebar/ImportCollectionLocation/index.js
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/bruno-converters/tests/openapi/swagger2-to-bruno/swagger2-to-bruno.spec.js
  • packages/bruno-converters/src/openapi/swagger2-to-bruno.js

@bijin-bruno bijin-bruno merged commit 8e978ae into usebruno:main Apr 1, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants