fix: openapi content level example (#7091)

* fix: openapi content level example

* add: unit tests
This commit is contained in:
Pooja
2026-02-10 15:56:42 +05:30
committed by GitHub
parent 1d1c3d83ec
commit 9127be8498
2 changed files with 234 additions and 1 deletions

View File

@@ -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
@@ -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() : '';

View File

@@ -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 }');
});
});