mirror of
https://github.com/usebruno/bruno.git
synced 2026-06-23 12:45:38 +00:00
fix: openapi content level example (#7091)
* fix: openapi content level example * add: unit tests
This commit is contained in:
@@ -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() : '';
|
||||
|
||||
@@ -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 }');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user