Fix XML in code sample (#3030)

This commit is contained in:
Nolann B.
2025-03-25 15:11:45 +01:00
committed by GitHub
parent 40e8e69c6d
commit ae78fc5394
3 changed files with 119 additions and 10 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@gitbook/react-openapi': patch
---
Fix XML in code sample
@@ -110,6 +110,23 @@ describe('curL code sample generator', () => {
);
});
it('should convert json to xml body properly', () => {
const input: CodeSampleInput = {
method: 'GET',
url: 'https://example.com/path',
headers: {
'Content-Type': 'application/xml',
},
body: '{ "key": "value" }',
};
const output = generator?.generate(input);
expect(output).toBe(
"curl -L \\\n --url 'https://example.com/path' \\\n --header 'Content-Type: application/xml' \\\n --data-binary $'<?xml version=1.0?>\n <key>value</key>\n '"
);
});
it('should format application/graphql body properly', () => {
const input: CodeSampleInput = {
method: 'GET',
@@ -258,6 +275,23 @@ describe('javascript code sample generator', () => {
);
});
it('should convert json to xml body properly', () => {
const input: CodeSampleInput = {
method: 'GET',
url: 'https://example.com/path',
headers: {
'Content-Type': 'application/xml',
},
body: '{ "key": "value" }',
};
const output = generator?.generate(input);
expect(output).toBe(
'const xml = `\n <?xml version=1.0?>\n <key>value</key>\n`;\n\nconst response = await fetch(\'https://example.com/path\', {\n method: \'GET\',\n headers: {\n "Content-Type": "application/xml"\n },\n body: xml\n});\n\nconst data = await response.json();'
);
});
it('should format application/graphql body properly', () => {
const input: CodeSampleInput = {
method: 'GET',
@@ -406,6 +440,23 @@ describe('python code sample generator', () => {
);
});
it('should convert json to xml body properly', () => {
const input: CodeSampleInput = {
method: 'GET',
url: 'https://example.com/path',
headers: {
'Content-Type': 'application/xml',
},
body: '{ "key": "value" }',
};
const output = generator?.generate(input);
expect(output).toBe(
'import requests\n\nresponse = requests.get(\n "https://example.com/path",\n headers={"Content-Type":"application/xml"},\n data="<?xml version=1.0?>\\n<key>value</key>\\n"\n)\n\ndata = response.json()'
);
});
it('should format application/graphql body properly', () => {
const input: CodeSampleInput = {
method: 'GET',
@@ -514,7 +565,7 @@ describe('http code sample generator', () => {
const output = generator?.generate(input);
expect(output).toBe(
'GET /path HTTP/1.1\nHost: example.com\nContent-Type: application/x-www-form-urlencoded\nContent-Length: 15\nAccept: */*\n\n"key=value"'
'GET /path HTTP/1.1\nHost: example.com\nContent-Type: application/x-www-form-urlencoded\nContent-Length: 15\nAccept: */*\n\n"key=\'value\'"'
);
});
@@ -554,6 +605,23 @@ describe('http code sample generator', () => {
);
});
it('should convert json to xml body properly', () => {
const input: CodeSampleInput = {
method: 'GET',
url: 'https://example.com/path',
headers: {
'Content-Type': 'application/xml',
},
body: '{ "key": "value" }',
};
const output = generator?.generate(input);
expect(output).toBe(
'GET /path HTTP/1.1\nHost: example.com\nContent-Type: application/xml\nContent-Length: 24\nAccept: */*\n\n"<?xml version=1.0?>\n<key>value</key>\n"'
);
});
it('should format application/graphql body properly', () => {
const input: CodeSampleInput = {
method: 'GET',
+45 -9
View File
@@ -8,6 +8,7 @@ import {
isText,
isXML,
} from './contentTypeChecks';
import { json2xml } from './json2xml';
import { stringifyOpenAPI } from './stringifyOpenAPI';
export interface CodeSampleInput {
@@ -238,7 +239,10 @@ const BodyGenerators = {
: String(body);
} else if (isText(contentType)) {
body = `--data '${String(body).replace(/"/g, '')}'`;
} else if (isXML(contentType) || isCSV(contentType)) {
} else if (isXML(contentType)) {
// Convert to XML and ensure proper formatting
body = `--data-binary $'${convertBodyToXML(body)}'`;
} else if (isCSV(contentType)) {
// We use --data-binary to avoid cURL converting newlines to \r\n
body = `--data-binary $'${stringifyOpenAPI(body).replace(/"/g, '').replace(/\\n/g, '\n')}'`;
} else if (isGraphQL(contentType)) {
@@ -312,7 +316,9 @@ const BodyGenerators = {
body = 'formData';
} else if (isXML(contentType)) {
code += 'const xml = `\n';
code += indent(String(body), 4);
// Convert JSON to XML if needed
code += indent(convertBodyToXML(body), 4);
code += '`;\n\n';
body = 'xml';
} else if (isText(contentType)) {
@@ -346,6 +352,11 @@ const BodyGenerators = {
body = 'files';
}
if (isXML(contentType)) {
// Convert JSON to XML if needed
body = convertBodyToXML(body);
}
return { body, code, headers };
},
getHTTPBody: (body: any, headers?: Record<string, string>) => {
@@ -358,23 +369,48 @@ const BodyGenerators = {
formUrlEncoded: () => {
const encoded = isPlainObject(body)
? Object.entries(body)
.map(([key, value]) => `${key}=${String(value)}`)
.map(([key, value]) => `${key}=${stringifyOpenAPI(value)}`)
.join('&')
: String(body);
return `"${encoded}"`;
: stringifyOpenAPI(body);
return `"${encoded.replace(/"/g, "'")}"`;
},
text: () => `"${String(body)}"`,
xmlOrCsv: () => `"${stringifyOpenAPI(body).replace(/"/g, '')}"`,
xml: () => {
// Convert JSON to XML if needed
return `"${convertBodyToXML(body)}"`;
},
csv: () => `"${stringifyOpenAPI(body).replace(/"/g, '')}"`,
default: () => `${stringifyOpenAPI(body, null, 2)}`,
};
if (isPDF(contentType)) return typeHandlers.pdf();
if (isFormUrlEncoded(contentType)) return typeHandlers.formUrlEncoded();
if (isText(contentType)) return typeHandlers.text();
if (isXML(contentType) || isCSV(contentType)) {
return typeHandlers.xmlOrCsv();
}
if (isXML(contentType)) return typeHandlers.xml();
if (isCSV(contentType)) return typeHandlers.csv();
return typeHandlers.default();
},
};
/**
* Converts a body to XML format
*/
function convertBodyToXML(body: any): string {
// If body is already a string and looks like XML, return it as is
if (typeof body === 'string' && body.trim().startsWith('<')) {
return body;
}
// If body is not an object, try to parse it as JSON
if (typeof body !== 'object' || body === null) {
try {
body = JSON.parse(body);
} catch {
// If parsing fails, return the original body
return body;
}
}
return json2xml(body).replace(/"/g, '').replace(/\\n/g, '\n').replace(/\\t/g, '\t');
}