Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion packages/bruno-converters/src/openapi/openapi-to-bruno.js
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,12 @@ const BODY_TYPE_HANDLERS = [
}
];

const getContentLevelExample = (bodyContent) => {
if (bodyContent.example !== undefined) return bodyContent.example;
const firstExample = Object.values(bodyContent.examples ?? {})[0];
return firstExample?.value;
};

/**
* Extracts or generates an example value from an OpenAPI schema
* Handles objects, arrays, primitives, and explicit examples
Expand Down Expand Up @@ -733,7 +739,14 @@ const transformOpenapiRequestItem = (request, usedNames = new Set()) => {
const content = get(_operationObject, 'requestBody.content', {});
const mimeType = Object.keys(content)[0];
const bodyContent = content[mimeType] || {};
const bodySchema = bodyContent.schema;
let bodySchema = bodyContent.schema;

if (bodySchema?.example === undefined) {
const contentExample = getContentLevelExample(bodyContent);
if (contentExample !== undefined) {
bodySchema = { ...bodySchema, example: contentExample };
}
}

// Normalize: lowercase (object keys may vary in case)
const normalizedMimeType = typeof mimeType === 'string' ? mimeType.toLowerCase() : '';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -909,3 +909,223 @@ paths:
expect(request.request.body.json).toBe('[]');
});
});

describe('content-level example vs examples priority', () => {
it('should prefer singular example over examples (plural) and fall back to examples when example is absent', () => {
const spec = `
openapi: "3.1.0"
info:
version: "1.0.0"
title: "Test"
servers:
- url: "https://api.example.com"
paths:
/both:
post:
summary: "Both example and examples"
requestBody:
content:
application/json:
schema:
type: object
properties:
name:
type: string
example:
name: "from singular"
examples:
first:
value:
name: "from plural"
responses:
"200":
description: "OK"
/only-examples:
post:
summary: "Only examples plural"
requestBody:
content:
application/json:
schema:
type: object
properties:
name:
type: string
examples:
first:
value:
name: "from plural"
responses:
"200":
description: "OK"
/schema-wins:
post:
summary: "Schema example wins over all"
requestBody:
content:
application/json:
schema:
type: object
example:
name: "from schema"
example:
name: "from content"
examples:
first:
value:
name: "from plural"
responses:
"200":
description: "OK"
`;
const result = openApiToBruno(spec);

// When both example and examples exist, singular example wins
const bothBody = JSON.parse(result.items.find((i) => i.name === 'Both example and examples').request.body.json);
expect(bothBody.name).toBe('from singular');

// When only examples exists, it is used as fallback
const pluralBody = JSON.parse(result.items.find((i) => i.name === 'Only examples plural').request.body.json);
expect(pluralBody.name).toBe('from plural');

// schema.example priority over both content-level example and examples
const schemaBody = JSON.parse(result.items.find((i) => i.name === 'Schema example wins over all').request.body.json);
expect(schemaBody.name).toBe('from schema');
});
});

describe('content-level example values for each body type', () => {
const spec = `
openapi: "3.1.0"
info:
version: "1.0.0"
title: "Test"
servers:
- url: "https://api.example.com"
paths:
/json:
post:
summary: "JSON body"
requestBody:
content:
application/json:
schema:
type: object
properties:
name:
type: string
example:
name: "json example"
responses:
"200":
description: "OK"
/xml:
post:
summary: "XML body"
requestBody:
content:
application/xml:
schema:
type: object
properties:
name:
type: string
example:
name: "xml example"
responses:
"200":
description: "OK"
/text:
post:
summary: "Text body"
requestBody:
content:
text/plain:
schema:
type: string
example: "plain text example"
responses:
"200":
description: "OK"
/form:
post:
summary: "Form body"
requestBody:
content:
application/x-www-form-urlencoded:
schema:
type: object
properties:
username:
type: string
example:
username: "form_user"
responses:
"200":
description: "OK"
/multipart:
post:
summary: "Multipart body"
requestBody:
content:
multipart/form-data:
schema:
type: object
properties:
desc:
type: string
example:
desc: "multipart desc"
responses:
"200":
description: "OK"
/sparql:
post:
summary: "SPARQL body"
requestBody:
content:
application/sparql-query:
schema:
type: string
example: "SELECT * WHERE { ?s ?p ?o }"
responses:
"200":
description: "OK"
`;

it('should import content-level example for JSON body', () => {
const result = openApiToBruno(spec);
const body = JSON.parse(result.items.find((i) => i.name === 'JSON body').request.body.json);
expect(body.name).toBe('json example');
});

it('should import content-level example for XML body', () => {
const result = openApiToBruno(spec);
const xml = result.items.find((i) => i.name === 'XML body').request.body.xml;
expect(xml).toContain('<name>xml example</name>');
});

it('should import content-level example for text/plain body', () => {
const result = openApiToBruno(spec);
const text = result.items.find((i) => i.name === 'Text body').request.body.text;
expect(text).toBe('plain text example');
});

it('should import content-level example for form-urlencoded body', () => {
const result = openApiToBruno(spec);
const field = result.items.find((i) => i.name === 'Form body').request.body.formUrlEncoded.find((f) => f.name === 'username');
expect(field.value).toBe('form_user');
});

it('should import content-level example for multipart body', () => {
const result = openApiToBruno(spec);
const field = result.items.find((i) => i.name === 'Multipart body').request.body.multipartForm.find((f) => f.name === 'desc');
expect(field.value).toBe('multipart desc');
});

it('should import content-level example for SPARQL body', () => {
const result = openApiToBruno(spec);
const sparql = result.items.find((i) => i.name === 'SPARQL body').request.body.sparql;
expect(sparql).toBe('SELECT * WHERE { ?s ?p ?o }');
});
});
Loading